import gradio as gr import folium import requests import json import numpy as np from PIL import Image import base64 import io from radar_analyzer import CanadianRadarAnalyzer import cv2 class RadarAnalysisApp: def __init__(self): # Always use Canadian radar data source self.wms_url = "https://geo.weather.gc.ca/geomet" self.analyzer = CanadianRadarAnalyzer() # Color display mode self.american_colors = False # False = Canadian colors, True = American colors # Extended North America bounds for map centering - covers Alaska to southeastern US self.canada_bounds = { "center": [52.5, -105.0], "southwest": [20, -170], "northeast": [85, -40] } def toggle_color_scheme(self, use_american_colors: bool): """Toggle between Canadian and American color schemes for the same radar data.""" self.american_colors = use_american_colors color_scheme = "American" if use_american_colors else "Canadian" print(f"🎨 Switched to {color_scheme} color scheme") return f"🎨 Using {color_scheme} Colors" def fetch_current_radar(self): """Fetch the most recent Canadian radar image.""" try: url = f"{self.wms_url}?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&LAYERS=RADAR_1KM_RRAI&STYLES=&CRS=EPSG:4326&BBOX=20,-170,85,-40&WIDTH=1200&HEIGHT=800&FORMAT=image/png" response = requests.get(url, timeout=30) response.raise_for_status() # Save the radar image with open('current_radar_fetch.png', 'wb') as f: f.write(response.content) return 'current_radar_fetch.png' except Exception as e: print(f"Error fetching radar: {e}") return None def analyze_current_radar(self): """Fetch and analyze the current radar image with optional color conversion.""" radar_file = self.fetch_current_radar() if not radar_file: return None, "Failed to fetch radar data" try: # Analyze the radar image using Canadian legend result = self.analyzer.analyze_radar(radar_file, "radar_legendwellcropped.png") # Apply American color conversion if requested if self.american_colors: print("🔄 Converting to American color scheme...") original_image = cv2.imread(radar_file) if original_image is not None: original_rgb = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB) converted_image = self.analyzer.convert_colors_to_american_scale(original_rgb) # Save converted image converted_file = radar_file.replace('.png', '_american_colors.png') converted_bgr = cv2.cvtColor(converted_image, cv2.COLOR_RGB2BGR) cv2.imwrite(converted_file, converted_bgr) # Update the result to point to converted image result['output_file'] = converted_file print(f"✅ Saved American color version: {converted_file}") # Debug: Print what we actually got print("Analysis result keys:", result.keys()) print("Analysis keys:", result['analysis'].keys()) # Create analysis summary with safe access analysis = result['analysis'] analysis_text = f""" **Radar Analysis Results:** - **Precipitation Pixels:** {analysis.get('precipitation_pixels', 0):,} - **Total Image Pixels:** {analysis.get('total_pixels', 0):,} - **Coverage:** {analysis.get('precipitation_percentage', 0):.2f}% - **Regions Found:** {len(result.get('regions', []))} **Detected Precipitation Levels:** """ # Add intensity breakdown intensity_levels = analysis.get('intensity_levels', analysis.get('pixel_statistics', {})) for intensity, count in intensity_levels.items(): if count > 0: analysis_text += f"\n- {intensity}: {count:,} pixels" # Add dBZ scale reference analysis_text += f""" **dBZ Scale Reference:** - 0.1-1.0 dBZ: Very light precipitation (blue) - 1.0-8.0 dBZ: Light to moderate (green-yellow) - 8.0-32.0 dBZ: Heavy precipitation (orange-red) - 32.0+ dBZ: Intense precipitation (red-purple) *Hover over radar pixels to see precise dBZ values* """ return result['output_file'], analysis_text except Exception as e: return None, f"Analysis failed: {str(e)}" def create_radar_map_with_analysis(self, show_analysis=True): """Create a Folium map with radar overlay and optional analysis.""" try: # Create base map m = folium.Map( location=self.canada_bounds["center"], zoom_start=4, tiles="OpenStreetMap" ) if show_analysis: # Analyze current radar annotated_file, analysis_text = self.analyze_current_radar() if annotated_file: # Add the analyzed radar as an overlay # Note: For this demo, we'll add the WMS layer # In a full implementation, you'd convert the analyzed image to map overlay pass # Add live radar overlay with hover functionality color_scheme = "American" if self.american_colors else "Canadian" wms_layer = folium.raster_layers.WmsTileLayer( url=self.wms_url, layers="RADAR_1KM_RRAI", version="1.3.0", transparent=True, format="image/png", name=f"🇨🇦 Canadian Radar ({color_scheme} Colors)", overlay=True, control=True, opacity=0.7, attr='ECCC' ) wms_layer.add_to(m) folium.LayerControl().add_to(m) # Add dBZ hover points if analysis data is available if show_analysis: try: # Try to get the latest analysis radar_file = self.fetch_current_radar() if radar_file: result = self.analyzer.analyze_radar(radar_file, "radar_legendwellcropped.png") hover_data = result.get('hover_data', {}) hover_points = hover_data.get('points', []) print(f"🚀 Adding {len(hover_points)} MAXIMUM RESOLUTION hover points to map") print(f"🎯 Coverage: ENTIRE radar image, EVERY precipitation pixel") # Add ALL precipitation pixels as hover points for MAXIMUM resolution # NO limits, NO caps, COMPLETE coverage for i, point in enumerate(hover_points): if i % 1000 == 0 and i > 0: progress = (i / len(hover_points)) * 100 print(f" 📍 Added {i:,}/{len(hover_points):,} hover points ({progress:.1f}%)") # Create ultra-precise markers for maximum zoom resolution folium.CircleMarker( location=[point['lat'], point['lon']], radius=0.8, # Ultra-small for high-resolution detail popup=folium.Popup( f"""
Error: {str(e)}