Source code for wntr.graphics.layer

"""
The wntr.graphics.layer module includes methods plot
water network data layers.
"""
import logging
import networkx as nx
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl

logger = logging.getLogger(__name__)

try:
    import geopandas as gpd_module
    from shapely.geometry import Point
except Exception:
    gpd_module = None


[docs] def plot_valve_layer(wn, valve_layer, valve_attribute=None, title=None, valve_size=15, valve_range=[None,None], valve_cmap=None, add_colorbar=True, colorbar_label=None, include_network=True, ax=None, filename=None, backend='nx'): """ Plot valve layer Parameters ---------- wn: wntr WaterNetworkModel A WaterNetworkModel object valve_layer: pd.Dataframe, optional Valve layer, defined by node and link pairs (for example, valve 0 is on link A and protects node B). The valve_layer DataFrame is indexed by valve number, with columns named 'node' and 'link'. valve_attribute: pd.Series, optional Attribute for each valve title: str, optional Plot title valve_size: int, optional Node size valve_range: list, optional Value range used to scale colormap ([None,None] indicates autoscale) valve_cmap: matplotlib.pyplot.cm colormap or named color, optional Valve colormap add_colorbar: bool, optional Add colorbar colorbar_label: str, optional Node colorbar label include_network: bool, optional Include a plot of the water network ax: matplotlib axes object, optional Axes for plotting (None indicates that a new figure with a single axes will be used) filename : str, optional Filename used to save the figure backend: str, optional Backend used for plotting: 'nx' for networkx (default) 'gpd' for geopandas Returns ------- ax : matplotlib axes object """ if backend == 'nx': ax = _plot_valve_layer_nx(wn, valve_layer, valve_attribute=valve_attribute, title=title, valve_size=valve_size, valve_range=valve_range, valve_cmap=valve_cmap, add_colorbar=add_colorbar, colorbar_label=colorbar_label, include_network=include_network, ax=ax, filename=filename) elif backend == 'gpd': ax = _plot_valve_layer_gpd(wn, valve_layer, valve_attribute=valve_attribute, title=title, valve_size=valve_size, valve_range=valve_range, valve_cmap=valve_cmap, add_colorbar=add_colorbar, colorbar_label=colorbar_label, include_network=include_network, ax=ax, filename=filename) else: raise Exception(f"Backend choice {backend} unrecognized. Please use 'nx' for networkx or 'gpd' for geopandas.") return ax
def _plot_valve_layer_nx(wn, valve_layer, valve_attribute=None, title=None, valve_size=15, valve_range=[None,None], valve_cmap=None, add_colorbar=True, colorbar_label=None, include_network=True, ax=None, filename=None): """ Plot valve layer using the networkx backend. """ if ax is None: # create a new figure plt.figure(facecolor='w', edgecolor='k') ax = plt.gca() # Graph, undirected G = wn.to_graph().to_undirected() # Position pos = nx.get_node_attributes(G,'pos') if len(pos) == 0: pos = None if title is not None: ax.set_title(title) if include_network: nx.draw_networkx_edges(G, pos, edge_color='grey', width=0.5, ax=ax) ax.axis('off') valve_coordinates = [] for valve_name, (pipe_name, node_name) in valve_layer.iterrows(): pipe = wn.get_link(pipe_name) if node_name == pipe.start_node_name: start_node = pipe.start_node end_node = pipe.end_node elif node_name == pipe.end_node_name: start_node = pipe.end_node end_node = pipe.start_node else: print("Not valid") continue x0 = start_node.coordinates[0] dx = end_node.coordinates[0] - x0 y0 = start_node.coordinates[1] dy = end_node.coordinates[1] - y0 valve_coordinates.append((x0 + dx * 0.1, y0 + dy * 0.1)) valve_coordinates = np.array(valve_coordinates) if valve_attribute is not None: sc = ax.scatter(valve_coordinates[:,0], valve_coordinates[:,1], s=valve_size, c=valve_attribute, marker='v', cmap=valve_cmap) else: sc = ax.scatter(valve_coordinates[:,0], valve_coordinates[:,1], s=valve_size, c='k', marker='v') if add_colorbar and valve_attribute is not None: clb = plt.colorbar(sc, shrink=0.5, pad=0.05, ax=ax) clb.ax.set_title(colorbar_label, fontsize=10) clb.mappable.set_clim(valve_range[0],valve_range[1]) if filename: plt.savefig(filename) return ax def _plot_valve_layer_gpd(wn, valve_layer, valve_attribute=None, title=None, valve_size=15, valve_range=[None,None], valve_cmap=None, add_colorbar=True, colorbar_label=None, include_network=True, ax=None, filename=None): """ Plot valve layer using the geopandas backend. Valve markers are drawn at zorder=6, above all elements rendered by _plot_network_gpd (max zorder=5). """ if gpd_module is None: raise ImportError('geopandas and shapely are required for the gpd backend') if ax is None: plt.figure(facecolor='w', edgecolor='k') ax = plt.gca() if title is not None: ax.set_title(title) wn_gis = wn.to_gis() link_gdf = pd.concat((wn_gis.pipes, wn_gis.pumps, wn_gis.valves)) if include_network: link_gdf.plot(ax=ax, aspect="equal", color='grey', linewidth=0.5, zorder=1) valve_points = [] valve_indices = [] for valve_name, (pipe_name, node_name) in valve_layer.iterrows(): pipe = wn.get_link(pipe_name) if pipe_name not in link_gdf.index: print("Not valid") continue geom = link_gdf.loc[pipe_name, "geometry"] if node_name == pipe.start_node_name: valve_points.append(geom.interpolate(0.1, normalized=True)) elif node_name == pipe.end_node_name: valve_points.append(geom.interpolate(0.9, normalized=True)) else: print("Not valid") continue valve_indices.append(valve_name) valve_gdf = gpd_module.GeoDataFrame(index=valve_indices, geometry=valve_points) valve_kwds = {"marker": "v", "markersize": valve_size, "zorder": 6, "aspect": "equal", "legend": False} if valve_attribute is not None: valve_gdf["_attribute"] = pd.Series(valve_attribute).reindex(valve_indices) valve_kwds["column"] = "_attribute" if valve_cmap is not None: valve_kwds["cmap"] = valve_cmap if valve_range[0] is not None: valve_kwds["vmin"] = valve_range[0] if valve_range[1] is not None: valve_kwds["vmax"] = valve_range[1] else: valve_kwds["color"] = "k" valve_gdf.plot(ax=ax, **valve_kwds) if add_colorbar and valve_attribute is not None: attr_values = valve_gdf["_attribute"] vmin = valve_range[0] if valve_range[0] is not None else attr_values.min() vmax = valve_range[1] if valve_range[1] is not None else attr_values.max() cmap = valve_cmap if valve_cmap is not None else plt.get_cmap('Spectral_r') sm = mpl.cm.ScalarMappable(cmap=cmap) sm.set_clim(vmin, vmax) clb = ax.figure.colorbar(sm, ax=ax, shrink=0.5, pad=0.05) clb.ax.set_title(colorbar_label, fontsize=10) ax.axis('off') if filename: plt.savefig(filename) return ax