Spaces:
Sleeping
Sleeping
Add working hover functionality with dBZ values
Browse files- Create hover data with lat/lon coordinates mapped to dBZ values
- Sample every 10th pixel to create manageable dataset
- Add invisible CircleMarkers with tooltips showing exact dBZ values
- Convert pixel coordinates to approximate lat/lon for Canada radar bounds
- Limit to 100 hover points on map to prevent performance issues
- Add comprehensive logging for hover data creation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- app.py +28 -25
- radar_analyzer.py +56 -1
app.py
CHANGED
|
@@ -125,31 +125,34 @@ class RadarAnalysisApp:
|
|
| 125 |
wms_layer.add_to(m)
|
| 126 |
folium.LayerControl().add_to(m)
|
| 127 |
|
| 128 |
-
# Add
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
|
|
|
|
|
|
| 153 |
|
| 154 |
# Add info panel
|
| 155 |
info_html = """
|
|
|
|
| 125 |
wms_layer.add_to(m)
|
| 126 |
folium.LayerControl().add_to(m)
|
| 127 |
|
| 128 |
+
# Add dBZ hover points if analysis data is available
|
| 129 |
+
if show_analysis:
|
| 130 |
+
try:
|
| 131 |
+
# Try to get the latest analysis
|
| 132 |
+
radar_file = self.fetch_current_radar()
|
| 133 |
+
if radar_file:
|
| 134 |
+
result = self.analyzer.analyze_radar(radar_file, "radar_legendwellcropped.png")
|
| 135 |
+
hover_data = result.get('hover_data', {})
|
| 136 |
+
hover_points = hover_data.get('points', [])
|
| 137 |
+
|
| 138 |
+
print(f"Adding {len(hover_points)} hover points to map")
|
| 139 |
+
|
| 140 |
+
# Add invisible markers for hover functionality
|
| 141 |
+
for point in hover_points[:100]: # Limit to 100 points to avoid overload
|
| 142 |
+
folium.CircleMarker(
|
| 143 |
+
location=[point['lat'], point['lon']],
|
| 144 |
+
radius=3,
|
| 145 |
+
popup=f"dBZ: {point['dbz']} ({point['intensity']})",
|
| 146 |
+
tooltip=f"dBZ: {point['dbz']}",
|
| 147 |
+
color='transparent',
|
| 148 |
+
fillColor='transparent',
|
| 149 |
+
fillOpacity=0,
|
| 150 |
+
opacity=0
|
| 151 |
+
).add_to(m)
|
| 152 |
+
|
| 153 |
+
except Exception as e:
|
| 154 |
+
print(f"Error adding hover data: {e}")
|
| 155 |
+
pass
|
| 156 |
|
| 157 |
# Add info panel
|
| 158 |
info_html = """
|
radar_analyzer.py
CHANGED
|
@@ -495,19 +495,74 @@ class CanadianRadarAnalyzer:
|
|
| 495 |
annotated_bgr = cv2.cvtColor(annotated_image, cv2.COLOR_RGB2BGR)
|
| 496 |
cv2.imwrite(output_filename, annotated_bgr)
|
| 497 |
|
|
|
|
|
|
|
|
|
|
| 498 |
# Prepare results
|
| 499 |
results = {
|
| 500 |
'analysis': analysis,
|
| 501 |
'regions': regions,
|
| 502 |
'output_file': output_filename,
|
| 503 |
'input_file': radar_image_path,
|
| 504 |
-
'legend_file': legend_path
|
|
|
|
| 505 |
}
|
| 506 |
|
| 507 |
return results
|
| 508 |
|
| 509 |
except Exception as e:
|
| 510 |
raise Exception(f"Radar analysis failed: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 511 |
|
| 512 |
if __name__ == "__main__":
|
| 513 |
# Test the analyzer
|
|
|
|
| 495 |
annotated_bgr = cv2.cvtColor(annotated_image, cv2.COLOR_RGB2BGR)
|
| 496 |
cv2.imwrite(output_filename, annotated_bgr)
|
| 497 |
|
| 498 |
+
# Create hover data for map integration
|
| 499 |
+
hover_data = self.create_hover_data(analysis['precipitation_map'])
|
| 500 |
+
|
| 501 |
# Prepare results
|
| 502 |
results = {
|
| 503 |
'analysis': analysis,
|
| 504 |
'regions': regions,
|
| 505 |
'output_file': output_filename,
|
| 506 |
'input_file': radar_image_path,
|
| 507 |
+
'legend_file': legend_path,
|
| 508 |
+
'hover_data': hover_data
|
| 509 |
}
|
| 510 |
|
| 511 |
return results
|
| 512 |
|
| 513 |
except Exception as e:
|
| 514 |
raise Exception(f"Radar analysis failed: {str(e)}")
|
| 515 |
+
|
| 516 |
+
def create_hover_data(self, dbz_map: np.ndarray) -> Dict:
|
| 517 |
+
"""
|
| 518 |
+
Create simplified hover data for map integration.
|
| 519 |
+
Sample every Nth pixel to avoid huge datasets.
|
| 520 |
+
"""
|
| 521 |
+
height, width = dbz_map.shape
|
| 522 |
+
sample_rate = 10 # Sample every 10th pixel to reduce data size
|
| 523 |
+
|
| 524 |
+
hover_points = []
|
| 525 |
+
|
| 526 |
+
# Canada radar bounds (approximate)
|
| 527 |
+
lat_min, lat_max = 42.0, 84.0
|
| 528 |
+
lon_min, lon_max = -142.0, -52.0
|
| 529 |
+
|
| 530 |
+
print(f"Creating hover data from {width}x{height} dBZ map...")
|
| 531 |
+
|
| 532 |
+
for y in range(0, height, sample_rate):
|
| 533 |
+
for x in range(0, width, sample_rate):
|
| 534 |
+
dbz_value = dbz_map[y, x]
|
| 535 |
+
|
| 536 |
+
if dbz_value > 0: # Only include pixels with precipitation
|
| 537 |
+
# Convert pixel coordinates to lat/lon (approximate)
|
| 538 |
+
lat = lat_max - (y / height) * (lat_max - lat_min)
|
| 539 |
+
lon = lon_min + (x / width) * (lon_max - lon_min)
|
| 540 |
+
|
| 541 |
+
hover_points.append({
|
| 542 |
+
'lat': round(lat, 4),
|
| 543 |
+
'lon': round(lon, 4),
|
| 544 |
+
'dbz': round(dbz_value, 1),
|
| 545 |
+
'intensity': self.categorize_dbz_simple(dbz_value)
|
| 546 |
+
})
|
| 547 |
+
|
| 548 |
+
print(f"Created {len(hover_points)} hover points")
|
| 549 |
+
|
| 550 |
+
return {
|
| 551 |
+
'points': hover_points,
|
| 552 |
+
'total_points': len(hover_points),
|
| 553 |
+
'sample_rate': sample_rate
|
| 554 |
+
}
|
| 555 |
+
|
| 556 |
+
def categorize_dbz_simple(self, dbz_value: float) -> str:
|
| 557 |
+
"""Simple dBZ categorization for hover display."""
|
| 558 |
+
if dbz_value < 1.0:
|
| 559 |
+
return "Very Light"
|
| 560 |
+
elif dbz_value < 8.0:
|
| 561 |
+
return "Light-Moderate"
|
| 562 |
+
elif dbz_value < 32.0:
|
| 563 |
+
return "Heavy"
|
| 564 |
+
else:
|
| 565 |
+
return "Intense"
|
| 566 |
|
| 567 |
if __name__ == "__main__":
|
| 568 |
# Test the analyzer
|