diff --git a/apps/nowcasting-app/components/helpers/data.ts b/apps/nowcasting-app/components/helpers/data.ts index a1aef69e..a21eb986 100644 --- a/apps/nowcasting-app/components/helpers/data.ts +++ b/apps/nowcasting-app/components/helpers/data.ts @@ -1,8 +1,10 @@ import { components } from "../../types/quartz-api"; -import { CombinedData, GspDeltaValue, MapFeatureObject } from "../types"; +import { CombinedData, GspDeltaValue, GspZoneGroupings, MapFeatureObject } from "../types"; import { Feature, FeatureCollection, GeoJsonProperties, Geometry, Position } from "geojson"; import gspShapeData from "../../data/gsp_regions_20220314.json"; +import dnoShapeData from "../../data/dno_regions_lat_long_converted.json"; import ngGSPZoneGroupings from "../../data/ng_gsp_zone_groupings.json"; +import dnoGspGroupings from "../../data/dno_gsp_groupings.json"; import ngZones from "../../data/ng_zones.json"; import { formatISODateString, getOpacityValueFromPVNormalized, getRoundedPv } from "./utils"; import { get30MinNow } from "./globalState"; @@ -133,29 +135,32 @@ const mapGspFeatures: ( // TODO BRAD: map/aggregate all the GSP data to the zone level const mapZoneFeatures: ( features: Feature[], + gspZoneGroupings: GspZoneGroupings, combinedData?: CombinedData, gspForecastsDataByTimestamp?: components["schemas"]["OneDatetimeManyForecastValues"][], targetTime?: string, - gspDeltas?: Map + gspDeltas?: Map, + idKey?: string ) => Feature[] = ( features, + gspZoneGroupings, combinedData, gspForecastsDataByTimestamp = [], targetTime, - gspDeltas + gspDeltas, + idKey = "id" ) => { if (!targetTime) return []; // Loop through ng_zones data and aggregate the forecast and actuals const newFeatures: Feature[] = features.map((feature) => { - if (!feature.properties?.id) return feature; - if (!ngGSPZoneGroupings[feature.properties.id as keyof typeof ngGSPZoneGroupings]) - return feature; + const zoneId = feature.properties?.[idKey as keyof typeof gspZoneGroupings]; + if (!zoneId) return feature; + const zoneGspIds: number[] = gspZoneGroupings[zoneId as keyof typeof gspZoneGroupings]; + if (!zoneGspIds) return feature; let zoneForecastTotal = 0; let zoneActualTotal = 0; let zoneInstalledCapacity = 0; - const gspIds: number[] = - ngGSPZoneGroupings[feature.properties.id as keyof typeof ngGSPZoneGroupings]; - gspIds.forEach((gsp: number) => { + zoneGspIds.forEach((gsp: number) => { zoneForecastTotal += gspForecastsDataByTimestamp.find( (fc) => fc.datetimeUtc.slice(0, 16) === formatISODateString(targetTime) @@ -171,11 +176,11 @@ const mapZoneFeatures: ( }); return { ...feature, - id: feature.properties.id, + id: zoneId, type: "Feature" as "Feature", properties: setFeatureObjectProps( feature.properties, - { regionName: feature.properties.id, installedCapacityMw: zoneInstalledCapacity }, + { regionName: zoneId, installedCapacityMw: zoneInstalledCapacity }, zoneForecastTotal, zoneActualTotal ) @@ -232,10 +237,22 @@ export const generateGeoJsonForecastData: ( console.log("aggregating to zone"); features = mapZoneFeatures( ngZones.features as Feature[], + ngGSPZoneGroupings, combinedData, gspForecastsDataByTimestamp, targetTime ); + } else if (aggregation === NationalAggregation.DNO) { + console.log("aggregating to DNO"); + features = mapZoneFeatures( + dnoShapeData.features as Feature[], + dnoGspGroupings, + combinedData, + gspForecastsDataByTimestamp, + targetTime, + undefined, + "LongName" + ); } const forecastGeoJson = { type: "FeatureCollection" as "FeatureCollection", diff --git a/apps/nowcasting-app/components/map/measuringUnit.tsx b/apps/nowcasting-app/components/map/measuringUnit.tsx index 70967283..8e6c5471 100644 --- a/apps/nowcasting-app/components/map/measuringUnit.tsx +++ b/apps/nowcasting-app/components/map/measuringUnit.tsx @@ -102,6 +102,14 @@ const MeasuringUnit = ({ text={"NG Zones"} value={NationalAggregation.zone} /> + + id={"GroupButtonZones"} + active={nationalAggregation === NationalAggregation.DNO} + isLoading={isLoading} + onToggle={onToggleAggregation} + text={"DNO"} + value={NationalAggregation.DNO} + /> diff --git a/apps/nowcasting-app/components/map/types.ts b/apps/nowcasting-app/components/map/types.ts index 757d072d..e2e65f5f 100644 --- a/apps/nowcasting-app/components/map/types.ts +++ b/apps/nowcasting-app/components/map/types.ts @@ -8,7 +8,8 @@ export enum ActiveUnit { export enum NationalAggregation { GSP = "GSP", - zone = "Zone" + zone = "Zone", + DNO = "DNO" } export enum SelectedData { diff --git a/apps/nowcasting-app/components/types.d.ts b/apps/nowcasting-app/components/types.d.ts index bd91a7b1..8202a498 100644 --- a/apps/nowcasting-app/components/types.d.ts +++ b/apps/nowcasting-app/components/types.d.ts @@ -311,3 +311,7 @@ export type MapFeatureObject = { id?: string | number | undefined; bbox?: BBox | undefined; }; + +export type GspZoneGroupings = { + [key]: number[]; +}; diff --git a/apps/nowcasting-app/data/dno_gsp_groupings.json b/apps/nowcasting-app/data/dno_gsp_groupings.json new file mode 100644 index 00000000..955727c6 --- /dev/null +++ b/apps/nowcasting-app/data/dno_gsp_groupings.json @@ -0,0 +1,341 @@ +{ + "WPD (South West)": [ + 1, + 8, + 13, + 45, + 113, + 152, + 181, + 257, + 283 + ], + "SSE": [ + 2, + 6, + 10, + 11, + 18, + 21, + 29, + 33, + 39, + 42, + 43, + 46, + 59, + 62, + 68, + 73, + 77, + 87, + 92, + 93, + 94, + 98, + 99, + 108, + 114, + 115, + 120, + 121, + 125, + 127, + 138, + 154, + 168, + 173, + 179, + 192, + 193, + 195, + 200, + 203, + 204, + 224, + 225, + 232, + 239, + 241, + 248, + 259, + 260, + 262, + 268, + 282, + 284, + 293, + 311, + 313 + ], + "WPD (South Wales)": [ + 3, + 7, + 55, + 151, + 196, + 227, + 238, + 242, + 281, + 295 + ], + "SSE (Southern)": [ + 4, + 32, + 41, + 64, + 75, + 100, + 116, + 158, + 180, + 190, + 191, + 197, + 199, + 202, + 211, + 216 + ], + "UKPN (London)": [ + 5, + 17, + 19, + 67, + 140, + 150, + 157, + 187, + 188, + 189, + 209, + 246, + 266, + 310 + ], + "UKPN (East)": [ + 9, + 34, + 38, + 40, + 47, + 101, + 110, + 201, + 214, + 226, + 245, + 251, + 280, + 290, + 291, + 297, + 299, + 300, + 314, + 317 + ], + "SPEN (SP Distribution)": [ + 14, + 15, + 16, + 22, + 31, + 35, + 44, + 51, + 58, + 61, + 63, + 69, + 70, + 71, + 76, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 90, + 91, + 95, + 96, + 97, + 102, + 104, + 105, + 106, + 107, + 112, + 123, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 137, + 141, + 145, + 147, + 149, + 153, + 159, + 161, + 167, + 169, + 170, + 171, + 172, + 183, + 184, + 185, + 198, + 205, + 208, + 222, + 223, + 234, + 237, + 244, + 247, + 252, + 255, + 263, + 265, + 270, + 277, + 278, + 279, + 285, + 303, + 304, + 306 + ], + "UKPN (South)": [ + 20, + 30, + 53, + 65, + 164, + 174, + 210, + 212, + 258, + 315 + ], + "WPD (East Midlands)": [ + 23, + 24, + 66, + 74, + 88, + 103, + 111, + 135, + 243, + 256, + 274, + 298, + 302, + 309 + ], + "SPEN (SP MANWEB)": [ + 25, + 54, + 72, + 122, + 126, + 165, + 182, + 186, + 230, + 240, + 292, + 316 + ], + "WPD (Midlands)": [ + 26, + 48, + 49, + 60, + 117, + 142, + 155, + 156, + 176, + 206, + 217, + 219, + 229, + 250, + 264, + 296, + 308 + ], + "NPG (Northern Electric)": [ + 27, + 124, + 144, + 146, + 177, + 178, + 215, + 218, + 220, + 228, + 235, + 253, + 271, + 272, + 275, + 276, + 294, + 301 + ], + "ENWL": [ + 28, + 37, + 56, + 143, + 148, + 163, + 166, + 194, + 221, + 231, + 249, + 269, + 273, + 305 + ], + "NPG (Yorkshire Electric)": [ + 36, + 52, + 78, + 89, + 109, + 118, + 119, + 136, + 160, + 162, + 175, + 207, + 213, + 233, + 254, + 261, + 267, + 286, + 287, + 289, + 307, + 312 + ] +}