Plotting GDM Models#
There are two options for plotting GDM models:
Using the
plotFunction
This returns an interactive Plotly plot with detailed information displayed on hover.Plotting from a GeoDataFrame
Export the model to a GeoDataFrame and use standard geospatial plotting libraries (e.g., GeoPandas or Matplotlib) for visualization.
We start by loading a sample distribution system.
from gdm.distribution import DistributionSystem
from gdmloader.constants import GCS_CASE_SOURCE
from gdmloader.source import SystemLoader
from IPython.display import display, HTML
import plotly.io as pio
pio.renderers.default = "notebook_connected"
gdm_loader = SystemLoader()
gdm_loader.add_source(GCS_CASE_SOURCE)
distribution_system: DistributionSystem = gdm_loader.load_dataset(
source_name=GCS_CASE_SOURCE.name,
system_type=DistributionSystem,
dataset_name="p1rhs7_1247",
)
distribution_system.name = "p1rhs7_1247"
distribution_system.info()
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/gdmloader/source.py:124, in SystemLoader.load_dataset(self, system_type, source_name, dataset_name, version)
123 try:
--> 124 source.fs.get(
125 remote_folder,
126 str(local_folder),
127 recursive=True,
128 )
129 except FileNotFoundError:
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:118, in sync_wrapper.<locals>.wrapper(*args, **kwargs)
117 self = obj or args[0]
--> 118 return sync(self.loop, func, *args, **kwargs)
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:103, in sync(loop, func, timeout, *args, **kwargs)
102 elif isinstance(return_result, BaseException):
--> 103 raise return_result
104 else:
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:56, in _runner(event, coro, result, timeout)
55 try:
---> 56 result[0] = await coro
57 except Exception as ex:
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:645, in AsyncFileSystem._get(self, rpath, lpath, recursive, callback, maxdepth, **kwargs)
644 rpath = self._strip_protocol(rpath)
--> 645 rpaths = await self._expand_path(
646 rpath, recursive=recursive, maxdepth=maxdepth
647 )
648 if source_is_str and (not recursive or maxdepth is not None):
649 # Non-recursive glob does not copy directories
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:883, in AsyncFileSystem._expand_path(self, path, recursive, maxdepth)
882 if isinstance(path, str):
--> 883 out = await self._expand_path([path], recursive, maxdepth)
884 else:
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/fsspec/asyn.py:912, in AsyncFileSystem._expand_path(self, path, recursive, maxdepth)
911 if not out:
--> 912 raise FileNotFoundError(path)
913 return sorted(out)
FileNotFoundError: ['gdm_data/data/DistributionSystem/2_2_0/p1rhs7_1247']
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
Cell In[1], line 12
9 gdm_loader = SystemLoader()
10 gdm_loader.add_source(GCS_CASE_SOURCE)
---> 12 distribution_system: DistributionSystem = gdm_loader.load_dataset(
13 source_name=GCS_CASE_SOURCE.name,
14 system_type=DistributionSystem,
15 dataset_name="p1rhs7_1247",
16 )
17 distribution_system.name = "p1rhs7_1247"
18 distribution_system.info()
File /opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/site-packages/gdmloader/source.py:131, in SystemLoader.load_dataset(self, system_type, source_name, dataset_name, version)
129 except FileNotFoundError:
130 msg = f"{remote_folder=} not found! Check the URL: {source.url}/{remote_folder}"
--> 131 raise ValueError(msg)
133 system_file = list(dataset_folder.rglob("*.json"))[0]
134 return system_type.from_json(system_file)
ValueError: remote_folder='gdm_data/data/DistributionSystem/2_2_0/p1rhs7_1247' not found! Check the URL: https://storage.googleapis.com/gdm_data/gdm_data/data/DistributionSystem/2_2_0/p1rhs7_1247
Plotting using Plotly#
fig = distribution_system.plot(
flip_coordinates=True,
show=False,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[2], line 5
1 fig = distribution_system.plot(
2 flip_coordinates=True,
3 show=False,
4 )
----> 5 display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))
File /opt/homebrew/Caskroom/miniconda/base/envs/gdm2/lib/python3.12/site-packages/plotly/io/_html.py:130, in to_html(fig, config, auto_play, include_plotlyjs, include_mathjax, post_script, full_html, animation_opts, default_width, default_height, validate, div_id)
127 from plotly.io.json import to_json_plotly
129 # ## Validate figure ##
--> 130 fig_dict = validate_coerce_fig_to_dict(fig, validate)
132 # ## Generate div id ##
133 plotdivid = div_id or str(uuid.uuid4())
File /opt/homebrew/Caskroom/miniconda/base/envs/gdm2/lib/python3.12/site-packages/plotly/io/_utils.py:20, in validate_coerce_fig_to_dict(fig, validate)
18 fig_dict = fig.to_plotly_json()
19 else:
---> 20 raise ValueError(
21 """
22 The fig parameter must be a dict or Figure.
23 Received value of type {typ}: {v}""".format(
24 typ=type(fig), v=fig
25 )
26 )
27 return fig_dict
ValueError:
The fig parameter must be a dict or Figure.
Received value of type <class 'NoneType'>: None
from gdm.distribution.enums import MapType, PlotingStyle
fig = distribution_system.plot(
map_type=MapType.SCATTER_MAP,
style=PlotingStyle.OPEN_STREET_MAP,
flip_coordinates=True,
show=False,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))
distribution_system.plot(
map_type=MapType.SCATTER_MAP,
style=PlotingStyle.CARTO_DARKMATTER,
flip_coordinates=True,
show=False,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))
fig = distribution_system.plot(
map_type=MapType.SCATTER_MAP,
style=PlotingStyle.CARTO_POSITRON,
flip_coordinates=True,
show=False,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))
Distribution system plots can be styled by passing plotting options to the function to customize their appearance.
from gdm.distribution.enums import ColorNodeBy, ColorLineBy
distribution_system.plot(
color_node_by=ColorNodeBy.VOLTAGE_LEVEL,
color_line_by=ColorLineBy.PHASE,
flip_coordinates=True,
)
display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[3], line 8
1 from gdm.distribution.enums import ColorNodeBy, ColorLineBy
3 distribution_system.plot(
4 color_node_by=ColorNodeBy.VOLTAGE_LEVEL,
5 color_line_by=ColorLineBy.PHASE,
6 flip_coordinates=True,
7 )
----> 8 display(HTML(pio.to_html(fig, include_plotlyjs="cdn", full_html=False)))
File /opt/homebrew/Caskroom/miniconda/base/envs/gdm2/lib/python3.12/site-packages/plotly/io/_html.py:130, in to_html(fig, config, auto_play, include_plotlyjs, include_mathjax, post_script, full_html, animation_opts, default_width, default_height, validate, div_id)
127 from plotly.io.json import to_json_plotly
129 # ## Validate figure ##
--> 130 fig_dict = validate_coerce_fig_to_dict(fig, validate)
132 # ## Generate div id ##
133 plotdivid = div_id or str(uuid.uuid4())
File /opt/homebrew/Caskroom/miniconda/base/envs/gdm2/lib/python3.12/site-packages/plotly/io/_utils.py:20, in validate_coerce_fig_to_dict(fig, validate)
18 fig_dict = fig.to_plotly_json()
19 else:
---> 20 raise ValueError(
21 """
22 The fig parameter must be a dict or Figure.
23 Received value of type {typ}: {v}""".format(
24 typ=type(fig), v=fig
25 )
26 )
27 return fig_dict
ValueError:
The fig parameter must be a dict or Figure.
Received value of type <class 'NoneType'>: None
## Plotting using Matplotlib
df = distribution_system.to_gdf()
df.plot()
<Axes: >