Skip to content

Commit 4e90387

Browse files
committed
Visualization of zones and areas
1 parent 9a25e2d commit 4e90387

File tree

3 files changed

+358
-8
lines changed

3 files changed

+358
-8
lines changed

viz/app.js

+295-7
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import { LinearInterpolator, FlyToInterpolator } from 'deck.gl';
4040
import { HeatmapLayer } from 'deck.gl';
4141
import { InvertColorsOff, ShopTwoOutlined } from '@mui/icons-material';
4242

43-
import { getCountyNodes, ExtractFirstTimeSlice, ExtractFlowData, getBarNet, getPoints, getGeneration, getLoad, getContours } from "./src/dataprocess";
43+
import { getCountyNodes, ExtractFirstTimeSlice, ExtractFlowData, getBarNet, getPoints, getGeneration, getLoad, getContours, getAreas, getZones } from "./src/dataprocess";
4444
import { LineColor, FlowColor, FillColor, fillGenColumnColor, fillGenColumnColorCap, getVoltageFillColor } from "./src/color"
4545

4646
import 'core-js/actual/structured-clone';
@@ -72,6 +72,9 @@ var data = ExtractFirstTimeSlice(geodata);
7272
const countyloaddata = getCountyNodes(data);
7373
data = countyloaddata.updatedata;
7474

75+
const areas = getAreas(casedata);
76+
77+
const zones = getZones(casedata);
7578

7679
const flowdata = ExtractFlowData(data);
7780

@@ -146,9 +149,15 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
146149
const [busNameSelectItems, setBusNameSelectItems] = useState([]);
147150

148151
const [busNameItems, setbusNameItems] = useState(data.features
149-
.filter(f => f.geometry.type == "Point").map((f) => (f.properties.NAME)));
152+
.filter(f => f.geometry.type == "Point").map((f) => (f.properties.NAME)));
153+
154+
const [areaNameSelectItems, setAreaNameSelectItems] = useState([]);
150155

156+
const [areaNameItems, setAreaNameItems] = useState(areas.features.map(f => f.properties.name));
151157

158+
const [zoneNameSelectItems, setZoneNameSelectItems] = useState([]);
159+
160+
const [zoneNameItems, setZoneNameItems] = useState(zones.features.map(f => f.properties.name));
152161

153162
const [countyNameSelectItems, setCountyNameSelectItems] = useState([]);
154163

@@ -430,6 +439,54 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
430439

431440
});
432441

