Monday, December 30, 2024

SWMMIO drawing.py Summary

 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:

  1. Draw shapes (e.g., circles for nodes, lines/polygons for conduits, parcels).
  2. Apply coloring schemes (e.g., flooding risk gradients, capacity usage).
  3. 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

  1. Size & Color Calculation for Nodes/Conduits/Parcels

    • node_draw_size(node) and node_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) and conduit_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).
  2. Drawing with PIL

    • draw_node(node, draw) and draw_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 or conduit.draw_coords.
    • draw_parcel_risk(parcel, draw) or draw_parcel_risk_delta(parcel, draw):
      • Fill polygons for subcatchments or parcels with specific colors to indicate risk/delta changes.
  3. 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.
  4. 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].
    • 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.
  5. 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 flow q into a line width by raising it to some exponent.

Usage Flow

A typical workflow might look like:

  1. Precompute or store in each node/parcel row the relevant attributes (e.g., HoursFlooded, MaxQ) along with drawing coordinates (node.draw_coords).
  2. Call draw_node(node, draw) or draw_conduit(conduit, draw) on a PIL.ImageDraw instance:
    • This automatically fetches the color and size from node_draw_color(node) and node_draw_size(node).
  3. Optionally annotate the image with street names (annotate_streets) or add a title/timestamp at the top corner.
  4. 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 by ImageFont.truetype.
  • swmmio.graphics.utils: Additional geometry or drawing utilities (like circle_bbox, angle_bw_points).
  • The code ultimately depends on PIL (from PIL import Image, ImageDraw, ImageFont, ImageOps) to manipulate raster images.

Benefits & Rationale

  1. 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.
  2. 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).
  3. 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:

A comprehensive explanation of how minimum travel distance relates to link length in InfoSewer

In hydraulic modeling of sewer networks, the minimum travel distance is a fundamental parameter that affects how accurately the model can si...