Below is an extended summary of this code, describing its primary functions, purpose, and how it integrates data about SWMM models (or similarly structured geospatial data) with Python’s PIL library for visualization.
Overview
This code provides a set of utility functions for graphically rendering elements of a SWMM-like model (nodes, conduits, parcels, etc.) on a static image. It leverages PIL (Python Imaging Library) to:
- Draw shapes (e.g., circles for nodes, lines/polygons for conduits, parcels).
- Apply coloring schemes (e.g., flooding risk gradients, capacity usage).
- Annotate images with text (titles, timestamps, details).
These functions appear especially useful for diagnosing or visualizing simulation results, such as hours flooded, maximum flow, or changes in subcatchment flooding.
Key Functional Areas
-
Size & Color Calculation for Nodes/Conduits/Parcels
node_draw_size(node)
andnode_draw_color(node)
:- Calculate a node’s radius and fill color based on attributes like “HoursFlooded.”
- Example: If a node floods for more than a threshold, it’s drawn larger and in red.
conduit_draw_size(conduit)
andconduit_draw_color(conduit)
:- Return draw size (line thickness) and color for a conduit based on flow capacity or “MaxQPerc.”
- Example: Overstressed conduits might be rendered thicker and shift from grey to red.
parcel_draw_color(parcel, style='risk')
:- For polygons representing parcels, color them according to risk levels or differences between scenarios (e.g., new_flooding = purple, decreased_flooding = lightblue).
-
Drawing with PIL
draw_node(node, draw)
anddraw_conduit(conduit, draw)
:- Use the node/conduit’s computed color/size to draw circles/lines on a
PIL.ImageDraw
object. - Coordinates are taken from
node.draw_coords
orconduit.draw_coords
.
- Use the node/conduit’s computed color/size to draw circles/lines on a
draw_parcel_risk(parcel, draw)
ordraw_parcel_risk_delta(parcel, draw)
:- Fill polygons for subcatchments or parcels with specific colors to indicate risk/delta changes.
-
Annotating Streets & Text
annotate_streets(df, img, text_col)
:- For each row in a DataFrame, draws a street name text along a line, rotated according to the angle between two points.
- Uses
ImageFont.truetype
with a user-defined font path (FONT_PATH
).
annotate_title(title, draw)
,annotate_timestamp(draw)
,annotate_details(txt, draw)
:- Writes a map title, date/time stamp, or additional text onto the image at specified positions.
-
Color Gradients
gradient_grey_red(x, xmin, xmax)
:- Converts a numeric value into an RGB color between grey and red, depending on how
x
compares to[xmin, xmax]
.
- Converts a numeric value into an RGB color between grey and red, depending on how
gradient_color_red(x, xmin, xmax, startCol=lightgrey)
:- Similar approach, but from a start color (e.g., lightgrey) to red.
- The gradient formulas increment or decrement each RGB channel to create a color scale.
- These gradient functions are used in node/conduit drawing or parcel coloring, to reflect data like flow or hours flooded.
-
Miscellaneous Utilities
circle_bbox(center, radius)
: Returns bounding box coords for a circle, given center coords and radius.length_bw_coords(pt1, pt2)
: Computes distance between two points.angle_bw_points(pt1, pt2)
: Returns the angle in degrees between two points, used for text rotation.midpoint(pt1, pt2)
: Returns the midpoint of two coordinates.line_size(q, exp=1)
: Quick function for scaling a numeric flowq
into a line width by raising it to some exponent.
Usage Flow
A typical workflow might look like:
- Precompute or store in each node/parcel row the relevant attributes (e.g.,
HoursFlooded
,MaxQ
) along with drawing coordinates (node.draw_coords
). - Call
draw_node(node, draw)
ordraw_conduit(conduit, draw)
on aPIL.ImageDraw
instance:- This automatically fetches the color and size from
node_draw_color(node)
andnode_draw_size(node)
.
- This automatically fetches the color and size from
- Optionally annotate the image with street names (
annotate_streets
) or add a title/timestamp at the top corner. - Save or show the final
PIL
image after all shapes are drawn.
Integration
swmmio.defs.constants
: The code references color constants (red, purple, lightblue, lightgreen, black, lightgrey, grey
).FONT_PATH
: A user-specified or default file path to a TrueType font, needed byImageFont.truetype
.swmmio.graphics.utils
: Additional geometry or drawing utilities (likecircle_bbox
,angle_bw_points
).- The code ultimately depends on PIL (
from PIL import Image, ImageDraw, ImageFont, ImageOps
) to manipulate raster images.
Benefits & Rationale
-
Automated Visualization:
- Simplifies drawing SWMM-based or geospatial data onto images, using meaningful color scales for flow, flood hours, or infiltration.
- Great for debugging (e.g., seeing which conduits are near capacity) or for final reporting.
-
Flexible:
- Because color sizes/gradients are derived from numeric columns (
MaxQPerc
,HoursFlooded
, etc.), the script can be easily extended to new metrics (like water quality data).
- Because color sizes/gradients are derived from numeric columns (
-
PIL-based:
- The code is library-agnostic in the sense that it doesn’t rely on more complex plotting frameworks (like matplotlib).
- A plain
ImageDraw
approach can be scaled for simpler or more custom rendering.
Conclusion
In summary, this code is a lightweight but comprehensive set of drawing and annotation routines for SWMM or other hydrologic/hydraulic data. It ties together numeric data (like flooding hours or conduit capacity usage) with visual cues (line thickness, color gradients) in a PIL image. By doing so, it enables automated map creation or quick debugging plots for model elements—nodes, conduits, parcels—complete with text annotations and dynamic color scaling.
No comments:
Post a Comment