def pf_res_plotly(net, cmap="Jet", use_line_geodata=None, on_map=False, projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=2, bus_size=10, climits_volt=(0.9, 1.1), climits_load=(0, 100), cpos_volt=1.0, cpos_load=1.1, filename="temp-plot.html", auto_open=True): """ Plots a pandapower network in plotly using colormap for coloring lines according to line loading and buses according to voltage in p.u. If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial INPUT: **net** - The pandapower format network. If none is provided, mv_oberrhein() will be plotted as an example OPTIONAL: **respect_switches** (bool, False) - Respect switches when artificial geodata is created **cmap** (str, True) - name of the colormap **colors_dict** (dict, None) - by default 6 basic colors from default collor palette is used. Otherwise, user can define a dictionary in the form: voltage_kv : color **on_map** (bool, False) - enables using mapbox plot in plotly. If provided geodata are not real geo-coordinates in lon/lat form, on_map will be set to False. **projection** (String, None) - defines a projection from which network geo-data will be transformed to lat-long. For each projection a string can be found at http://spatialreference.org/ref/epsg/ **map_style** (str, 'basic') - enables using mapbox plot in plotly - 'streets' - 'bright' - 'light' - 'dark' - 'satellite' **figsize** (float, 1) - aspectratio is multiplied by it in order to get final image size **aspectratio** (tuple, 'auto') - when 'auto' it preserves original aspect ratio of the network geodata any custom aspectration can be given as a tuple, e.g. (1.2, 1) **line_width** (float, 1.0) - width of lines **bus_size** (float, 10.0) - size of buses to plot. **climits_volt** (tuple, (0.9, 1.0)) - limits of the colorbar for voltage **climits_load** (tuple, (0, 100)) - limits of the colorbar for line_loading **cpos_volt** (float, 1.0) - position of the bus voltage colorbar **cpos_load** (float, 1.1) - position of the loading percent colorbar **filename** (str, "temp-plot.html") - filename / path to plot to. Should end on `*.html` **auto_open** (bool, True) - automatically open plot in browser OUTPUT: **figure** (graph_objs._figure.Figure) figure object """ version_check() if 'res_bus' not in net or net.get('res_bus').shape[0] == 0: logger.warning('There are no Power Flow results. A Newton-Raphson power flow will be executed.') runpp(net) # create geocoord if none are available if 'line_geodata' not in net: net.line_geodata = pd.DataFrame(columns=['coords']) if 'bus_geodata' not in net: net.bus_geodata = pd.DataFrame(columns=["x", "y"]) if len(net.line_geodata) == 0 and len(net.bus_geodata) == 0: logger.warning("No or insufficient geodata available --> Creating artificial coordinates." + " This may take some time") create_generic_coordinates(net, respect_switches=True) if on_map: logger.warning("Map plots not available with artificial coordinates and will be disabled!") on_map = False for geo_type in ["bus_geodata", "line_geodata"]: dupl_geo_idx = pd.Series(net[geo_type].index)[pd.Series( net[geo_type].index).duplicated()] if len(dupl_geo_idx): if len(dupl_geo_idx) > 20: logger.warning("In net.%s are %i duplicated " % (geo_type, len(dupl_geo_idx)) + "indices. That can cause troubles for draw_traces()") else: logger.warning("In net.%s are the following duplicated " % geo_type + "indices. That can cause troubles for draw_traces(): " + str( dupl_geo_idx)) # check if geodata are real geographycal lat/lon coordinates using geopy if on_map and projection is not None: geo_data_to_latlong(net, projection=projection) # ----- Buses ------ # initializating bus trace # hoverinfo which contains name and pf results precision = 3 hoverinfo = ( net.bus.name.astype(str) + '<br />' + 'V_m = ' + net.res_bus.vm_pu.round(precision).astype(str) + ' pu' + '<br />' + 'V_m = ' + (net.res_bus.vm_pu * net.bus.vn_kv.round(2)).round(precision).astype(str) + ' kV' + '<br />' + 'V_a = ' + net.res_bus.va_degree.round(precision).astype(str) + ' deg').tolist() hoverinfo = pd.Series(index=net.bus.index, data=hoverinfo) bus_trace = create_bus_trace(net, net.bus.index, size=bus_size, infofunc=hoverinfo, cmap=cmap, cbar_title='Bus Voltage [pu]', cmin=climits_volt[0], cmax=climits_volt[1], cpos=cpos_volt) # ----- Lines ------ # if bus geodata is available, but no line geodata # if bus geodata is available, but no line geodata cmap_lines = 'jet' if cmap == 'Jet' else cmap if use_line_geodata is None: use_line_geodata = False if len(net.line_geodata) == 0 else True elif use_line_geodata and len(net.line_geodata) == 0: logger.warning("No or insufficient line geodata available --> only bus geodata will be used.") use_line_geodata = False # hoverinfo which contains name and pf results hoverinfo = ( net.line.name.astype(str) + '<br />' + 'I = ' + net.res_line.loading_percent.round(precision).astype(str) + ' %' + '<br />' + 'I_from = ' + net.res_line.i_from_ka.round(precision).astype(str) + ' kA' + '<br />' + 'I_to = ' + net.res_line.i_to_ka.round(precision).astype(str) + ' kA' + '<br />').tolist() hoverinfo = pd.Series(index=net.line.index, data=hoverinfo) line_traces = create_line_trace(net, use_line_geodata=use_line_geodata, respect_switches=True, width=line_width, infofunc=hoverinfo, cmap=cmap_lines, cmap_vals=net.res_line['loading_percent'].values, cmin=climits_load[0], cmax=climits_load[1], cbar_title='Line Loading [%]', cpos=cpos_load) # ----- Trafos ------ # hoverinfo which contains name and pf results hoverinfo = ( net.trafo.name.astype(str) + '<br />' + 'I = ' + net.res_trafo.loading_percent.round(precision).astype(str) + ' %' + '<br />' + 'I_hv = ' + net.res_trafo.i_hv_ka.round(precision).astype(str) + ' kA' + '<br />' + 'I_lv = ' + net.res_trafo.i_lv_ka.round(precision).astype(str) + ' kA' + '<br />').tolist() hoverinfo = pd.Series(index=net.trafo.index, data=hoverinfo) trafo_traces = create_trafo_trace(net, width=line_width * 1.5, infofunc=hoverinfo, cmap=cmap_lines, cmin=0, cmax=100) # ----- Ext grid ------ # get external grid from create_bus_trace marker_type = 'circle' if on_map else 'square' ext_grid_trace = create_bus_trace(net, buses=net.ext_grid.bus, color='grey', size=bus_size * 2, trace_name='external_grid', patch_type=marker_type) return draw_traces(line_traces + trafo_traces + ext_grid_trace + bus_trace, showlegend=False, aspectratio=aspectratio, on_map=on_map, map_style=map_style, figsize=figsize, filename=filename, auto_open=auto_open)
def simple_plotly(net, respect_switches=True, use_line_geodata=None, on_map=False, projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=1, bus_size=10, ext_grid_size=20.0, bus_color="blue", line_color='grey', trafo_color='green', ext_grid_color="yellow"): """ 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 INPUT: **net** - The pandapower format network. If none is provided, mv_oberrhein() will be plotted as an example OPTIONAL: **respect_switches** (bool, True) - Respect switches when artificial geodata is created *use_line_geodata** (bool, True) - defines if lines patches are based on net.line_geodata of the lines (True) or on net.bus_geodata of the connected buses (False) **on_map** (bool, False) - enables using mapbox plot in plotly. If provided geodata are not real geo-coordinates in lon/lat form, on_map will be set to False. **projection** (String, None) - defines a projection from which network geo-data will be transformed to lat-long. For each projection a string can be found at http://spatialreference.org/ref/epsg/ **map_style** (str, 'basic') - enables using mapbox plot in plotly - 'streets' - 'bright' - 'light' - 'dark' - 'satellite' **figsize** (float, 1) - aspectratio is multiplied by it in order to get final image size **aspectratio** (tuple, 'auto') - when 'auto' it preserves original aspect ratio of the network geodata; any custom aspectration can be given as a tuple, e.g. (1.2, 1) **line_width** (float, 1.0) - width of lines **bus_size** (float, 10.0) - size of buses to plot. **ext_grid_size** (float, 20.0) - size of ext_grids to plot. See bus sizes for details. Note: ext_grids are plotted as rectangles **bus_color** (String, "blue") - Bus Color. Init as first value of color palette. **line_color** (String, 'grey') - Line Color. Init is grey **trafo_color** (String, 'green') - Trafo Color. Init is green **ext_grid_color** (String, 'yellow') - External Grid Color. Init is yellow OUTPUT: **figure** (graph_objs._figure.Figure) figure object """ version_check() # create geocoord if none are available if 'line_geodata' not in net: net.line_geodata = pd.DataFrame(columns=['coords']) if 'bus_geodata' not in net: net.bus_geodata = pd.DataFrame(columns=["x", "y"]) if len(net.bus_geodata) == 0: logger.warning( "No or insufficient geodata available --> Creating artificial coordinates." + " This may take some time...") create_generic_coordinates(net, respect_separation_points=respect_switches) if on_map: logger.warning( "Map plots not available with artificial coordinates and will be disabled!" ) on_map = False # check if geodata are real geographycal lat/lon coordinates using geopy if on_map and projection is not None: geo_data_to_latlong(net, projection=projection) # ----- Buses ------ # initializating bus trace hoverinfo = get_hoverinfo(net, element="bus") bus_trace = create_bus_trace(net, net.bus.index, size=bus_size, color=bus_color, infofunc=hoverinfo) # ----- Lines ------ # if bus geodata is available, but no line geodata if use_line_geodata is None: use_line_geodata = False if len(net.line_geodata) == 0 else True elif use_line_geodata and len(net.line_geodata) == 0: logger.warning( "No or insufficient line geodata available --> only bus geodata will be used." ) use_line_geodata = False hoverinfo = get_hoverinfo(net, element="line") line_traces = create_line_trace(net, net.line.index, respect_switches=respect_switches, color=line_color, width=line_width, use_line_geodata=use_line_geodata, infofunc=hoverinfo) # ----- Trafos ------ hoverinfo = get_hoverinfo(net, element="trafo") trafo_trace = create_trafo_trace(net, color=trafo_color, width=line_width * 5, infofunc=hoverinfo, use_line_geodata=use_line_geodata) # ----- Ext grid ------ # get external grid from create_bus_trace marker_type = 'circle' if on_map else 'square' # workaround because doesn't appear on mapbox if square hoverinfo = get_hoverinfo(net, element="ext_grid") ext_grid_trace = create_bus_trace(net, buses=net.ext_grid.bus, color=ext_grid_color, size=ext_grid_size, patch_type=marker_type, trace_name='external_grid', infofunc=hoverinfo) return draw_traces(line_traces + trafo_trace + ext_grid_trace + bus_trace, aspectratio=aspectratio, figsize=figsize, on_map=on_map, map_style=map_style)
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): version_check() # create geocoord if none are available branch_geodata = branch_element + "_geodata" node_geodata = node_element + "_geodata" if branch_geodata not in net: net[branch_geodata] = pd.DataFrame(columns=['coords']) if node_geodata not in net: net[node_geodata] = pd.DataFrame(columns=["x", "y"]) if len(net[node_geodata]) == 0: logger.warning( "No or insufficient geodata available --> Creating artificial coordinates." + " This may take some time...") create_generic_coordinates(net, respect_switches=respect_separators) if on_map: logger.warning( "Map plots not available with artificial coordinates and will be disabled!" ) on_map = False # check if geodata are real geographycal lat/lon coordinates using geopy if on_map and projection is not None: geo_data_to_latlong(net, projection=projection) # ----- Nodes (Buses) ------ # initializating node trace hoverinfo = hoverinfo_func(net, element=node_element) node_trace = node_trace_func(net, net[node_element].index, size=node_size, color=node_color, infofunc=hoverinfo) # ----- branches (Lines) ------ # if node geodata is available, but no branch geodata if use_branch_geodata is None: use_branch_geodata = False if len(net[branch_geodata]) == 0 else True elif use_branch_geodata and len(net[branch_geodata]) == 0: logger.warning( "No or insufficient line geodata available --> only bus geodata will be used." ) use_branch_geodata = False hoverinfo = hoverinfo_func(net, element=branch_element) branch_traces = branch_trace_func(net, net[branch_element].index, use_branch_geodata, respect_separators, color=branch_color, width=branch_width, infofunc=hoverinfo) trans_trace = [] # ----- Trafos ------ if 'trafo' in net: hoverinfo = hoverinfo_func(net, element=trans_element) trans_trace += create_trafo_trace(net, color=trafo_color, width=branch_width * 5, infofunc=hoverinfo, use_line_geodata=use_branch_geodata) # ----- 3W Trafos ------ if 'trafo3w' in net: hoverinfo = hoverinfo_func(net, element=trans3w_element) trans_trace += create_trafo_trace(net, color=trafo3w_color, trafotype='3W', width=branch_width * 5, trace_name='3w_trafos', infofunc=hoverinfo, use_line_geodata=use_branch_geodata) # ----- Ext grid ------ # get external grid from _create_node_trace marker_type = 'circle' if on_map else 'square' # workaround because doesn't appear on mapbox if square hoverinfo = hoverinfo_func(net, element="ext_grid") ext_grid_trace = _create_node_trace(net, nodes=net.ext_grid[node_element], size=ext_grid_size, patch_type=marker_type, color=ext_grid_color, infofunc=hoverinfo, trace_name='external_grid', node_element=node_element, branch_element=branch_element) return draw_traces(branch_traces + trans_trace + ext_grid_trace + node_trace, aspectratio=aspectratio, figsize=figsize, on_map=on_map, map_style=map_style, filename=filename, auto_open=auto_open)
def vlevel_plotly(net, respect_switches=True, use_line_geodata=None, colors_dict=None, on_map=False, projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=2, bus_size=10): """ Plots a pandapower network in plotly using lines/buses colors according to the voltage level they belong to. If no geodata is available, artificial geodata is generated. For advanced plotting see the tutorial INPUT: **net** - The pandapower format network. If none is provided, mv_oberrhein() will be plotted as an example OPTIONAL: **respect_switches** (bool, True) - Respect switches when artificial geodata is created **use_line_geodata** (bool, True) - defines if lines patches are based on net.line_geodata of the lines (True) or on net.bus_geodata of the connected buses (False) *colors_dict** (dict, None) - dictionary for customization of colors for each voltage level in the form: voltage_kv : color **on_map** (bool, False) - enables using mapbox plot in plotly If provided geodata are not real geo-coordinates in lon/lat form, on_map will be set to False. **projection** (String, None) - defines a projection from which network geo-data will be transformed to lat-long. For each projection a string can be found at http://spatialreference.org/ref/epsg/ **map_style** (str, 'basic') - enables using mapbox plot in plotly - 'streets' - 'bright' - 'light' - 'dark' - 'satellite' **figsize** (float, 1) - aspectratio is multiplied by it in order to get final image size **aspectratio** (tuple, 'auto') - when 'auto' it preserves original aspect ratio of the network geodata any custom aspectration can be given as a tuple, e.g. (1.2, 1) **line_width** (float, 1.0) - width of lines **bus_size** (float, 10.0) - size of buses to plot. """ version_check() # create geocoord if none are available if 'line_geodata' not in net: net.line_geodata = pd.DataFrame(columns=['coords']) if 'bus_geodata' not in net: net.bus_geodata = pd.DataFrame(columns=["x", "y"]) if len(net.line_geodata) == 0 and len(net.bus_geodata) == 0: logger.warning("No or insufficient geodata available --> Creating artificial coordinates." + " This may take some time") create_generic_coordinates(net, respect_switches=respect_switches) if on_map: logger.warning("Map plots not available with artificial coordinates and will be disabled!") on_map = False # check if geodata are real geographycal lat/lon coordinates using geopy if on_map and projection is not None: geo_data_to_latlong(net, projection=projection) # if bus geodata is available, but no line geodata if use_line_geodata is None: use_line_geodata = False if len(net.line_geodata) == 0 else True elif use_line_geodata and len(net.line_geodata) == 0: logger.warning("No or insufficient line geodata available --> only bus geodata will be used.") use_line_geodata = False # getting connected componenets without consideration of trafos graph = create_nxgraph(net, include_trafos=False) vlev_buses = connected_components(graph) # getting unique sets of buses for each voltage level vlev_bus_dict = {} for vl_buses in vlev_buses: if net.bus.loc[vl_buses, 'vn_kv'].unique().shape[0] > 1: logger.warning('buses from the same voltage level does not have the same vn_kv !?') vn_kv = net.bus.loc[vl_buses, 'vn_kv'].unique()[0] if vlev_bus_dict.get(vn_kv): vlev_bus_dict[vn_kv].update(vl_buses) else: vlev_bus_dict[vn_kv] = vl_buses # create a default colormap for voltage levels nvlevs = len(vlev_bus_dict) colors = get_plotly_color_palette(nvlevs) colors_dict = dict(zip(vlev_bus_dict.keys(), colors)) # creating traces for buses and lines for each voltage level bus_traces = [] line_traces = [] for vn_kv, buses_vl in vlev_bus_dict.items(): vlev_color = colors_dict[vn_kv] bus_trace_vlev = create_bus_trace(net, buses=buses_vl, size=bus_size, legendgroup=str(vn_kv), color=vlev_color, trace_name='buses {0} kV'.format(vn_kv)) if bus_trace_vlev is not None: bus_traces += bus_trace_vlev vlev_lines = net.line[net.line.from_bus.isin(buses_vl) & net.line.to_bus.isin(buses_vl)].index.tolist() line_trace_vlev = create_line_trace(net, lines=vlev_lines, use_line_geodata=use_line_geodata, respect_switches=respect_switches, legendgroup=str(vn_kv), color=vlev_color, width=line_width, trace_name='lines {0} kV'.format(vn_kv)) if line_trace_vlev is not None: line_traces += line_trace_vlev trafo_traces = create_trafo_trace(net, color='gray', width=line_width * 2) draw_traces(line_traces + trafo_traces + bus_traces, showlegend=True, aspectratio=aspectratio, on_map=on_map, map_style=map_style, figsize=figsize)
def _draw_colored_bus_groups_plotly( net, bus_groups, respect_switches=True, use_line_geodata=None, on_map=False, projection=None, map_style='basic', figsize=1, aspectratio='auto', line_width=2, bus_size=10, filename="temp-plot.html", auto_open=True): """ Internal function of vlevel_plotly() **bus_groups** - list of tuples consisting of set of bus indices, color, legendgroup """ version_check() # create geocoord if none are available if 'line_geodata' not in net: net.line_geodata = pd.DataFrame(columns=['coords']) if 'bus_geodata' not in net: net.bus_geodata = pd.DataFrame(columns=["x", "y"]) if len(net.line_geodata) == 0 and len(net.bus_geodata) == 0: logger.warning("No or insufficient geodata available --> Creating artificial coordinates." + " This may take some time") create_generic_coordinates(net, respect_switches=respect_switches) if on_map: logger.warning( "Map plots not available with artificial coordinates and will be disabled!") on_map = False # check if geodata are real geographycal lat/lon coordinates using geopy if on_map and projection is not None: geo_data_to_latlong(net, projection=projection) # if bus geodata is available, but no line geodata if use_line_geodata is None: use_line_geodata = False if len(net.line_geodata) == 0 else True elif use_line_geodata and len(net.line_geodata) == 0: logger.warning( "No or insufficient line geodata available --> only bus geodata will be used.") use_line_geodata = False # creating traces for buses and lines for each voltage level bus_traces = [] line_traces = [] traced_lines = set() for bus_group_legend in bus_groups: buses_vl, vlev_color, legend_group = bus_group_legend bus_trace_vlev = create_bus_trace( net, buses=buses_vl, size=bus_size, legendgroup=legend_group, color=vlev_color, trace_name=f'buses {legend_group}') if bus_trace_vlev is not None: bus_traces += bus_trace_vlev vlev_lines = net.line[net.line.from_bus.isin(buses_vl) & net.line.to_bus.isin(buses_vl)].index.tolist() traced_lines |= set(vlev_lines) line_trace_vlev = create_line_trace( net, lines=vlev_lines, use_line_geodata=use_line_geodata, respect_switches=respect_switches, legendgroup=legend_group, color=vlev_color, width=line_width, trace_name=f'lines {legend_group}') if line_trace_vlev is not None: line_traces += line_trace_vlev # creating traces for other lines line_trace_other = create_line_trace( net, lines=net.line.index.difference(traced_lines).tolist(), use_line_geodata=use_line_geodata, respect_switches=respect_switches, color="grey", width=line_width) if line_trace_vlev is not None: line_traces += line_trace_other trafo_traces = create_trafo_trace(net, color='gray', width=line_width * 2) return draw_traces(line_traces + trafo_traces + bus_traces, showlegend=True, aspectratio=aspectratio, on_map=on_map, map_style=map_style, figsize=figsize, filename=filename, auto_open=auto_open)