442+
const zoomToAreaName = useCallback((filterareas,minLng, minLat, maxLng, maxLat) => {
443+
var viewport = new WebMercatorViewport(INITIAL_VIEW_STATE);
444+
445+
const { longitude, latitude, zoom } = viewport.fitBounds([[minLng, minLat], [maxLng, maxLat]]);
446+
447+
setInitialViewState(viewState => ({
448+
...viewState,
449+
latitude: latitude,
450+
longitude: longitude,
451+
pitch: 50,
452+
traansitionInterpolator: transitionFlyToInterpolator,
453+
transitionDuration: 5000,
454+
zoom: 7.5,
455+
onTransitionEnd: activatePopup
456+
}))
457+
458+
var popup = { display: false, name: '', info: '' }; // Will be displayed after transition end only
459+
popup.name = "Area " + filterareas.properties.name;
460+
// popup.info = "Area: " + info.object.properties.name;
461+
setShowPopup(showPopup => ({ ...showPopup, ...popup }));
462+
463+
});
464+
465+
const zoomToZoneName = useCallback((filterzones,minLng, minLat, maxLng, maxLat) => {
466+
var viewport = new WebMercatorViewport(INITIAL_VIEW_STATE);
467+
468+
const { longitude, latitude, zoom } = viewport.fitBounds([[minLng, minLat], [maxLng, maxLat]]);
469+
470+
setInitialViewState(viewState => ({
471+
...viewState,
472+
latitude: latitude,
473+
longitude: longitude,
474+
pitch: 50,
475+
traansitionInterpolator: transitionFlyToInterpolator,
476+
transitionDuration: 5000,
477+
zoom: 7.5,
478+
onTransitionEnd: activatePopup
479+
}))
480+
481+
var popup = { display: false, name: '', info: '' }; // Will be displayed after transition end only
482+
popup.name = "Zone " + filterzones.properties.name;
483+
// popup.info = "Zone: " + info.object.properties.name;
484+
setShowPopup(showPopup => ({ ...showPopup, ...popup }));
485+
486+
});
487+
488+
489+
433490
const zoomToCounty = useCallback((info) => {
434491
if (!info) return null;
435492

@@ -456,7 +513,73 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
456513

457514
var popup = { display: false, name: '', info: '' }; // Will be displayed after transition end only
458515
popup.name = info.object.properties.NAME;
459-
popup.info = "Load: " + info.object.properties.Pd.toFixed(2) + "MW";
516+
popup.info = "Load loss: " + info.object.properties.Pd.toFixed(2) + "MW";
517+
setShowPopup(showPopup => ({ ...showPopup, ...popup }));
518+
519+
520+
}
521+
});
522+
523+
const zoomToArea = useCallback((info) => {
524+
if (!info) return null;
525+
526+
if (info.layer.id == 'AreaLayer') {
527+
var layer = info.layer;
528+
var { viewport } = layer.context;
529+
530+
var cbounds = bbox(info.object);
531+
var c1 = [cbounds[0], cbounds[1]];
532+
var c2 = [cbounds[2], cbounds[3]];
533+
var areabounds = [c1, c2];
534+
const { longitude, latitude, zoom } = viewport.fitBounds(areabounds);
535+
536+
setInitialViewState(viewState => ({
537+
...viewState,
538+
latitude: latitude,
539+
longitude: longitude,
540+
pitch: 50,
541+
traansitionInterpolator: transitionFlyToInterpolator,
542+
transitionDuration: 5000,
543+
zoom: zoom - 0.25,
544+
onTransitionEnd: activatePopup
545+
}))
546+
547+
var popup = { display: false, name: '', info: '' }; // Will be displayed after transition end only
548+
popup.name = "Area " + info.object.properties.name;
549+
// popup.info = "Area: " + info.object.properties.name;
550+
setShowPopup(showPopup => ({ ...showPopup, ...popup }));
551+
552+
553+
}
554+
});
555+
556+
const zoomToZone = useCallback((info) => {
557+
if (!info) return null;
558+
559+
if (info.layer.id == 'ZoneLayer') {
560+
var layer = info.layer;
561+
var { viewport } = layer.context;
562+
563+
var cbounds = bbox(info.object);
564+
var c1 = [cbounds[0], cbounds[1]];
565+
var c2 = [cbounds[2], cbounds[3]];
566+
var zonebounds = [c1, c2];
567+
const { longitude, latitude, zoom } = viewport.fitBounds(zonebounds);
568+
569+
setInitialViewState(viewState => ({
570+
...viewState,
571+
latitude: latitude,
572+
longitude: longitude,
573+
pitch: 50,
574+
traansitionInterpolator: transitionFlyToInterpolator,
575+
transitionDuration: 5000,
576+
zoom: zoom - 0.25,
577+
onTransitionEnd: activatePopup
578+
}))
579+
580+
var popup = { display: false, name: '', info: '' }; // Will be displayed after transition end only
581+
popup.name = "Zone " + info.object.properties.name;
582+
// popup.info = "Zone: " + info.object.properties.name;
460583
setShowPopup(showPopup => ({ ...showPopup, ...popup }));
461584

462585

@@ -487,10 +610,9 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
487610
const [genlayeractive, setGenLayerActive] = useState(false);
488611
const [genlayercapactive, setGenLayerCapActive] = useState(false);
489612
const [voltagelayeractive, setVoltageLayerActive] = useState(false);
490-
491-
492-
493-
613+
const [zonelayeractive, setZoneLayerActive] = useState(false);
614+
const [arealayeractive, setAreaLayerActive] = useState(false);
615+
494616
const handleUserInput = (inputText) => {
495617
console.log(`New message incoming! ${inputText}`);
496618
// Now send the message to GPT and get response
@@ -612,6 +734,31 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
612734
})))
613735
};
614736

