Below is an extended summary of the code that describes how it constructs a SWMM model profile plot in Python, focusing on node/link geometry, profile configuration, and plot labeling:
Overview
This code supplies a set of matplotlib-based utilities for generating a profile plot (a side-view cut) of a SWMM model network, including nodes (manholes), links (conduits, weirs, orifices, pumps, outlets), ground elevation, and an optional hydraulic grade line (HGL). The profile is built from a path (a sequential chain of upstream-to-downstream elements) and rendered onto a given matplotlib axis (ax).
Core functionalities:
- Profile Building
build_profile_plot(ax, model, path_selection)– the central function that orchestrates retrieving geometry from a SWMM model, placing each node/link at the correct horizontal position, and returning a config dictionary (profile_config) for subsequent use.
- Node & Link Drawing
_add_node_plot(...)and_add_link_plot(...)– low-level routines to plot rectangles/trapezoids for manholes or link cross-sections (differentiating between conduits, weirs, orifices, pumps, etc.).
- Ground Line & HGL
_add_ground_plot(...)– draws the ground-level profile (brown dashed line) across the entire path.add_hgl_plot(...)– overlays a line that represents the computed or observed water surface elevation at each node (or between nodes).
- Labeling
add_node_labels_plot(...)– attaches text labels/arrows for each node in the profile.add_link_labels_plot(...)– attaches text labels/arrows for each link in the profile.
The net result is a layered side-view diagram of how nodes, links, ground line, and HGL align along a chosen path in a SWMM model.
Key Components
1. build_profile_plot(ax, model, path_selection)
Purpose:
- Assembles the entire profile by iterating over a list of
(us_node, ds_node, link_name)tuples, effectively describing a chain from upstream to downstream. - Produces a dictionary with details on each node/link’s placement, enabling further annotation or plotting.
Process:
-
Initialization
- Retrieves
nodes = model.nodes.dataframeandlinks = model.links.dataframe. - Declares
profile_configwith empty lists for “nodes” and “links,” plus “path_selection.” - Sets up arrays for
ground_levels['x']&ground_levels['level'].
- Retrieves
-
Iterating over Path
- For each tuple
(us_node, ds_node, link_id)inpath_selection:- Plots the first node if
ind == 0, calling_add_node_plot(...)and storing the node geometry inprofile_config["nodes"]. - Accumulates a “rolling x-position” (
rolling_x_pos) that simulates the horizontal distance for each link, dependent on link length or a default link length (if it’s a weir, orifice, pump, outlet). - Calls
_add_node_plot(...)again for the downstream node and_add_link_plot(...)for the link geometry between them.- Each node gets appended to
profile_config['nodes'], each link toprofile_config['links'].
- Each node gets appended to
- Plots the first node if
- After finishing the loop,
_add_ground_plot(...)is used to draw a dashed line indicating ground elevation.
- For each tuple
-
Return
- A
profile_configdictionary with:nodes: A list of dicts containing node IDs, rolling x-positions, invert elevations.links: A list of dicts with link IDs, midpoints, link type.path_selection: Echo of the input path for reference.
- A
2. _add_node_plot(ax, x, model, node_name, link_set, ... )
Purpose:
- Draws a rectangular manhole (or node structure) at position
xon the x-axis, with the correct invert elevation and max depth.
Details:
- Extracts
invert_elfromnodes.loc[node_name]. - Determines the node’s depth from model’s input data (
model.inp.junctions,model.inp.outfalls,model.inp.storage), defaulting toMaxDepth. - Plots a rectangle with corners
[(x−width, invert_el), (x+width, invert_el+depth), ...]in black lines. - Optionally draws a gradient fill on the sides for a 3D effect.
Returns:
- A dictionary of
{'x': [ul_x, ur_x], 'level': [ul_y, ur_y]}, used by_add_ground_plotto incorporate node’s top edge as part of ground level, if needed.
3. _add_link_plot(ax, us_x_position, ds_x_position, model, link_set, ...)
Purpose:
- Draws a link cross-section between the upstream node at
us_x_positionand downstream node atds_x_position, considering the link type (conduit, weir, orifice, pump, outlet).
Process:
- Determine link type from
links.loc[link_id].Type. - For CONDUIT:
- Use
links.loc[link_id].Length(already accounted for in the x offset) plus geometry fields likeGeom1for diameter/height,InOffset,OutOffsetfor vertical offsets.
- Use
- For ORIFICE, WEIR, PUMP, OUTLET:
- Uses specialized default lengths (like
DEFAULT_WEIR_LENGTH) or a single crest height for orifices/weirs. - Draw polygons or lines to represent the side profile.
- Uses specialized default lengths (like
- Returns a dict with
{'x': [...], 'bottom': [...], 'link_type': link_type, 'mid_x': [...], 'mid_y': [...]}, enabling the main function or labeling routines to know how to position text or the HGL line.
4. _add_ground_plot(ax, ground_levels)
Purpose:
- Joins the ground-level points computed from each node or link in a dashed brown line (
'--','brown'). - The
ground_levels['x']andground_levels['level']data are accumulated during node draws inbuild_profile_plot.
5. add_hgl_plot(ax, profile_config, hgl=None, depth=None, color='b', label="HGL")
Purpose:
- Overlays a line representing the hydraulic grade line (HGL) or water surface.
- Two usage patterns:
hgl– a dictionary/Series mapping node IDs to HGL elevations, ordepth– a dictionary/Series mapping node IDs to water depth, which is then added to the node invert.
- The function loops through each node in
profile_config['nodes'], builds an array of HGL values, and does a singleax.plot(...).
Weir Link Special Handling:
- If a link is type “WEIR,” it tries to insert a midpoint to reflect any possible “step” between upstream and downstream side. This ensures the HGL transitions properly if weirs create abrupt changes.
6. add_node_labels_plot(ax, model, profile_config, ...) and add_link_labels_plot(ax, model, profile_config, ...)
Purpose:
- Adds textual labels for each node or link above/below the structure.
- Each label is anchored with an arrow (
arrowprops=dict(...)) from the label text down to the structure. - Offers optional stagger so that labels alternate to avoid collisions.
Implementation details:
- For nodes:
- Extract invert + depth = top of node.
- Place an annotation arrow from the node top to a label above the highest node in the plot.
- For links:
- Use the link’s midpoint or bottom to place the arrow.
- Place the text below the entire group if needed (to avoid crowding).
Typical Usage Flow
- Call
build_profile_plot(ax, model, path_selection).- Returns
profile_configwith node/link geometry. - Draws the profile lines for manholes, conduits, ground, etc.
- Returns
- Optionally overlay:
add_hgl_plotto show the water surface profile.add_node_labels_plotoradd_link_labels_plotto label items.
- Render or save the figure:
import matplotlib.pyplot as plt fig, ax = plt.subplots() pcfg = build_profile_plot(ax, my_model, my_path) add_hgl_plot(ax, pcfg, hgl=node_water_surface_dict) add_node_labels_plot(ax, my_model, pcfg) add_link_labels_plot(ax, my_model, pcfg) plt.show()
Constants and Defaults
MH_WIDTH= 10: Horizontal half-width for manholes when drawing a node profile.DEFAULT_ORIFICE_LENGTH,DEFAULT_PUMP_LENGTH,DEFAULT_WEIR_LENGTH,DEFAULT_OUTLET_LENGTH: The “visual” length used for these special link types if the model doesn’t have a length (or if a simplified approach is desired).
Error Handling
error.InvalidDataTypes– raised ifadd_hgl_plot(...)sees neitherhglnordepthin the correct form.- The code also uses
model.inpreferences (likemodel.inp.junctions) to check how to interpret node depth or offset. If data is missing, it might cause an exception or result in an incomplete profile.
Conclusion
This code forms a profile-plot toolkit for SWMM or SWMM-like hydraulic models:
build_profile_plotsystematically places nodes and links horizontally, respecting lengths and offsets.- Node/Link subroutines handle the geometry difference among CONDUIT, WEIR, ORIFICE, PUMP, OUTLET.
- Ground line and HGL lines add topographical and hydraulic context.
- Labeling routines annotate each node/link, making the final plot self-explanatory.
Together, these help engineers or researchers visualize how water flows and see the relative elevations of nodes, the shape/length of links, and changes in water surface (HGL) across a chosen path in the SWMM network.