Spaces:
Sleeping
Sleeping
Implement maximum resolution hover and region detection
Browse files- Create hover points for EVERY precipitation pixel (not sampled)
- Higher precision lat/lon coordinates (6 decimal places)
- Visible red markers with detailed popup information
- Individual regions for each unique RGB color/dBZ combination
- Pixel-level precision for zoom-in functionality
- Include pixel coordinates, exact dBZ values, and intensity levels
- Set min_region_size to 1 for maximum granularity
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- app.py +26 -10
- radar_analyzer.py +39 -22
app.py
CHANGED
|
@@ -135,20 +135,36 @@ class RadarAnalysisApp:
|
|
| 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
|
| 141 |
-
for point in hover_points
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
folium.CircleMarker(
|
| 143 |
location=[point['lat'], point['lon']],
|
| 144 |
-
radius=
|
| 145 |
-
popup=
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
).add_to(m)
|
|
|
|
|
|
|
| 152 |
|
| 153 |
except Exception as e:
|
| 154 |
print(f"Error adding hover data: {e}")
|
|
|
|
| 135 |
hover_data = result.get('hover_data', {})
|
| 136 |
hover_points = hover_data.get('points', [])
|
| 137 |
|
| 138 |
+
print(f"Adding {len(hover_points)} HIGH-RESOLUTION hover points to map")
|
| 139 |
|
| 140 |
+
# Add ALL precipitation pixels as hover points for maximum resolution
|
| 141 |
+
for i, point in enumerate(hover_points):
|
| 142 |
+
if i % 500 == 0 and i > 0:
|
| 143 |
+
print(f" Added {i}/{len(hover_points)} hover points...")
|
| 144 |
+
|
| 145 |
+
# Create very small, invisible markers that work at all zoom levels
|
| 146 |
folium.CircleMarker(
|
| 147 |
location=[point['lat'], point['lon']],
|
| 148 |
+
radius=1, # Very small radius
|
| 149 |
+
popup=folium.Popup(
|
| 150 |
+
f"""
|
| 151 |
+
<b>dBZ: {point['dbz']}</b><br>
|
| 152 |
+
Intensity: {point['intensity']}<br>
|
| 153 |
+
Pixel: ({point['pixel_x']}, {point['pixel_y']})<br>
|
| 154 |
+
Lat: {point['lat']}<br>
|
| 155 |
+
Lon: {point['lon']}
|
| 156 |
+
""",
|
| 157 |
+
max_width=200
|
| 158 |
+
),
|
| 159 |
+
tooltip=f"dBZ: {point['dbz']} ({point['intensity']})",
|
| 160 |
+
color='red',
|
| 161 |
+
fillColor='red',
|
| 162 |
+
fillOpacity=0.3,
|
| 163 |
+
opacity=0.5,
|
| 164 |
+
weight=1
|
| 165 |
).add_to(m)
|
| 166 |
+
|
| 167 |
+
print(f"Added {len(hover_points)} hover points for maximum zoom resolution")
|
| 168 |
|
| 169 |
except Exception as e:
|
| 170 |
print(f"Error adding hover data: {e}")
|
radar_analyzer.py
CHANGED
|
@@ -421,7 +421,7 @@ class CanadianRadarAnalyzer:
|
|
| 421 |
'intensity_levels': pixel_stats
|
| 422 |
}
|
| 423 |
|
| 424 |
-
def find_color_regions(self, radar_image: np.ndarray, min_region_size: int =
|
| 425 |
"""
|
| 426 |
Find connected regions of the same precipitation intensity.
|
| 427 |
|
|
@@ -437,10 +437,10 @@ class CanadianRadarAnalyzer:
|
|
| 437 |
regions = []
|
| 438 |
|
| 439 |
if fast_mode:
|
| 440 |
-
print("Using
|
| 441 |
-
#
|
| 442 |
from collections import defaultdict
|
| 443 |
-
|
| 444 |
|
| 445 |
for y in range(height):
|
| 446 |
for x in range(width):
|
|
@@ -450,16 +450,27 @@ class CanadianRadarAnalyzer:
|
|
| 450 |
(pixel_rgb[0] > 240 and pixel_rgb[1] > 240 and pixel_rgb[2] > 240)):
|
| 451 |
match = self.find_precipitation_value(pixel_rgb)
|
| 452 |
if match:
|
| 453 |
-
|
|
|
|
| 454 |
|
| 455 |
-
|
| 456 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 457 |
ys = [p[0] for p in pixels]
|
| 458 |
xs = [p[1] for p in pixels]
|
| 459 |
|
|
|
|
|
|
|
|
|
|
| 460 |
regions.append({
|
| 461 |
'pixels': pixels,
|
| 462 |
-
'precipitation': match,
|
|
|
|
|
|
|
| 463 |
'bbox': {
|
| 464 |
'min_y': min(ys),
|
| 465 |
'max_y': max(ys),
|
|
@@ -470,7 +481,7 @@ class CanadianRadarAnalyzer:
|
|
| 470 |
'center': (int(np.mean(ys)), int(np.mean(xs)))
|
| 471 |
})
|
| 472 |
|
| 473 |
-
print(f"
|
| 474 |
return regions
|
| 475 |
|
| 476 |
print(f"Starting DETAILED region analysis on {width}x{height} image...")
|
|
@@ -689,11 +700,10 @@ class CanadianRadarAnalyzer:
|
|
| 689 |
|
| 690 |
def create_hover_data(self, dbz_map: np.ndarray) -> Dict:
|
| 691 |
"""
|
| 692 |
-
Create
|
| 693 |
-
|
| 694 |
"""
|
| 695 |
height, width = dbz_map.shape
|
| 696 |
-
sample_rate = 10 # Sample every 10th pixel to reduce data size
|
| 697 |
|
| 698 |
hover_points = []
|
| 699 |
|
|
@@ -701,30 +711,37 @@ class CanadianRadarAnalyzer:
|
|
| 701 |
lat_min, lat_max = 42.0, 84.0
|
| 702 |
lon_min, lon_max = -142.0, -52.0
|
| 703 |
|
| 704 |
-
print(f"Creating hover data from {width}x{height} dBZ map...")
|
| 705 |
|
| 706 |
-
|
| 707 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
dbz_value = dbz_map[y, x]
|
| 709 |
|
| 710 |
if dbz_value > 0: # Only include pixels with precipitation
|
| 711 |
-
# Convert pixel coordinates to lat/lon (
|
| 712 |
lat = lat_max - (y / height) * (lat_max - lat_min)
|
| 713 |
lon = lon_min + (x / width) * (lon_max - lon_min)
|
| 714 |
|
| 715 |
hover_points.append({
|
| 716 |
-
'lat': round(lat,
|
| 717 |
-
'lon': round(lon,
|
| 718 |
-
'dbz': round(dbz_value,
|
| 719 |
-
'intensity': self.categorize_dbz_simple(dbz_value)
|
|
|
|
|
|
|
| 720 |
})
|
| 721 |
|
| 722 |
-
print(f"Created {len(hover_points)} hover points")
|
| 723 |
|
| 724 |
return {
|
| 725 |
'points': hover_points,
|
| 726 |
'total_points': len(hover_points),
|
| 727 |
-
'
|
| 728 |
}
|
| 729 |
|
| 730 |
def categorize_dbz_simple(self, dbz_value: float) -> str:
|
|
|
|
| 421 |
'intensity_levels': pixel_stats
|
| 422 |
}
|
| 423 |
|
| 424 |
+
def find_color_regions(self, radar_image: np.ndarray, min_region_size: int = 1, fast_mode: bool = False) -> List[Dict]:
|
| 425 |
"""
|
| 426 |
Find connected regions of the same precipitation intensity.
|
| 427 |
|
|
|
|
| 437 |
regions = []
|
| 438 |
|
| 439 |
if fast_mode:
|
| 440 |
+
print("Using HIGH-RESOLUTION region mode - separate regions per unique color")
|
| 441 |
+
# Create individual regions for each unique color (highest resolution)
|
| 442 |
from collections import defaultdict
|
| 443 |
+
color_groups = defaultdict(list)
|
| 444 |
|
| 445 |
for y in range(height):
|
| 446 |
for x in range(width):
|
|
|
|
| 450 |
(pixel_rgb[0] > 240 and pixel_rgb[1] > 240 and pixel_rgb[2] > 240)):
|
| 451 |
match = self.find_precipitation_value(pixel_rgb)
|
| 452 |
if match:
|
| 453 |
+
# Group by exact RGB color for maximum resolution
|
| 454 |
+
color_groups[pixel_rgb].append((y, x, match))
|
| 455 |
|
| 456 |
+
print(f"Found {len(color_groups)} unique precipitation colors")
|
| 457 |
+
|
| 458 |
+
for color_rgb, pixel_data in color_groups.items():
|
| 459 |
+
if len(pixel_data) >= min_region_size:
|
| 460 |
+
pixels = [(p[0], p[1]) for p in pixel_data]
|
| 461 |
+
match = pixel_data[0][2] # Get precipitation match
|
| 462 |
+
|
| 463 |
ys = [p[0] for p in pixels]
|
| 464 |
xs = [p[1] for p in pixels]
|
| 465 |
|
| 466 |
+
# Calculate precise dBZ value for this exact color
|
| 467 |
+
dbz_value = (match.min_value + match.max_value) / 2
|
| 468 |
+
|
| 469 |
regions.append({
|
| 470 |
'pixels': pixels,
|
| 471 |
+
'precipitation': match,
|
| 472 |
+
'exact_color': color_rgb,
|
| 473 |
+
'dbz_value': dbz_value,
|
| 474 |
'bbox': {
|
| 475 |
'min_y': min(ys),
|
| 476 |
'max_y': max(ys),
|
|
|
|
| 481 |
'center': (int(np.mean(ys)), int(np.mean(xs)))
|
| 482 |
})
|
| 483 |
|
| 484 |
+
print(f"High-resolution mode: Created {len(regions)} color-specific regions")
|
| 485 |
return regions
|
| 486 |
|
| 487 |
print(f"Starting DETAILED region analysis on {width}x{height} image...")
|
|
|
|
| 700 |
|
| 701 |
def create_hover_data(self, dbz_map: np.ndarray) -> Dict:
|
| 702 |
"""
|
| 703 |
+
Create high-resolution hover data for map integration.
|
| 704 |
+
Include every precipitation pixel for maximum zoom resolution.
|
| 705 |
"""
|
| 706 |
height, width = dbz_map.shape
|
|
|
|
| 707 |
|
| 708 |
hover_points = []
|
| 709 |
|
|
|
|
| 711 |
lat_min, lat_max = 42.0, 84.0
|
| 712 |
lon_min, lon_max = -142.0, -52.0
|
| 713 |
|
| 714 |
+
print(f"Creating HIGH-RESOLUTION hover data from {width}x{height} dBZ map...")
|
| 715 |
|
| 716 |
+
# Include EVERY precipitation pixel for maximum resolution
|
| 717 |
+
for y in range(height):
|
| 718 |
+
if y % 100 == 0: # Progress logging
|
| 719 |
+
progress = (y / height) * 100
|
| 720 |
+
print(f" Hover data progress: {progress:.1f}%")
|
| 721 |
+
|
| 722 |
+
for x in range(width):
|
| 723 |
dbz_value = dbz_map[y, x]
|
| 724 |
|
| 725 |
if dbz_value > 0: # Only include pixels with precipitation
|
| 726 |
+
# Convert pixel coordinates to lat/lon (precise)
|
| 727 |
lat = lat_max - (y / height) * (lat_max - lat_min)
|
| 728 |
lon = lon_min + (x / width) * (lon_max - lon_min)
|
| 729 |
|
| 730 |
hover_points.append({
|
| 731 |
+
'lat': round(lat, 6), # Higher precision for zooming
|
| 732 |
+
'lon': round(lon, 6),
|
| 733 |
+
'dbz': round(dbz_value, 2), # Higher precision
|
| 734 |
+
'intensity': self.categorize_dbz_simple(dbz_value),
|
| 735 |
+
'pixel_x': x,
|
| 736 |
+
'pixel_y': y
|
| 737 |
})
|
| 738 |
|
| 739 |
+
print(f"Created {len(hover_points)} high-resolution hover points")
|
| 740 |
|
| 741 |
return {
|
| 742 |
'points': hover_points,
|
| 743 |
'total_points': len(hover_points),
|
| 744 |
+
'resolution': 'full' # Every pixel included
|
| 745 |
}
|
| 746 |
|
| 747 |
def categorize_dbz_simple(self, dbz_value: float) -> str:
|