737+
const handleAreaLayerChange = (event) => {
738+
setAreaLayerActive(event.target.checked);
739+
// setVoltageFilterValue([0.89, 1.11]);
740+
741+
event.target.checked && (setInitialViewState(viewState => ({
742+
...viewState,
743+
pitch: 40,
744+
traansitionInterpolator: transitionFlyToInterpolator,
745+
transitionDuration: 2000,
746+
})))
747+
};
748+
749+
const handleZoneLayerChange = (event) => {
750+
setZoneLayerActive(event.target.checked);
751+
// setVoltageFilterValue([0.89, 1.11]);
752+
753+
event.target.checked && (setInitialViewState(viewState => ({
754+
...viewState,
755+
pitch: 40,
756+
traansitionInterpolator: transitionFlyToInterpolator,
757+
transitionDuration: 2000,
758+
})))
759+
};
760+
761+
615762
const handleGenLayerChange = (event) => {
616763
setGenLayerActive(event.target.checked);
617764
setGenFilterValue([gendata.minPg, gendata.maxPg]);
@@ -910,6 +1057,59 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
9101057
}),
9111058
*/
9121059

1060+
1061+
new GeoJsonLayer({
1062+
id: 'AreaLayer',
1063+
data: areas,
1064+
pickable: arealayeractive,
1065+
visible: arealayeractive,
1066+
stroked: true,
1067+
filled: true,
1068+
extruded: true,
1069+
wireframe: true,
1070+
lineWidthMinPixels: 1,
1071+
getPolygon: d => d.geometry.coordinates,
1072+
// getElevation: d => d.properties.Pd*5.0,
1073+
getFillColor: [255, 192, 203],
1074+
getLineColor: [80, 80, 80],
1075+
getLineWidth: d => 1,
1076+
opacity: 0.1,
1077+
onClick: zoomToArea,
1078+
// extensions: [new DataFilterExtension({ filtersize: 1 })],
1079+
// getFilterValue: getLoadFilterValue,
1080+
// filterRange: loadfiltervalue,
1081+
1082+
// updateTriggers: {
1083+
// getFilterValue: [netfiltervalue, countyNameSelectItems]
1084+
// }
1085+
}),
1086+
1087+
new GeoJsonLayer({
1088+
id: 'ZoneLayer',
1089+
data: zones,
1090+
pickable: zonelayeractive,
1091+
visible: zonelayeractive,
1092+
stroked: true,
1093+
filled: true,
1094+
extruded: true,
1095+
wireframe: true,
1096+
lineWidthMinPixels: 1,
1097+
getPolygon: d => d.geometry.coordinates,
1098+
// getElevation: d => d.properties.Pd*5.0,
1099+
getFillColor: [252, 245, 95],
1100+
getLineColor: [80, 80, 80],
1101+
getLineWidth: d => 1,
1102+
opacity: 0.1,
1103+
onClick: zoomToZone,
1104+
// extensions: [new DataFilterExtension({ filtersize: 1 })],
1105+
// getFilterValue: getLoadFilterValue,
1106+
// filterRange: loadfiltervalue,
1107+
1108+
// updateTriggers: {
1109+
// getFilterValue: [netfiltervalue, countyNameSelectItems]
1110+
// }
1111+
}),
1112+
9131113
new GeoJsonLayer({
9141114
id: 'PolygonLayerload',
9151115
data: countyload,
@@ -1104,6 +1304,56 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
11041304
}
11051305
}
11061306

