Visualization Module
Diagnostic and debug visualizations for terrain processing.
This subpackage provides visualization tools for flow analysis, edge extrusion debugging, bounds pipeline transformations, and linear feature layers (streams, roads, trails).
Flow Diagnostics
Standardized visualizations for flow accumulation analysis: DEM views, ocean masks, water bodies, drainage networks, and validation summaries.
Flow diagnostic visualization functions.
This module provides standardized visualizations for flow accumulation analysis, including DEM views, ocean masks, water bodies, drainage networks, and validation summaries.
Example
from src.terrain.visualization.flow_diagnostics import create_flow_diagnostics
# Generate all diagnostic plots create_flow_diagnostics(
dem=dem, dem_conditioned=dem_conditioned, ocean_mask=ocean_mask, flow_dir=flow_dir, drainage_area=drainage_area, upstream_rainfall=upstream_rainfall, precip=precip, output_dir=Path(“output/diagnostics”), lake_mask=lake_mask, lake_outlets=lake_outlets,
)
- src.terrain.visualization.flow_diagnostics.save_flow_plot(data, title, output_path, cmap, label='', log_scale=False, mask=None, overlay_data=None, overlay_cmap=None, overlay_alpha=0.7, vmin=None, vmax=None, figsize=(12, 10), dpi=150, pixel_perfect=True)[source]
Save a single flow diagnostic plot to file.
- Parameters:
data (np.ndarray) – 2D array of data to plot
title (str) – Plot title
output_path (Path) – Output file path
cmap (str) – Matplotlib colormap name
label (str, optional) – Colorbar label
log_scale (bool, optional) – Apply log10 transformation
mask (np.ndarray, optional) – Boolean mask for data (True = mask out)
overlay_data (np.ndarray, optional) – Boolean array for overlay
overlay_cmap (str, optional) – Colormap for overlay
overlay_alpha (float, optional) – Alpha for overlay (default: 0.7)
vmin (float, optional) – Colorbar limits
vmax (float, optional) – Colorbar limits
figsize (tuple, optional) – Figure size in inches
dpi (int, optional) – Output resolution
pixel_perfect (bool, optional) – If True, save pixel-perfect raw image + annotated thumbnail (default: True)
- Returns:
Path to saved file (raw version if pixel_perfect=True)
- Return type:
Path
- src.terrain.visualization.flow_diagnostics.plot_dem(dem, output_path, title=None)[source]
Plot original DEM elevation.
- src.terrain.visualization.flow_diagnostics.plot_ocean_mask(ocean_mask, output_path)[source]
Plot ocean mask with coverage percentage.
- src.terrain.visualization.flow_diagnostics.plot_water_bodies(dem, lake_mask, output_path, flow_dir=None, lake_outlets=None, lake_inlets=None)[source]
Plot water bodies with optional flow arrows for outlets/inlets.
Shows DEM as background with lakes overlaid in blue. If flow_dir is provided, draws quiver arrows showing: - Red arrows: outlets (water leaving lakes) - Green arrows: inlets (water entering lakes)
Saves pixel-perfect raw image + annotated thumbnail with arrows.
- src.terrain.visualization.flow_diagnostics.plot_endorheic_basins(dem, basin_mask, output_path)[source]
Plot endorheic basins overlaid on DEM. Pixel-perfect output.
- src.terrain.visualization.flow_diagnostics.plot_conditioned_dem(dem_conditioned, output_path)[source]
Plot conditioned (depression-filled) DEM.
- src.terrain.visualization.flow_diagnostics.plot_breach_depth(dem, breached_dem, ocean_mask, output_path)[source]
Plot breach depth (how much elevation was lowered during breaching).
Breach depth shows where and how much the DEM was lowered to create flow paths. Positive values indicate breaching occurred (elevation was lowered).
- src.terrain.visualization.flow_diagnostics.plot_fill_depth(dem, dem_conditioned, ocean_mask, output_path, breached_dem=None)[source]
Plot depression fill depth.
Fill depth represents how much water was added to fill depressions. If breached_dem is provided, computes fill depth as (conditioned - breached), which correctly shows only the FILLING operation (not breaching). Otherwise falls back to (conditioned - original), which includes both operations.
- src.terrain.visualization.flow_diagnostics.plot_flow_direction(flow_dir, output_path)[source]
Plot D8 flow direction codes.
- src.terrain.visualization.flow_diagnostics.plot_drainage_area(drainage_area, output_path, lake_mask=None)[source]
Plot drainage area (log scale) with optional lake overlay.
- src.terrain.visualization.flow_diagnostics.plot_drainage_area_comparison(dem, dem_conditioned, ocean_mask, output_path)[source]
Create comparison plot of drainage area from raw vs conditioned DEM.
Shows three panels: - Drainage area from raw DEM (left) - Drainage area from conditioned DEM (middle) - Absolute difference between them (right)
This verifies that conditioning (breaching + filling) affects flow routing.
- src.terrain.visualization.flow_diagnostics.plot_stream_network(dem, drainage_area, output_path, lake_mask=None, percentile=95, base_dim=0.4)[source]
Plot stream network extracted from drainage area. Pixel-perfect output.
Streams are defined as cells with drainage area >= percentile threshold.
- src.terrain.visualization.flow_diagnostics.plot_stream_overlay(base_data, stream_threshold_data, stream_color_data, output_path, base_cmap='viridis', stream_cmap='plasma', percentile=95, stream_alpha=1.0, base_label='Base Metric', stream_label='Stream Metric', title='Stream Network Overlay', lake_mask=None, base_log_scale=True, stream_log_scale=True, variable_width=False, min_width=1, max_width=4, base_dim=0.5)[source]
Plot stream network colored by a metric, overlaid on a base map.
Creates visualization with streams extracted from one metric and colored by another (or the same) metric, over a full-coverage base map.
- Parameters:
base_data (np.ndarray) – Data for background map coloring (e.g., discharge_potential, elevation)
stream_threshold_data (np.ndarray) – Data for extracting streams (usually drainage_area for percentile threshold)
stream_color_data (np.ndarray) – Data for coloring stream pixels (e.g., discharge_potential, upstream_rainfall)
output_path (Path) – Output file path
base_cmap (str) – Matplotlib colormap for base map (default: viridis)
stream_cmap (str) – Matplotlib colormap for streams (default: plasma)
percentile (float) – Percentile threshold for stream extraction (default: 95 = top 5%)
stream_alpha (float) – Stream transparency: 1.0 = opaque, 0.7 = semi-transparent (default: 1.0)
base_label (str) – Colorbar label for base map
stream_label (str) – Label describing stream metric (used in title)
title (str) – Plot title
lake_mask (np.ndarray, optional) – Lake mask for overlay (integer IDs or boolean)
base_log_scale (bool) – Apply log10 to base data (default: True)
stream_log_scale (bool) – Apply log10 to stream color data (default: True)
variable_width (bool) – Scale stream line width by metric value (default: False)
min_width (int) – Minimum stream width in pixels when variable_width=True (default: 1)
max_width (int) – Maximum stream width in pixels when variable_width=True (default: 4)
base_dim (float) – Dim factor for base map (0.0 = black, 1.0 = full brightness). Default 0.5. Dimming the base makes streams more visible.
- Returns:
Path to saved raw pixel-perfect file
- Return type:
Path
- src.terrain.visualization.flow_diagnostics.plot_precipitation(precip, output_path, is_real=False)[source]
Plot precipitation data.
- src.terrain.visualization.flow_diagnostics.plot_upstream_rainfall(upstream_rainfall, output_path, lake_mask=None)[source]
Plot upstream accumulated rainfall (log scale).
- src.terrain.visualization.flow_diagnostics.plot_discharge_potential(drainage_area, upstream_rainfall, output_path, lake_mask=None, log_scale=True)[source]
Plot discharge potential (drainage × rainfall-weighted).
Combines drainage area with upstream rainfall to show where the biggest flows occur.
- src.terrain.visualization.flow_diagnostics.plot_validation_summary(output_path, dem_shape, ocean_cells, max_drainage, max_upstream, num_lakes=0, num_outlets=0, num_basins=0, basin_cells=0, cycles=0, sample_size=1000, mass_balance=100.0, drainage_violations=0, is_real_precip=False)[source]
Plot validation summary as a text table.
Parameters are all the statistics to display in the summary.
- src.terrain.visualization.flow_diagnostics.create_flow_diagnostics(dem, dem_conditioned, ocean_mask, flow_dir, drainage_area, upstream_rainfall, precip, output_dir, lake_mask=None, lake_outlets=None, lake_inlets=None, basin_mask=None, breached_dem=None, num_basins=0, is_real_precip=False, cycles=0, sample_size=1000, mass_balance=100.0, drainage_violations=0)[source]
Generate all flow diagnostic visualizations.
Creates a comprehensive set of plots for flow accumulation analysis: 1. Original DEM 2. Ocean mask 3. Water bodies (if lake_mask provided) 3b. Endorheic basins (if basin_mask provided) 4. Conditioned DEM 5. Fill depth 6. Flow direction 7. Drainage area 8. Stream network with lakes 9. Precipitation 10. Upstream rainfall 10b. Discharge potential (log scale) 10c. Discharge potential (linear scale) 11. Validation summary
- Parameters:
dem (np.ndarray) – Original DEM
dem_conditioned (np.ndarray) – Depression-filled DEM
ocean_mask (np.ndarray) – Boolean ocean mask
flow_dir (np.ndarray) – D8 flow direction codes
drainage_area (np.ndarray) – Accumulated drainage area (cells)
upstream_rainfall (np.ndarray) – Accumulated upstream rainfall
precip (np.ndarray) – Precipitation data
output_dir (Path) – Directory for output images
lake_mask (np.ndarray, optional) – Lake mask (integer IDs)
lake_outlets (np.ndarray, optional) – Boolean mask of lake outlet cells
lake_inlets (np.ndarray, optional) – Boolean mask of lake inlet cells
basin_mask (np.ndarray, optional) – Boolean mask of endorheic basins
num_basins (int, optional) – Number of endorheic basins
is_real_precip (bool, optional) – Whether precipitation is real (WorldClim) or synthetic
cycles (int, optional) – Number of flow cycles detected (validation)
sample_size (int, optional) – Sample size for cycle detection
mass_balance (float, optional) – Mass balance percentage
drainage_violations (int, optional) – Number of drainage violations
breached_dem (ndarray | None)
- Returns:
Output directory path
- Return type:
Path
- src.terrain.visualization.flow_diagnostics.vectorize_stream_network(stream_mask, simplify_tolerance=2.0)[source]
Convert stream raster to vector polylines using topology-aware path extraction.
Uses skan library for proper skeleton-to-vector conversion that preserves stream network topology and handles branch points correctly.
- Parameters:
- Returns:
List of polylines, each as (N, 2) array of [y, x] coordinates. Each polyline represents a stream segment between junctions/endpoints.
- Return type:
Example
>>> stream_mask = stream_raster > 0 >>> polylines = vectorize_stream_network(stream_mask, simplify_tolerance=2.0) >>> print(f"Extracted {len(polylines)} stream segments")
- src.terrain.visualization.flow_diagnostics.polyline_to_variable_width_polygon(polyline, widths)[source]
Convert a polyline to a variable-width polygon.
Creates a filled polygon outline by offsetting perpendicular to the polyline at each point based on the width at that point.
- src.terrain.visualization.flow_diagnostics.plot_vectorized_streams(stream_raster, base_data, output_path, base_cmap='terrain', base_label='Elevation', title='Vectorized Stream Network', simplify_tolerance=2.0, base_log_scale=False, variable_width=True, max_width=3.0)[source]
Plot vectorized stream network overlaid on base map (TEMPORARY/EXPERIMENTAL).
Creates diagnostic showing: 1. Left: Original stream raster 2. Right: Vectorized polylines overlaid on base map
- Parameters:
stream_raster (ndarray) – Stream metric values (0 = no stream)
base_data (ndarray) – Base map data (e.g., elevation, drainage)
output_path (Path) – Where to save plot
base_cmap (str) – Matplotlib colormap for base map
base_label (str) – Label for base map colorbar
title (str) – Plot title
simplify_tolerance (float) – Douglas-Peucker tolerance (pixels)
base_log_scale (bool) – Apply log scale to base data
variable_width (bool)
max_width (float)
- Returns:
Path to saved plot
- Return type:
Line Layers
Linear feature overlay creation (streams, roads, trails, power lines) from raster data. Supports variable-width lines with smooth gaussian tapering.
Linear feature layer creation for visualization.
This module provides functions to create linear feature overlay layers (streams, roads, trails, power lines, etc.) from raster data. Line layers are preprocessed rasters where: - Line pixels contain metric values (for coloring) - Non-line pixels are 0
Variable-width lines are created by expanding line pixels based on their metric values using smooth gaussian tapering and maximum_filter expansion. This produces beautiful, gradually-tapered lines matching the diagnostic plot quality.
- src.terrain.visualization.line_layers.get_metric_data(metric_choice, drainage, rainfall, discharge)[source]
Get metric data array based on user choice.
- Parameters:
metric_choice – One of “drainage”, “rainfall”, or “discharge”
drainage – Drainage area data array
rainfall – Upstream rainfall data array
discharge – Discharge potential data array
- Returns:
The selected metric data array
- src.terrain.visualization.line_layers.expand_lines_variable_width_sparse(line_mask, metric_data, max_width, min_width=1, width_gamma=1.0)[source]
Ultra-fast sparse expansion using numba JIT.
10-50x faster and 100x less memory than dense approaches for sparse networks. Uses sparse representation (only stream pixels) + numba JIT compilation.
- Parameters:
line_mask – Boolean array of initial line pixels
metric_data – Metric values (higher = wider)
max_width – Maximum width in pixels
min_width – Minimum width in pixels (default: 1)
width_gamma – Gamma correction for width scale (default: 1.0 = linear)
- Returns:
Tuple of (expanded_mask, expanded_values)
- src.terrain.visualization.line_layers.expand_lines_variable_width_fast(line_mask, metric_data, max_width, min_width=1, width_gamma=1.0)[source]
Fast variable-width expansion using distance transforms.
This is ~10-40x faster than the iterative dilation approach (O(N log N) vs O(max_width × N)). Uses distance transforms to find nearest line pixel, then applies smoothed width values.
Trade-off: In overlapping regions, uses nearest line pixel (not max value from all nearby). For most visualizations, this produces visually identical results.
- Parameters:
line_mask – Boolean array of initial line pixels
metric_data – Metric values (higher = wider)
max_width – Maximum width in pixels
min_width – Minimum width in pixels (default: 1)
width_gamma – Gamma correction for width scale (default: 1.0 = linear)
- Returns:
expanded_mask: Boolean array of expanded line pixels
expanded_values: Metric values propagated to expanded pixels
- Return type:
Tuple of (expanded_mask, expanded_values)
- src.terrain.visualization.line_layers.expand_lines_variable_width(line_mask, metric_data, max_width, min_width=1, width_gamma=1.0, fast=True, sparse=False, method=None)[source]
Expand line mask with variable width using smooth tapering.
Higher metric values → wider lines. Uses gaussian smoothing and maximum_filter for gradual, smooth tapering. This is the same algorithm used in diagnostic plots.
- Parameters:
line_mask – Boolean array of initial line pixels
metric_data – Metric values (higher = wider)
max_width – Maximum width in pixels
min_width – Minimum width in pixels (default: 1)
width_gamma – Gamma correction for width scale (default: 1.0 = linear) < 1.0 makes more streams wider, > 1.0 makes fewer streams wider
fast – If True, use O(N log N) distance-transform algorithm (default). If False, use O(max_width × N) iterative dilation (slower, max-value semantics). Deprecated: use method parameter instead.
sparse – If True, use sparse + numba JIT (10-100x faster for sparse networks). Deprecated: use method parameter instead.
method – Algorithm choice: “sparse”, “fast”, “slow”. Overrides fast/sparse parameters. - “sparse”: Numba JIT circles (10-100x faster, requires numba) - “fast”: Distance transform (13-311x faster than slow) - “slow”: Iterative dilation (best quality, max-value semantics)
- Returns:
expanded_mask: Boolean array of expanded line pixels
expanded_values: Metric values propagated to expanded pixels
- Return type:
Tuple of (expanded_mask, expanded_values)
Examples
# Expand stream network by discharge values (fast distance transform) >>> mask, values = expand_lines_variable_width(stream_mask, discharge, max_width=3)
# Expand with sparse + numba (fastest for sparse networks) >>> mask, values = expand_lines_variable_width(stream_mask, discharge, max_width=3, method=”sparse”)
# Expand with slow algorithm (best quality, max-value semantics) >>> mask, values = expand_lines_variable_width(road_mask, lane_count, max_width=5, method=”slow”)
- src.terrain.visualization.line_layers.create_line_layer(metric_data, selection_metric_data, percentile, variable_width=False, max_width=3, width_gamma=1.0, sparse=False, method=None)[source]
Create linear feature overlay layer.
Creates a preprocessed raster where line pixels have metric values and non-line pixels are 0. Optionally expands lines with variable width based on metric values.
Works for any linear features: streams, roads, trails, power lines, pipelines, etc.
- Parameters:
metric_data – Metric values to assign to line pixels (for coloring)
selection_metric_data – Metric values to threshold (for line selection)
percentile – Percentile threshold (e.g., 95.0 = top 5%)
variable_width – If True, expand lines based on metric values
max_width – Maximum expansion width in pixels (only used if variable_width=True)
width_gamma – Gamma correction for width scale (default: 1.0 = linear)
sparse – If True, use sparse + numba algorithm (deprecated, use method instead)
method – Algorithm choice: “sparse”, “fast”, or “slow” (default: “fast”)
- Returns:
line pixels have metric_data values, others are 0
- Return type:
Line layer raster
Examples
# Stream network colored by discharge >>> streams = create_line_layer( … metric_data=discharge_log, … selection_metric_data=drainage_area, … percentile=95.0 … )
# Road network colored by traffic, width by lanes >>> roads = create_line_layer( … metric_data=traffic_volume, … selection_metric_data=lane_count, … percentile=90.0, … variable_width=True, … max_width=5 … )
# Trail network colored by difficulty >>> trails = create_line_layer( … metric_data=difficulty_score, … selection_metric_data=usage_frequency, … percentile=80.0 … )
- src.terrain.visualization.line_layers.create_stream_network_layer(metric_data, selection_metric_data, percentile, variable_width=False, max_width=3, width_gamma=1.0, sparse=False, method=None)
Create linear feature overlay layer.
Creates a preprocessed raster where line pixels have metric values and non-line pixels are 0. Optionally expands lines with variable width based on metric values.
Works for any linear features: streams, roads, trails, power lines, pipelines, etc.
- Parameters:
metric_data – Metric values to assign to line pixels (for coloring)
selection_metric_data – Metric values to threshold (for line selection)
percentile – Percentile threshold (e.g., 95.0 = top 5%)
variable_width – If True, expand lines based on metric values
max_width – Maximum expansion width in pixels (only used if variable_width=True)
width_gamma – Gamma correction for width scale (default: 1.0 = linear)
sparse – If True, use sparse + numba algorithm (deprecated, use method instead)
method – Algorithm choice: “sparse”, “fast”, or “slow” (default: “fast”)
- Returns:
line pixels have metric_data values, others are 0
- Return type:
Line layer raster
Examples
# Stream network colored by discharge >>> streams = create_line_layer( … metric_data=discharge_log, … selection_metric_data=drainage_area, … percentile=95.0 … )
# Road network colored by traffic, width by lanes >>> roads = create_line_layer( … metric_data=traffic_volume, … selection_metric_data=lane_count, … percentile=90.0, … variable_width=True, … max_width=5 … )
# Trail network colored by difficulty >>> trails = create_line_layer( … metric_data=difficulty_score, … selection_metric_data=usage_frequency, … percentile=80.0 … )
Bounds Pipeline
Multi-stage coordinate transformation pipeline for bounds visualization. Handles WGS84 to UTM projection, flipping, and downsampling to mesh grid.
Transformation pipeline for bounds visualization.
Encapsulates the multi-stage transformation from WGS84 original DEM through reprojection, flipping, and downsampling to final mesh grid.
IMPORTANT: The WGS84 → UTM transformation is NON-LINEAR (Transverse Mercator projection involves trigonometric relationships). A rectangular boundary in WGS84 becomes CURVED when projected to UTM. This module uses pyproj to handle the proper projection math, not linear approximations.
This module provides reusable components for both visualization and testing.
- class src.terrain.visualization.bounds_pipeline.SimpleAffine(c, d, e, f, a, b)[source]
Bases:
objectMinimal affine transform for mapping between coordinate spaces.
- Represents the affine transform equation:
x_world = c + pixel_x * a + pixel_y * b y_world = f + pixel_x * d + pixel_y * e
Where (c, f) is the top-left corner, (a, e) are pixel scales, and (b, d) handle rotation/skew.
- __init__(c, d, e, f, a, b)[source]
Initialize affine transform coefficients.
- Parameters:
c (float) – X-coordinate of top-left corner (easting/longitude)
d (float) – Pixel spacing in x direction for y (usually 0 for aligned grid)
e (float) – Y-coordinate scale (usually negative for top-to-bottom scanning)
f (float) – Y-coordinate of top-left corner (northing/latitude)
a (float) – Pixel spacing in x direction (meters or degrees per pixel)
b (float) – Pixel spacing in y direction for x (usually 0 for aligned grid)
- class src.terrain.visualization.bounds_pipeline.TransformationPipeline(original_shape, distortion_factor, target_vertices, bbox_wgs84=None, bbox_utm=None, src_crs='EPSG:4326', dst_crs='EPSG:32617')[source]
Bases:
objectManages the transformation pipeline from WGS84 to final mesh grid.
Pipeline stages: 1. Original: WGS84 coordinates, full resolution 2. Reprojected: UTM, distorted by NON-LINEAR projection (Transverse Mercator) 3. Flipped: Same shape as reprojected, but horizontally flipped 4. Final: Downsampled mesh grid (20×49 pixels for Detroit)
IMPORTANT: The WGS84 → UTM transformation is non-linear. A rectangular boundary in WGS84 becomes curved in UTM space due to the Transverse Mercator projection’s trigonometric relationships.
- Parameters:
- __init__(original_shape, distortion_factor, target_vertices, bbox_wgs84=None, bbox_utm=None, src_crs='EPSG:4326', dst_crs='EPSG:32617')[source]
Initialize transformation pipeline.
- Parameters:
original_shape (Tuple[int, int]) – (height, width) of original DEM in WGS84
distortion_factor (float) – Height compression ratio from projection (e.g., 0.87) Used for shape estimation; actual projection uses pyproj
target_vertices (int) – Target number of vertices for final mesh
bbox_wgs84 (Tuple[float, float, float, float] | None) – Optional (min_lon, min_lat, max_lon, max_lat) in WGS84
bbox_utm (Tuple[float, float, float, float] | None) – Optional (min_easting, min_northing, max_easting, max_northing) in UTM
src_crs (str) – Source coordinate reference system (default: EPSG:4326 / WGS84)
dst_crs (str) – Destination coordinate reference system (default: EPSG:32617 / UTM 17N)
- class src.terrain.visualization.bounds_pipeline.EdgeTransformer(pipeline, use_pyproj=True)[source]
Bases:
objectTransforms edge pixels through the transformation pipeline.
Applies the sequence of transformations (reprojection, flip, downsample) to edge pixel coordinates.
IMPORTANT: The WGS84 → UTM reprojection uses pyproj for proper non-linear Transverse Mercator projection. This means rectangular edges in WGS84 become curved in UTM space.
- Parameters:
pipeline (TransformationPipeline)
use_pyproj (bool)
- __init__(pipeline, use_pyproj=True)[source]
Initialize with a transformation pipeline.
- Parameters:
pipeline (TransformationPipeline) – TransformationPipeline instance
use_pyproj (bool) – If True, use pyproj for proper non-linear projection. If False, fall back to linear approximation (for testing).
- transform_to_mesh_space(pixels, from_stage='original', clamp=True)[source]
Transform edge pixels to mesh coordinate space with FRACTIONAL precision.
Unlike transform_full_pipeline() which snaps to integer grid cells, this method preserves fractional coordinates for smooth edge extrusion.
- Parameters:
pixels (List[Tuple[int, int]]) – Edge pixel coordinates (y, x) in the source stage
from_stage (str) – Source stage (‘original’, ‘reprojected’, or ‘flipped’)
clamp (bool) – If True, clamp coordinates to [0, dim-1]. If False, return true projected coordinates which may exceed grid bounds due to non-linear projection curvature.
- Returns:
List of (y, x) coordinates in mesh space with fractional precision. If clamp=True, values range from 0.0 to (height-1) and 0.0 to (width-1). If clamp=False, values may exceed these bounds.
- Return type:
Edge Debug
Diagnostic plots for rectangle edge sampling and coordinate transformations.
Edge Extrusion Debug Visualizations
Diagnostic plots for understanding rectangle edge sampling and coordinate transformations. Helps visualize: - Original rectangle sampling in DEM pixel space - Coordinate transformations (original → geographic → reprojected → final mesh) - Boundary point distributions before/after deduplication/sorting - Edge distribution analysis (north/south/east/west)
- src.terrain.visualization.edge_debug.plot_rectangle_edge_sampling(dem_shape, edge_pixels_dense, edge_pixels_sparse, output_path)[source]
Plot rectangle edge sampling at different spacings.
Shows the difference between dense (1px spacing) and sparse (5px spacing) edge sampling in the original DEM pixel coordinate space.
- src.terrain.visualization.edge_debug.plot_edge_distribution(boundary_points, output_path, title='Edge Distribution', margin=0.05)[source]
Plot boundary points colored by which edge they’re on.
Classifies points as North (top), South (bottom), East (right), or West (left) based on their position relative to the bounding box.
- src.terrain.visualization.edge_debug.plot_deduplication_comparison(before, after, output_path)[source]
Plot before/after comparison of deduplication.
Shows how many points were removed as duplicates and where the remaining points are distributed.
- src.terrain.visualization.edge_debug.plot_sorting_effect(before, after, output_path)[source]
Plot the effect of angular sorting on boundary points.
Shows how points are reordered from shuffled state into a proper closed loop around the boundary.
- src.terrain.visualization.edge_debug.plot_transformation_pipeline(terrain, output_dir, edge_sample_spacing=1.0)[source]
Create a series of plots showing each stage of coordinate transformation.
Visualizes: 1. Original rectangle in DEM pixel space (EPSG:4326) 2. Geographic coordinates after Affine transform 3. Reprojected coordinates (if CRS changed) 4. Final mesh pixel space
- src.terrain.visualization.edge_debug.create_full_pipeline_debug_plot(terrain, output_path, edge_sample_spacing=1.0)[source]
Create a comprehensive debug visualization of the entire rectangle edge pipeline.
Single plot showing: - Original rectangle sampling - Edge distribution before/after transforms - Deduplication statistics - Final boundary distribution
See Also
Diagnostics Module - Terrain diagnostics
Flow Accumulation Module - Flow routing algorithms
Flow Pipeline Module - Flow computation pipeline