Skip to content

Commit

Permalink
extend plotly function: add zoomlevel and hvdc lines, more parameters (
Browse files Browse the repository at this point in the history
…e2nIEE#2259)

* add zoomlevel and hvdc lines to plotly-plotting

* Update CHANGELOG.rst

* extend docstring, order CHANGELOG.rst
  • Loading branch information
jkisse authored Apr 16, 2024
1 parent 5cda155 commit a4f1d90
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 28 deletions.
9 changes: 5 additions & 4 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ Change Log

[upcoming release] - 2024-..-..
-------------------------------
- [ADDED] switch results p and q
- [ADDED] PowerFactory converter: option to export lines with sections as a single line with averaged-out impedance, or export line sections as separate individual lines
- [ADDED] extend plotly function: add zoomlevel-parameter and hvdc lines
- [CHANGED] plotting for voltage profile considers also gens that are slacks and only ext_grids and slack gens that are in service
- [CHANGED] switched from setup.py to pyproject.toml
- [CHANGED] updated upload_release.py to not call setup.py anymore (see https://packaging.python.org/en/latest/discussions/setup-py-deprecated/)
- [CHANGED] updated upload_release.py to install the uploadad package and print the version
- [CHANGED] updated MANIFEST.in to exclude the ci files from the wheel distribution
- [FIXED] further futurewarnings and deprecation warnings
- [ADDED] switch results p and q
- [CHANGED] plotting for voltage profile considers also gens that are slacks and only ext_grids and slack gens that are in service
- [ADDED] PowerFactory converter: option to export lines with sections as a single line with averaged-out impedance, or export line sections as separate individual lines
- [FIXED] massive performance drag in large grids due to initializing Ybus for FACTS with np.zeros instead of using sparse matrix initialization
- [FIXED] further futurewarnings and deprecation warnings

[2.14.6] - 2024-04-02
-------------------------------
Expand Down
35 changes: 26 additions & 9 deletions pandapower/plotting/plotly/simple_plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from pandapower.plotting.generic_geodata import create_generic_coordinates
from pandapower.plotting.plotly.traces import create_bus_trace, create_line_trace, \
create_scale_trace, create_trafo_trace, draw_traces, _create_node_trace, _create_branch_trace
create_dcline_trace, create_scale_trace, create_trafo_trace, draw_traces, \
_create_node_trace, _create_branch_trace
from pandapower.plotting.plotly.mapbox_plot import *

try:
Expand Down Expand Up @@ -76,7 +77,7 @@ def simple_plotly(net, respect_switches=True, use_line_geodata=None, on_map=Fals
bus_color="blue", line_color='grey', trafo_color='green',
trafo3w_color='green', ext_grid_color="yellow",
filename='temp-plot.html', auto_open=True, showlegend=True,
additional_traces=None):
additional_traces=None, zoomlevel=11, auto_draw_traces=True, hvdc_color='cyan'):
"""
Plots a pandapower network as simple as possible in plotly.
If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial
Expand Down Expand Up @@ -134,6 +135,14 @@ def simple_plotly(net, respect_switches=True, use_line_geodata=None, on_map=Fals
**additional_traces** (list, None) - List with additional, user-created traces that will
be appended to the simple_plotly traces before drawing all traces
**zoomlevel** (int, 11) - initial mapbox-zoomlevel on a map if `on_map=True`. Small
values = less zoom / larger area shown
**auto_draw_traces** (bool, True) - if True, a figure with the drawn traces is returned.
If False, the traces and a dict with settings is returned
**hvdc_color** (str, "cyan") - color for HVDC lines
OUTPUT:
**figure** (graph_objs._figure.Figure) figure object
"""
Expand Down Expand Up @@ -168,7 +177,9 @@ def simple_plotly(net, respect_switches=True, use_line_geodata=None, on_map=Fals
hoverinfo_func=get_hoverinfo,
filename=filename,
auto_open=auto_open,
showlegend=showlegend)
showlegend=showlegend,
zoomlevel=zoomlevel,
hvdc_color=hvdc_color)
if additional_traces:
if isinstance(additional_traces, dict):
additional_traces = [additional_traces]
Expand All @@ -182,20 +193,21 @@ def simple_plotly(net, respect_switches=True, use_line_geodata=None, on_map=Fals
shift += len(weighted_trace["meta"]["scale_marker_size"])

traces.extend(additional_traces)

return draw_traces(traces, **settings)

if auto_draw_traces:
return draw_traces(traces, **settings)
else:
return traces, settings

def _simple_plotly_generic(net, respect_separators, use_branch_geodata, on_map, projection, map_style,
figsize, aspectratio, branch_width, node_size, ext_grid_size, node_color,
branch_color, trafo_color, trafo3w_color, ext_grid_color,
node_element, branch_element, trans_element, trans3w_element,
separator_element, branch_trace_func, node_trace_func,
hoverinfo_func, filename='temp-plot.html', auto_open=True,
showlegend=True):
showlegend=True, zoomlevel=11, hvdc_color="cyan"):
settings = dict(on_map=on_map, projection=projection, map_style=map_style, figsize=figsize,
aspectratio=aspectratio, filename=filename, auto_open=auto_open,
showlegend=showlegend)
showlegend=showlegend, zoomlevel=zoomlevel)
# create geocoord if none are available
branch_geodata = branch_element + "_geodata"
node_geodata = node_element + "_geodata"
Expand Down Expand Up @@ -236,6 +248,7 @@ def _simple_plotly_generic(net, respect_separators, use_branch_geodata, on_map,
trans_trace = []
trans_trace3w = []
ext_grid_trace = []
dc_line_trace = []
# ----- Trafos ------
if 'trafo' in net and len(net.trafo):
hoverinfo = hoverinfo_func(net, element=trans_element)
Expand All @@ -258,8 +271,12 @@ def _simple_plotly_generic(net, respect_separators, use_branch_geodata, on_map,
patch_type=marker_type, color=ext_grid_color,
infofunc=hoverinfo, trace_name='external grid',
node_element=node_element, branch_element=branch_element)
# ----- HVDC lines ------
if 'dcline' in net and len(net.dcline):
dc_line_trace = create_dcline_trace(net, color=hvdc_color)

return branch_traces + trans_trace + trans_trace3w + ext_grid_trace + node_trace, settings
return branch_traces + trans_trace + trans_trace3w + ext_grid_trace + node_trace + dc_line_trace,\
settings


if __name__ == '__main__':
Expand Down
104 changes: 89 additions & 15 deletions pandapower/plotting/plotly/traces.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,8 @@ def _get_branch_geodata_plotly(net, branches, use_branch_geodata, branch_element
def create_line_trace(net, lines=None, use_line_geodata=True, respect_switches=False, width=1.0,
color='grey', infofunc=None, trace_name='lines', legendgroup='lines',
cmap=None, cbar_title=None, show_colorbar=True, cmap_vals=None, cmin=None,
cmax=None, cpos=1.1, cmap_vals_category='loading_percent', hoverlabel=None):
cmax=None, cpos=1.1, cmap_vals_category='loading_percent', hoverlabel=None,
dash="solid"):
"""
Creates a plotly trace of pandapower lines. It is a power net specific wrapper function for the
more generic _create_line_trace function.
Expand Down Expand Up @@ -417,6 +418,78 @@ def create_line_trace(net, lines=None, use_line_geodata=True, respect_switches=F
separator_element=separator_element,
node_element=node_element,
cmap_vals_category=cmap_vals_category,
hoverlabel=hoverlabel,
dash=dash)

def create_dcline_trace(net, dclines=None, width=1.0,
color='grey', infofunc=None, trace_name='hvdc lines', legendgroup='dclines',
cmap=None, cbar_title=None, show_colorbar=True, cmap_vals=None, cmin=None,
cmax=None, cpos=1.1, cmap_vals_category='loading_percent', hoverlabel=None):
"""
Creates a plotly trace of pandapower dclines. It is a power net specific wrapper function for the
more generic _create_line_trace function.
INPUT:
**net** (pandapowerNet) - The pandapower network
OPTIONAL:
**dclines** (list, None) - The lines for which the collections are created.
If None, all lines in the network are considered.
**width** (int, 1) - line width
**infofunc** (pd.Series, None) - hoverinfo for dcline elements. Indices should correspond to
the pandapower element indices
**trace_name** (String, "lines") - name of the trace which will appear in the legend
**color** (String, "grey") - color of dclines in the trace
**legendgroup** (String, None) - defines groups of layers that will be displayed in a legend
e.g. groups according to voltage level (as used in `vlevel_plotly`)
**cmap** (String, None) - name of a colormap which exists within plotly if set to True default `Jet`
colormap is used, alternative colormaps : Greys, YlGnBu, Greens, YlOrRd,
Bluered, RdBu, Reds, Blues, Picnic, Rainbow, Portland, Jet, Hot, Blackbody, Earth, Electric, Viridis
To revert the color map, append "_r" to the name.
**cmap_vals** (list, None) - values used for coloring using colormap
**show_colorbar** (bool, False) - flag for showing or not corresponding colorbar
**cbar_title** (String, None) - title for the colorbar
**cmin** (float, None) - colorbar range minimum
**cmax** (float, None) - colorbar range maximum
**cpos** (float, 1.1) - position of the colorbar
"""

branch_element = "dcline"
node_element = "bus"
separator_element = "switch"

return _create_branch_trace(net=net,
branches=dclines,
use_branch_geodata=False,
width=width,
color=color,
infofunc=infofunc,
trace_name=trace_name,
legendgroup=legendgroup,
cmap=cmap,
cbar_title=cbar_title,
show_colorbar=show_colorbar,
cmap_vals=cmap_vals,
cmin=cmin,
cmax=cmax,
cpos=cpos,
branch_element=branch_element,
separator_element=separator_element,
node_element=node_element,
cmap_vals_category=cmap_vals_category,
hoverlabel=hoverlabel)


Expand All @@ -425,7 +498,7 @@ def _create_branch_trace(net, branches=None, use_branch_geodata=True, respect_se
legendgroup=None, cmap=None, cbar_title=None, show_colorbar=True,
cmap_vals=None, cmin=None, cmax=None, cpos=1.1, branch_element='line',
separator_element='switch', node_element='bus',
cmap_vals_category='loading_percent', hoverlabel=None):
cmap_vals_category='loading_percent', hoverlabel=None, dash="solid"):
"""
Creates a plotly trace of branch elements. The rather generic, non-power net specific names
were introduced to make it usable in other packages, e.g. for pipe networks.
Expand Down Expand Up @@ -495,11 +568,10 @@ def _create_branch_trace(net, branches=None, use_branch_geodata=True, respect_se
len(infofunc) == len(branches):
infofunc = pd.Series(index=branches, data=infofunc)
if len(infofunc) != len(branches) and len(infofunc) != len(net[branch_element]):
raise UserWarning("Different amount of hover info than {}s to "
"plot".format(branch_element))
raise UserWarning(f"Different amount of hover info than {branch_element}s to plot")
assert isinstance(infofunc, pd.Series), \
"infofunc should be a pandas series with the net.{}.index to the infofunc " \
"contents".format(branch_element)
f"infofunc should be a pandas series with the net.{branch_element}.index " \
f"to the infofunc contents"
no_go_branches = set()
if respect_separators:
if separator_element == "switch":
Expand All @@ -511,14 +583,15 @@ def _create_branch_trace(net, branches=None, use_branch_geodata=True, respect_se
set(net[separator_element][(~net[separator_element].in_service) |
(net[separator_element].opened)])
else:
raise NotImplementedError("respect separtors is only implements for switches, "
"not for {}s.".format(separator_element))
raise NotImplementedError(f"respect separators is only implements for switches, "
"not for {separator_element}s.")
branches_to_plot = net[branch_element].loc[list(set(net[branch_element].index) &
(set(branches) - no_go_branches))]
no_go_branches_to_plot = None
branch_geodata = branch_element + "_geodata"
node_geodata = node_element + "_geodata"
use_branch_geodata = use_branch_geodata if net[branch_geodata].shape[0] > 0 else False
if not (branch_geodata in net) or not len(net[branch_geodata]):
use_branch_geodata = False
if use_branch_geodata:
branches_to_plot = branches_to_plot.loc[np.intersect1d(branches_to_plot.index,
net[branch_geodata].index)]
Expand Down Expand Up @@ -568,7 +641,7 @@ def _create_branch_trace(net, branches=None, use_branch_geodata=True, respect_se
branch_element, idx, branch['name']))

line_trace = dict(type='scatter', text=[], hoverinfo='text', mode='lines', name=trace_name,
line=Line(width=width, color=color), showlegend=False,
line=Line(width=width, color=color, dash=dash), showlegend=False,
legendgroup=legendgroup)

line_trace['x'], line_trace['y'] = _get_branch_geodata_plotly(net,
Expand Down Expand Up @@ -958,7 +1031,7 @@ def create_scale_trace(net, weighted_trace, down_shift=0):
color=scale_info.get("scale_marker_color"),
symbol=marker["symbol"],
sizemode=marker["sizemode"]),
text=[f"{scale_size / scale_info['marker_scaling']} {unit}", ""],
text=[f"{scale_size / scale_info['marker_scaling']:.0f} {unit}", ""],
textposition="top center",
showlegend=False,
textfont=dict(family="Helvetica",
Expand Down Expand Up @@ -1033,8 +1106,9 @@ def draw_traces(traces, on_map=False, map_style='basic', showlegend=True, figsiz
# scattermapboxplot lines do not support dash for some reason, make it a red line instead
if "dash" in trace["line"]._props:
_prps = dict(trace["line"]._props)
_prps.pop("dash", None)
_prps["color"] = "red"
_prps.pop("dash")
if trace["line"]._props["dash"] != "solid":
_prps["color"] = "red"
trace["line"] = scmLine(_prps)
else:
trace["line"] = scmLine(dict(trace["line"]._props))
Expand Down Expand Up @@ -1081,7 +1155,7 @@ def draw_traces(traces, on_map=False, map_style='basic', showlegend=True, figsiz
lon=pd.Series(traces[0]['lon']).dropna().mean()),
style=map_style,
pitch=0,
zoom=kwargs.pop('zoomlevel', 11))
zoom=kwargs.pop('zoomlevel', 3))

# default aspectratio: if on_map use auto, else use 'original'
aspectratio = 'original' if not on_map and aspectratio == 'auto' else aspectratio
Expand Down Expand Up @@ -1118,7 +1192,7 @@ def draw_traces(traces, on_map=False, map_style='basic', showlegend=True, figsiz
fig['layout']['width'], fig['layout']['height'] = ([ar * figsize * 700 for ar in aspectratio])

# check if called from ipynb or not in order to consider appropriate plot function
if _in_ipynb():
if _in_ipynb() and auto_open:
from plotly.offline import init_notebook_mode, iplot as plot
init_notebook_mode()
plot(fig, filename=filename)
Expand Down

0 comments on commit a4f1d90

Please sign in to comment.