Validating RAS Mapper Layers and Terrain Files¶
Validation Framework¶
This notebook demonstrates the ras-commander validation framework for pre-flight checks and data quality assurance. The framework uses three core classes:
- ValidationSeverity: Severity levels (INFO < WARNING < ERROR < CRITICAL)
- ValidationResult: Single validation check result
- ValidationReport: Aggregation of multiple validation results
Why Validation Matters: - Catch errors before expensive HEC-RAS execution - Ensure data quality for reliable results - Document assumptions and limitations - Enable graceful degradation when optional data missing
Reference¶
- Validation Patterns:
.claude/rules/validation/validation-patterns.md - RasMap API:
ras_commander/RasMap.py(validation methods) - FEMA Data Capture Standards
LLM Forward Principle¶
Validation creates audit trail before execution: 1. Pre-flight checks documented: All validation results logged 2. Data quality issues flagged: Warnings visible to reviewers 3. Graceful degradation: System continues with reduced functionality when appropriate
Professional Context: Validation is not a substitute for engineering judgment. Use validation to identify issues, then apply professional expertise to determine appropriate actions.
# =============================================================================
# DEVELOPMENT MODE TOGGLE
# =============================================================================
# Set USE_LOCAL_SOURCE based on your setup:
# True = Use local source code (for developers editing ras-commander)
# False = Use pip-installed package (for users)
# =============================================================================
USE_LOCAL_SOURCE = True # <-- TOGGLE THIS (set to True for local development)
# -----------------------------------------------------------------------------
if USE_LOCAL_SOURCE:
import sys
from pathlib import Path
local_path = str(Path.cwd().parent) # Parent of examples/ = repo root
if local_path not in sys.path:
sys.path.insert(0, local_path) # Insert at position 0 = highest priority
print(f"📁 LOCAL SOURCE MODE: Loading from {local_path}/ras_commander")
else:
print("📦 PIP PACKAGE MODE: Loading installed ras-commander")
# Import ras-commander (will use local or pip based on toggle above)
from ras_commander import RasExamples, RasMap, ValidationSeverity, ras
# Verify which version loaded
import ras_commander
print(f"✓ Loaded: {ras_commander.__file__}")
Understanding Severity Levels¶
ValidationSeverity Classification:
INFO - Informational (operation proceeds normally): - File metadata (size, format, creation date) - Successful validation checks - Data statistics and summaries
WARNING - Non-critical issue (operation may succeed): - Large files (performance impact) - Data extends beyond expected range - Missing optional datasets - Unusual but valid configurations
ERROR - Critical issue (operation will likely fail): - Required files not found - Invalid data format - Missing required datasets - Coordinate reference system undefined
CRITICAL - Blocking issue (cannot proceed): - File corrupted or unreadable - Incompatible file formats - Security violations
Decision Matrix:
report = RasMap.check_layer(terrain_file)
if report.is_valid:
# No ERROR or CRITICAL - safe to proceed
execute_mapping()
elif report.has_warnings:
# Warnings only - proceed with caution
logger.warning("Quality issues detected - review before use")
execute_mapping()
else:
# Errors or critical - cannot proceed
logger.error("Validation failed - fix issues before proceeding")
report.print_report(show_passed=False)
raise ValueError("Invalid terrain layer")
Validation Best Practices¶
1. Pre-Flight Checks Always validate inputs before expensive operations:
# Validate terrain before mapping
report = RasMap.check_layer(terrain_file, layer_type='terrain')
if not report.is_valid:
print("❌ Terrain validation failed - fix before mapping")
report.print_report(show_passed=False)
sys.exit(1)
# Proceed with mapping
execute_mapping(terrain_file)
2. Detailed vs Boolean Methods
- Detailed (check_*): Returns ValidationResult/ValidationReport with full diagnostics
- Boolean (is_valid_*): Returns True/False for simple checks
Use detailed when you need diagnostics, boolean for simple pass/fail.
3. Graceful Degradation
# Optional land cover layer
if RasMap.is_valid_layer(land_cover_file):
print("✓ Using land cover for Manning's n")
roughness = compute_from_land_cover(land_cover_file)
else:
print("⚠️ Land cover invalid - using default Manning's n")
roughness = default_mannings_n
4. Document Assumptions Always log validation results for audit trail:
report = RasMap.check_layer(terrain_file)
report.print_report() # Document all checks, not just failures
# Save to file for professional review
with open('validation_report.txt', 'w') as f:
f.write(str(report))
Professional Review Checklist¶
- [ ] All input layers validated before use
- [ ] Validation reports saved for review
- [ ] Warnings reviewed and dispositioned
- [ ] Errors fixed or exceptions documented
- [ ] Assumptions clearly stated
- [ ] Graceful degradation documented (if applicable)
Parameters¶
Configure these values to customize the notebook for your project.
# =============================================================================
# PARAMETERS - Edit these to customize the notebook
# =============================================================================
from pathlib import Path
# Project Configuration
PROJECT_NAME = "BaldEagleCrkMulti2D" # Example project to extract
RAS_VERSION = "7.0" # HEC-RAS version (6.3, 6.5, 6.6, etc.)
# HDF Analysis Settings
PLAN = "01" # Plan number (for HDF file path)
TIME_INDEX = -1 # Time step index (-1 = last)
PROFILE = "Max" # Profile name for steady analysis
Overview¶
This notebook demonstrates the RAS Mapper layer validation framework in ras-commander. RAS Mapper uses various geospatial layers (terrain, land cover, boundaries) to visualize and configure HEC-RAS models. Validating these layers ensures:
- Files exist and are readable
- Formats are supported (GeoJSON, Shapefile, GeoTIFF, HDF)
- Coordinate reference systems (CRS) are defined
- Raster metadata is valid
- Spatial extents cover the model domain
The validation framework provides: - Format validation - CRS validation - Raster metadata checks - Spatial extent verification - Specialized terrain and land cover validation - Comprehensive validation reports
We'll use the Muncie example project which includes RAS Mapper layers.
Extract Example Project¶
# Extract example project (contains RAS Mapper configuration)
project_path = RasExamples.extract_project(PROJECT_NAME)
print(f"\nProject extracted to: {project_path}")
# Find geospatial files in the project
from pathlib import Path
# Common geospatial file extensions
geo_extensions = ['*.tif', '*.tiff', '*.shp', '*.geojson', '*.json', '*.hdf', '*.h5']
geo_files = []
for pattern in geo_extensions:
geo_files.extend(project_path.glob(pattern))
# Also check subdirectories
geo_files.extend(project_path.glob(f"*/{pattern}"))
geo_files.extend(project_path.glob(f"*/*/{pattern}"))
print(f"Found {len(geo_files)} geospatial file(s):")
for geo_file in geo_files[:10]: # Show first 10
size_kb = geo_file.stat().st_size / 1024
print(f" - {geo_file.relative_to(project_path)} ({size_kb:.2f} KB)")
if len(geo_files) > 10:
print(f" ... and {len(geo_files) - 10} more")
3. Discover Registered RASMapper Layers¶
rasmap_df is a compact project summary: it keeps terrain, land-cover, soils, and infiltration paths in list-valued columns so a whole project fits on one row. The layer-list methods below are more discoverable for QA/QC workflows because they return one row per registered .rasmap layer, including the layer name users see in RAS Mapper, the source filename, the resolved path, and available display/selection metadata.
rasmap_files = list(project_path.glob("*.rasmap"))
rasmap_file = rasmap_files[0] if rasmap_files else None
if rasmap_file:
print(f"Reading layer catalog from: {rasmap_file.name}")
compact_rasmap_df = RasMap.parse_rasmap(rasmap_file)
terrain_layers = RasMap.list_terrain_layers(project_path)
land_classification_layers = RasMap.list_land_classification_layers(project_path)
landcover_layers = RasMap.list_landcover_layers(project_path)
soils_layers = RasMap.list_soils_layers(project_path)
infiltration_layers = RasMap.list_infiltration_layers(project_path)
print("\nCompact project summary columns:")
display(compact_rasmap_df[[
"terrain_hdf_path",
"landcover_hdf_path",
"soil_layer_path",
"infiltration_hdf_path",
]])
print("\nTerrain layers registered in RASMapper:")
display(terrain_layers[[
"name",
"filename",
"resolved_path",
"checked",
"type",
"resample_method",
"surface_on",
]])
print("\nAll land-classification layers registered in RASMapper:")
display(land_classification_layers[[
"name",
"classification_kind",
"filename",
"resolved_path",
"checked",
"selected_parameter",
]])
print("\nFiltered wrappers for workflow-specific discovery:")
print(f" land cover: {len(landcover_layers)} layer(s)")
print(f" soils: {len(soils_layers)} layer(s)")
print(f" infiltration: {len(infiltration_layers)} layer(s)")
else:
print("No .rasmap file found for this example project.")
# Look for terrain files specifically
terrain_files = [f for f in geo_files if 'terrain' in f.name.lower() or f.suffix.lower() in ['.tif', '.tiff']]
if terrain_files:
test_terrain_file = terrain_files[0]
print(f"Using terrain file: {test_terrain_file.name}")
else:
print("⚠️ No terrain files found - will use synthetic examples")
test_terrain_file = project_path / "terrain.tif" # For examples
1. Format Validation: check_layer_format()¶
Validates that layer files exist, are readable, and have supported formats.
# Example 1: Valid terrain file (GeoTIFF)
if terrain_files:
result = RasMap.check_layer_format(test_terrain_file)
print(f"File: {test_terrain_file.name}")
print(f"Result: {result}")
print(f"\nDetails:")
for key, value in result.details.items():
print(f" {key}: {value}")
# Example 2: Check various file types
file_types_to_check = {
'GeoTIFF': [f for f in geo_files if f.suffix.lower() in ['.tif', '.tiff']],
'Shapefile': [f for f in geo_files if f.suffix.lower() == '.shp'],
'GeoJSON': [f for f in geo_files if f.suffix.lower() in ['.geojson', '.json']],
'HDF': [f for f in geo_files if f.suffix.lower() in ['.hdf', '.h5']]
}
print("Format validation by file type:\n")
for file_type, files in file_types_to_check.items():
if files:
test_file = files[0]
result = RasMap.check_layer_format(test_file)
status = "✓" if result.passed else "✗"
print(f"{status} {file_type}: {test_file.name}")
print(f" {result.message}")
if result.severity == ValidationSeverity.WARNING:
print(f" ⚠️ {result.severity.value.upper()}")
print()
# Example 3: Invalid file (doesn't exist)
nonexistent_file = project_path / "missing_terrain.tif"
result = RasMap.check_layer_format(nonexistent_file)
print(f"File: {nonexistent_file.name}")
print(f"Result: {result}")
print(f"Passed: {result.passed}")
print(f"Severity: {result.severity.value}")
2. CRS Validation: check_layer_crs()¶
Validates coordinate reference system and checks compatibility with project CRS.
# Example 1: Check terrain CRS
if terrain_files:
result = RasMap.check_layer_crs(test_terrain_file)
print(f"File: {test_terrain_file.name}")
print(f"Result: {result}")
print(f"\nDetails:")
for key, value in result.details.items():
print(f" {key}: {value}")
# Example 2: Check CRS compatibility with expected projection
if terrain_files:
# First, get the CRS from the terrain file
result1 = RasMap.check_layer_crs(test_terrain_file)
if result1.passed and 'crs' in result1.details:
terrain_crs = result1.details['crs']
print(f"Terrain CRS: {terrain_crs}")
# Extract EPSG code as integer (e.g., "EPSG:2965" -> 2965)
epsg_code = None
if terrain_crs and terrain_crs.startswith("EPSG:"):
try:
epsg_code = int(terrain_crs.split(":")[1])
except (ValueError, IndexError):
pass
# Check if another file matches
if len(geo_files) > 1 and epsg_code:
other_file = [f for f in geo_files if f != test_terrain_file][0]
result2 = RasMap.check_layer_crs(other_file, expected_epsg=epsg_code)
print(f"\nComparing with: {other_file.name}")
print(f"Result: {result2}")
if result2.passed:
print(" CRS matches terrain file")
else:
print(" CRS mismatch - may need reprojection")
3. Raster Metadata: check_raster_metadata()¶
Validates raster-specific properties (dimensions, resolution, no-data values).
# Example 1: Check terrain raster metadata
if terrain_files:
results = RasMap.check_raster_metadata(test_terrain_file)
print(f"File: {test_terrain_file.name}")
print(f"Number of checks: {len(results)}")
print(f"\nResults:")
for result in results:
status = "PASS" if result.passed else "FAIL"
print(f" [{status}] {result.check_name}: {result.message}")
if result.details:
for key, value in result.details.items():
print(f" {key}: {value}")
# Example 2: Check multiple raster files
raster_files = [f for f in geo_files if f.suffix.lower() in ['.tif', '.tiff']]
if raster_files:
print(f"Raster metadata for {len(raster_files)} file(s):\n")
for raster_file in raster_files[:3]: # Check first 3
results = RasMap.check_raster_metadata(raster_file)
print(f"File: {raster_file.name}")
# Extract key metrics from results
for result in results:
if result.check_name == 'resolution_check' and result.details:
print(f" Resolution: {result.details.get('resolution', 'N/A')} meters")
elif result.check_name == 'nodata_check' and result.details:
print(f" No-data: {result.details.get('nodata_percent', 'N/A'):.1f}%")
elif result.check_name == 'extent_info' and result.details:
bounds = result.details.get('bounds')
if bounds:
print(f" Extent: {bounds[0]:.2f}, {bounds[1]:.2f} to {bounds[2]:.2f}, {bounds[3]:.2f}")
print()
4. Spatial Extent: check_spatial_extent()¶
Validates spatial coverage and checks overlap with expected domain.
# Example 1: Check terrain spatial extent
# First we need to get the layer's bounds to establish a model extent
if terrain_files:
import rasterio
# Get bounds of the terrain file
with rasterio.open(test_terrain_file) as src:
terrain_bounds = src.bounds
model_extent = (terrain_bounds.left, terrain_bounds.bottom,
terrain_bounds.right, terrain_bounds.top)
print(f"File: {test_terrain_file.name}")
print(f"Model extent (from terrain): {model_extent}")
# Now check spatial extent with that as the reference
result = RasMap.check_spatial_extent(test_terrain_file, model_extent)
print(f"\nResult: {result}")
print(f"\nDetails:")
for key, value in result.details.items():
print(f" {key}: {value}")
# Example 2: Check coverage overlap between layers
if len(geo_files) >= 2 and terrain_files:
import rasterio
# Use terrain as the model extent reference
with rasterio.open(test_terrain_file) as src:
terrain_bounds = src.bounds
model_extent = (terrain_bounds.left, terrain_bounds.bottom,
terrain_bounds.right, terrain_bounds.top)
file1 = test_terrain_file
file2 = [f for f in geo_files if f != test_terrain_file][0]
print(f"Checking overlap:\n")
print(f"Reference (model extent from terrain): {test_terrain_file.name}")
print(f" Bounds: minx={model_extent[0]:.2f}, miny={model_extent[1]:.2f}, maxx={model_extent[2]:.2f}, maxy={model_extent[3]:.2f}")
# Check if second file overlaps with model extent
result = RasMap.check_spatial_extent(file2, model_extent)
print(f"\nFile 2: {file2.name}")
print(f" {result}")
if result.passed:
print(f"\n Files have overlapping coverage")
if result.details and 'coverage_percent' in result.details:
print(f" Coverage: {result.details['coverage_percent']:.1f}%")
else:
print(f"\n Coverage mismatch detected")
5. Terrain Layer Validation: check_terrain_layer()¶
Specialized validation for terrain/elevation layers.
# Example 1: Comprehensive terrain validation
# The check_terrain_layer method validates terrain layers in a rasmap file
rasmap_files = list(project_path.glob("*.rasmap"))
if rasmap_files and terrain_files:
rasmap_file = rasmap_files[0]
print(f"RASMapper file: {rasmap_file.name}")
# Get terrain names from the rasmap
terrain_names = RasMap.get_terrain_names(rasmap_file)
if terrain_names:
layer_name = terrain_names[0]
print(f"Terrain layer found: {layer_name}")
result = RasMap.check_terrain_layer(rasmap_file, layer_name)
print(f"\nResult: {result}")
print(f"\nDetails:")
for key, value in result.details.items():
if isinstance(value, dict):
print(f" {key}:")
for sub_key, sub_val in value.items():
print(f" {sub_key}: {sub_val}")
else:
print(f" {key}: {value}")
else:
print("No terrain layers found in rasmap")
else:
print("No rasmap file found - skipping terrain layer validation")
print("\nTo validate terrain layers in a rasmap:")
print(" result = RasMap.check_terrain_layer('project.rasmap', 'Terrain_Name')")
# Example 2: Validate elevation range using rasterio directly
# Since check_terrain_layer works with rasmap, let's use rasterio for elevation stats
if terrain_files:
import rasterio
import numpy as np
with rasterio.open(test_terrain_file) as src:
data = src.read(1) # Read first band
nodata = src.nodata
# Mask nodata values
if nodata is not None:
valid_data = data[data != nodata]
else:
valid_data = data.flatten()
# Calculate statistics
min_elev = float(np.min(valid_data)) if len(valid_data) > 0 else None
max_elev = float(np.max(valid_data)) if len(valid_data) > 0 else None
mean_elev = float(np.mean(valid_data)) if len(valid_data) > 0 else None
print(f"Terrain elevation statistics for {test_terrain_file.name}:\n")
print(f" Minimum: {min_elev:.2f}" if min_elev is not None else " Minimum: N/A")
print(f" Maximum: {max_elev:.2f}" if max_elev is not None else " Maximum: N/A")
print(f" Mean: {mean_elev:.2f}" if mean_elev is not None else " Mean: N/A")
# Check for reasonable range
if min_elev is not None and max_elev is not None:
if min_elev < -500 or max_elev > 15000:
print("\n WARNING: Elevation range may be unrealistic for US terrain")
print(" Check units (should be feet or meters, not mm or other)")
else:
print("\n Elevation range appears reasonable")
6. Land Cover Validation: check_land_cover_layer()¶
Specialized validation for land cover/Manning's n layers.
# Example 1: Discover and validate land-cover layers by their RASMapper names.
# list_landcover_layers() filters the broader land-classification catalog to
# Manning's n / land-cover sidecars and exposes the layer name needed below.
if rasmap_file and not landcover_layers.empty:
for _, layer in landcover_layers.iterrows():
layer_name = layer["name"]
print(f"\nValidating land-cover layer: {layer_name}")
print(f" Sidecar HDF: {layer['resolved_path']}")
land_cover_result = RasMap.check_land_cover_layer(rasmap_file, layer_name)
print(f" Valid: {land_cover_result.passed}")
print(f" Severity: {land_cover_result.severity.value}")
print(f" Message: {land_cover_result.message}")
else:
print("No land-cover layers found in this project rasmap file.")
7. Comprehensive Layer Validation: check_layer()¶
Performs all applicable validation checks and returns a comprehensive report.
# Example 1: Comprehensive validation of a terrain layer in a rasmap file
rasmap_files = list(project_path.glob("*.rasmap"))
if rasmap_files:
rasmap_file = rasmap_files[0]
print(f"RASMapper file: {rasmap_file.name}")
# Get terrain names
terrain_names = RasMap.get_terrain_names(rasmap_file)
if terrain_names:
layer_name = terrain_names[0]
layer_type = "Terrain"
print(f"\nValidating layer: {layer_name}")
print(f"Layer type: {layer_type}")
report = RasMap.check_layer(
rasmap_path=rasmap_file,
layer_name=layer_name,
layer_type=layer_type
)
print(f"\nReport summary: {report.summary}")
print(f"Is valid: {report.is_valid}")
print(f"Has warnings: {report.has_warnings}")
# Print formatted report
print("\nDetailed Report:")
report.print_report(show_passed=True)
else:
print("No terrain layers found in rasmap file")
else:
print("No rasmap file found in project")
print("\nTo validate layers in a rasmap:")
print(" report = RasMap.check_layer('project.rasmap', 'Layer_Name', 'Terrain')")
# Example 2: Filter validation results by severity
rasmap_files = list(project_path.glob("*.rasmap"))
if rasmap_files:
rasmap_file = rasmap_files[0]
terrain_names = RasMap.get_terrain_names(rasmap_file)
if terrain_names:
layer_name = terrain_names[0]
layer_type = "Terrain"
report = RasMap.check_layer(rasmap_file, layer_name, layer_type)
# Get only errors
errors = report.get_results_by_severity(ValidationSeverity.ERROR)
print(f"Errors found: {len(errors)}")
for error in errors:
print(f" [FAIL] {error}")
# Get only warnings
warnings = report.get_results_by_severity(ValidationSeverity.WARNING)
print(f"\nWarnings found: {len(warnings)}")
for warning in warnings:
print(f" [WARN] {warning}")
# Get info messages
info = report.get_results_by_severity(ValidationSeverity.INFO)
print(f"\nInfo messages: {len(info)}")
for msg in info:
print(f" [INFO] {msg}")
else:
print("No terrain layers found")
else:
print("No rasmap file found - skipping severity filtering example")
8. Boolean Convenience: is_valid_layer()¶
Quick boolean check for layer validity.
# Example: Quick validation of terrain layers in a rasmap file
rasmap_files = list(project_path.glob("*.rasmap"))
if rasmap_files:
rasmap_file = rasmap_files[0]
terrain_names = RasMap.get_terrain_names(rasmap_file)
print(f"Quick validation of terrain layers in {rasmap_file.name}:\n")
for layer_name in terrain_names:
layer_type = "Terrain"
is_valid = RasMap.is_valid_layer(rasmap_file, layer_name, layer_type)
status = "VALID" if is_valid else "INVALID"
print(f"{status}: {layer_name} ({layer_type})")
if not terrain_names:
print("No terrain layers found in rasmap")
else:
print("No rasmap file found in project")
print("\nQuick validation example:")
print(" is_valid = RasMap.is_valid_layer('project.rasmap', 'Terrain_2024', 'Terrain')")
9. Practical Use Case: Pre-Flight Check for Model Setup¶
Validate all required RAS Mapper layers before model setup.
# Simulate pre-flight check for model setup
print("=" * 80)
print("PRE-FLIGHT CHECK: RAS Mapper Layer Validation")
print("=" * 80)
rasmap_files = list(project_path.glob("*.rasmap"))
if rasmap_files:
rasmap_file = rasmap_files[0]
print(f"\nRASMapper file: {rasmap_file.name}")
# Get terrain layers
terrain_names = RasMap.get_terrain_names(rasmap_file)
all_valid = True
for layer_name in terrain_names:
layer_type = "Terrain"
print(f"\n{'='*80}")
print(f"Checking: {layer_name} ({layer_type})")
print(f"{'='*80}")
# Quick check
is_valid = RasMap.is_valid_layer(rasmap_file, layer_name, layer_type)
if is_valid:
print(f" PASS")
else:
print(f" FAIL - running detailed diagnostics...")
# Get detailed report
report = RasMap.check_layer(rasmap_file, layer_name, layer_type)
report.print_report(show_passed=False)
all_valid = False
if not terrain_names:
print("\n No terrain layers found in rasmap")
all_valid = False
print("\n" + "=" * 80)
if all_valid:
print("PRE-FLIGHT CHECK PASSED - All terrain layers valid")
print(" Ready to configure RAS Mapper")
else:
print("PRE-FLIGHT CHECK FAILED - Fix layer issues before proceeding")
print("=" * 80)
else:
print("\nNo rasmap file found in project")
print("\nPre-flight check requires a .rasmap file with configured layers")
Geometry and Plan HDF Association Audit¶
The .rasmap file tells RAS Mapper which layers are available. Compiled geometry and plan/result HDF files also carry /Geometry attributes such as Terrain Filename, Terrain Layername, Land Cover Filename, and Infiltration Filename. RasMap.get_hdf_geometry_association() reads those attributes without mutating the model, which makes it useful for checking whether plans/results are tied to the expected terrain and classification layers.
import pandas as pd
geometry_hdfs = sorted(project_path.glob("*.g*.hdf"))
plan_hdfs = sorted(project_path.glob(f"*.p{PLAN}.hdf"))
association_rows = []
for artifact_type, hdf_candidates in [
("geometry", geometry_hdfs),
("plan/result", plan_hdfs),
]:
if not hdf_candidates:
continue
hdf_path = hdf_candidates[0]
association = RasMap.get_hdf_geometry_association(hdf_path)
association_rows.append({
"artifact_type": artifact_type,
"hdf_path": str(hdf_path),
"terrain_hdf_path": association.get("terrain_hdf_path"),
"terrain_layer_name": association.get("terrain_layer_name"),
"landcover_hdf_path": association.get("landcover_hdf_path"),
"landcover_layer_name": association.get("landcover_layer_name"),
"infiltration_hdf_path": association.get("infiltration_hdf_path"),
"infiltration_layer_name": association.get("infiltration_layer_name"),
})
if association_rows:
association_df = pd.DataFrame(association_rows)
display(association_df)
else:
print("No geometry or plan/result HDF files found to audit.")
10. Visualization: Layer Extent Comparison (Optional)¶
Visualize spatial extents of multiple layers to verify coverage.
# Optional: Visualize layer extents using matplotlib and rasterio
try:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import rasterio
raster_files = [f for f in geo_files if f.suffix.lower() in ['.tif', '.tiff']]
if raster_files:
fig, ax = plt.subplots(figsize=(10, 8))
colors = ['red', 'blue', 'green', 'orange', 'purple']
for i, raster_file in enumerate(raster_files[:5]): # Plot first 5
try:
with rasterio.open(raster_file) as src:
bounds = src.bounds
# Extract bounds
minx = bounds.left
miny = bounds.bottom
maxx = bounds.right
maxy = bounds.top
width = maxx - minx
height = maxy - miny
# Draw rectangle
rect = patches.Rectangle(
(minx, miny), width, height,
linewidth=2, edgecolor=colors[i % len(colors)],
facecolor='none', label=raster_file.name
)
ax.add_patch(rect)
except Exception as e:
print(f"Could not read {raster_file.name}: {e}")
ax.set_xlabel('Easting')
ax.set_ylabel('Northing')
ax.set_title('Spatial Extents of Geospatial Layers')
ax.legend(loc='upper right')
ax.autoscale()
ax.set_aspect('equal')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print("\nExtent visualization complete")
print(" Overlapping rectangles indicate good coverage alignment")
else:
print("No raster files found for visualization")
except ImportError as e:
print(f"Visualization dependencies not available: {e}")
Cleanup¶
# Clean up extracted project
import shutil
if project_path.parent.name == "example_projects":
shutil.rmtree(project_path.parent, ignore_errors=True)
print("✓ Cleaned up example projects")
Summary¶
This notebook demonstrated the RAS Mapper layer validation framework:
Individual Validation Methods:
- check_layer_format() - Validates file format and accessibility
- check_layer_crs() - Validates coordinate reference system
- check_raster_metadata() - Validates raster properties
- check_spatial_extent() - Validates spatial coverage
Specialized Validations:
- check_terrain_layer() - Terrain-specific validation
- check_land_cover_layer() - Land cover-specific validation
Comprehensive Validation:
- check_layer() - Runs all applicable checks, returns ValidationReport
Boolean Convenience:
- is_valid_layer() - Quick validity check
Validation Reports: - Filter by severity (INFO, WARNING, ERROR, CRITICAL) - Get failed checks - Print formatted reports
Use these tools to ensure RAS Mapper layers are valid before model setup and execution!