| """ |
| Alternative approach: Create a custom Folium layer that processes tiles on-the-fly |
| This ensures we get the exact same clean tiles that Tab 1 displays |
| """ |
|
|
| import folium |
| import numpy as np |
| from PIL import Image |
| import io |
| import base64 |
| from radar_processor import RadarImageProcessor |
|
|
| class ProcessingWmsTileLayer(folium.raster_layers.WmsTileLayer): |
| """Custom WMS layer that processes tiles with American colors on-the-fly.""" |
| |
| def __init__(self, *args, **kwargs): |
| |
| self.processor = kwargs.pop('processor', None) |
| super().__init__(*args, **kwargs) |
| |
| def render(self, **kwargs): |
| |
| standard_html = super().render(**kwargs) |
| |
| |
| processing_js = """ |
| <script> |
| // Intercept tile loading and process them |
| function processRadarTile(img) { |
| try { |
| var canvas = document.createElement('canvas'); |
| var ctx = canvas.getContext('2d'); |
| canvas.width = img.width; |
| canvas.height = img.height; |
| |
| ctx.drawImage(img, 0, 0); |
| var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); |
| var data = imageData.data; |
| |
| // Process pixels to American colors |
| for (var i = 0; i < data.length; i += 4) { |
| var r = data[i]; |
| var g = data[i + 1]; |
| var b = data[i + 2]; |
| var a = data[i + 3]; |
| |
| if (a > 0) { // Non-transparent pixel |
| // Simple Canadian to American color mapping |
| var newColor = mapCanadianToAmerican(r, g, b); |
| data[i] = newColor[0]; // R |
| data[i + 1] = newColor[1]; // G |
| data[i + 2] = newColor[2]; // B |
| } |
| } |
| |
| ctx.putImageData(imageData, 0, 0); |
| img.src = canvas.toDataURL(); |
| } catch (e) { |
| console.log('Tile processing failed:', e); |
| } |
| } |
| |
| function mapCanadianToAmerican(r, g, b) { |
| // Canadian cyan (0,255,255) -> American blue (30,144,255) |
| if (r < 50 && g > 200 && b > 200) return [30, 144, 255]; |
| |
| // Canadian bright green (0,200,0) -> American lime (0,255,0) |
| if (r < 50 && g > 150 && g < 250 && b < 50) return [0, 255, 0]; |
| |
| // Canadian yellow (255,255,0) -> American yellow (255,255,0) [same] |
| if (r > 200 && g > 200 && b < 100) return [255, 255, 0]; |
| |
| // Canadian orange (255,150,0) -> American dark orange (255,140,0) |
| if (r > 200 && g > 100 && g < 200 && b < 50) return [255, 140, 0]; |
| |
| // Canadian red (255,0,0) -> American red (255,0,0) [same] |
| if (r > 200 && g < 100 && b < 100) return [255, 0, 0]; |
| |
| // Canadian magenta (200,0,200) -> American magenta (255,0,255) |
| if (r > 150 && g < 100 && b > 150) return [255, 0, 255]; |
| |
| // Default: return original color |
| return [r, g, b]; |
| } |
| |
| // Hook into tile loading |
| setTimeout(function() { |
| var images = document.querySelectorAll('img[src*="geo.weather.gc.ca"]'); |
| images.forEach(function(img) { |
| if (img.complete) { |
| processRadarTile(img); |
| } else { |
| img.onload = function() { processRadarTile(img); }; |
| } |
| }); |
| }, 1000); |
| </script> |
| """ |
| |
| return standard_html + processing_js |
|
|
| def create_processing_radar_map(wms_url, layer_name, opacity=0.7): |
| """Create a map with processing WMS layer that converts colors on-the-fly.""" |
| |
| |
| m = folium.Map( |
| location=[56.1304, -106.3468], |
| zoom_start=4, |
| tiles="OpenStreetMap" |
| ) |
| |
| |
| processor = RadarImageProcessor() |
| processing_layer = ProcessingWmsTileLayer( |
| url=wms_url, |
| layers=layer_name, |
| version="1.3.0", |
| transparent=True, |
| format="image/png", |
| name="Processed Canadian Radar (American Colors)", |
| overlay=True, |
| control=True, |
| opacity=opacity, |
| processor=processor, |
| attr='<a href="https://eccc-msc.github.io/open-data/licence/readme_en/">ECCC</a> (Recolored)' |
| ) |
| |
| processing_layer.add_to(m) |
| |
| |
| folium.LayerControl().add_to(m) |
| |
| return m |