1307+
const handleAreaMultiselect = (selectItem, metadata) => {
1308+
1309+
const selected = areaNameSelectItems.indexOf(metadata.dataItem)
1310+
console.log(selected);
1311+
if (selected >= 0) { //if is selected, remove
1312+
const newArray = [...areaNameSelectItems.slice(0, selected), ...areaNameSelectItems.slice(selected + 1)];
1313+
setAreaNameSelectItems(newArray)
1314+
1315+
} else { //add to array
1316+
setAreaNameSelectItems(areaNameSelectItems => ([...areaNameSelectItems, metadata.dataItem]))
1317+
const filterareas = areas.features.filter(area => area.properties.name === metadata.dataItem)
1318+
if (filterareas.length > 0) {
1319+
const longs = filterareas[0].geometry.coordinates[0].map(d => d[0])
1320+
const lats = filterareas[0].geometry.coordinates[0].map(d => d[1])
1321+
const minLng = Math.min(...longs)
1322+
const maxLng = Math.max(...longs)
1323+
const minLat = Math.min(...lats)
1324+
const maxLat = Math.max(...lats)
1325+
1326+
zoomToAreaName(filterareas[0],minLng, minLat, maxLng, maxLat)
1327+
}
1328+
}
1329+
}
1330+
1331+
const handleZoneMultiselect = (selectItem, metadata) => {
1332+
1333+
const selected = zoneNameSelectItems.indexOf(metadata.dataItem)
1334+
console.log(selected);
1335+
if (selected >= 0) { //if is selected, remove
1336+
const newArray = [...zoneNameSelectItems.slice(0, selected), ...zoneNameSelectItems.slice(selected + 1)];
1337+
setZoneNameSelectItems(newArray)
1338+
1339+
} else { //add to array
1340+
setZoneNameSelectItems(zoneNameSelectItems => ([...zoneNameSelectItems, metadata.dataItem]))
1341+
const filterzones = zones.features.filter(area => area.properties.name === metadata.dataItem)
1342+
if (filterzones.length > 0) {
1343+
const longs = filterzones[0].geometry.coordinates[0].map(d => d[0])
1344+
const lats = filterzones[0].geometry.coordinates[0].map(d => d[1])
1345+
const minLng = Math.min(...longs)
1346+
const maxLng = Math.max(...longs)
1347+
const minLat = Math.min(...lats)
1348+
const maxLat = Math.max(...lats)
1349+
1350+
zoomToZoneName(filterzones[0],minLng, minLat, maxLng, maxLat)
1351+
}
1352+
}
1353+
}
1354+
1355+
1356+
11071357
const renderItem = ({
11081358
id,
11091359
name
@@ -1477,6 +1727,44 @@ export default function App({ refdata = data, refflowdata = flowdata, ggdata = g
14771727
</AccordionDetails>
14781728
</Accordion>
14791729

1730+
<Accordion defaultExpanded={false}>
1731+
<AccordionSummary style={{ height: "20px", minHeight: "30px", paddingRight: "40px", paddingLeft: "0px" }}
1732+
expandIcon={<ArrowDropDownIcon />}>
1733+
<Typography>
1734+
<Checkbox checked={arealayeractive} style={{ color: "primary" }} onChange={handleAreaLayerChange} />Show Areas
1735+
</Typography>
1736+
</AccordionSummary>
1737+
<AccordionDetails>
1738+
<Typography component="div">
1739+
{arealayeractive && (<div style={{ paddingRight: "40px" }}><Multiselect
1740+
defaultValue={areaNameSelectItems}
1741+
data={areaNameItems}
1742+
placeholder={'Search for areas'}
1743+
onChange={handleAreaMultiselect}
1744+
/></div>)}
1745+
</Typography>
1746+
</AccordionDetails>
1747+
</Accordion>
1748+
1749+
<Accordion defaultExpanded={false}>
1750+
<AccordionSummary style={{ height: "20px", minHeight: "30px", paddingRight: "40px", paddingLeft: "0px" }}
1751+
expandIcon={<ArrowDropDownIcon />}>
1752+
<Typography>
1753+
<Checkbox checked={zonelayeractive} style={{ color: "primary" }} onChange={handleZoneLayerChange} />Show Zones
1754+
</Typography>
1755+
</AccordionSummary>
1756+
<AccordionDetails>
1757+
<Typography component="div">
1758+
{zonelayeractive && (<div style={{ paddingRight: "40px" }}><Multiselect
1759+
defaultValue={zoneNameSelectItems}
1760+
data={zoneNameItems}
1761+
placeholder={'Search for zones'}
1762+
onChange={handleZoneMultiselect}
1763+
/></div>)}
1764+
</Typography>
1765+
</AccordionDetails>
1766+
</Accordion>
1767+
14801768
</div>
14811769

14821770
{/* <br></br> */}

viz/geninputfile.py

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
f.write('\n')
1313
f.write('\t\t\t\tvar casedata0 = {};\n')
1414
f.write('\t\t\t\tcasedata0.geojsondata = {};\n')
15+
f.write('\t\t\t\tcasedata0.nareas = inputcasedata.nareas;\n')
16+
f.write('\t\t\t\tcasedata0.nzones = inputcasedata.nzones;\n')
17+
f.write('\t\t\t\tcasedata0.areas = inputcasedata.areas;\n')
18+
f.write('\t\t\t\tcasedata0.zones = inputcasedata.zones;\n')
1519
f.write('\t\t\t\tcasedata0.geojsondata.type = "FeatureCollection";\n')
1620
f.write(
1721
'\t\t\t\tcasedata0.geojsondata.features = [...inputcasedata.geojsondata.features];\n')

0 commit comments

Comments
 (0)