""" map_visualization.py - Interactive Map Visualization with Folium """ import folium from folium import plugins import pandas as pd from typing import List, Dict, Optional from datetime import datetime class DogMapVisualizer: def __init__(self, default_location: List[float] = [38.9637, 35.2433]): self.default_location = default_location self.default_zoom = 13 print(f"✅ Map Visualizer initialized") print(f" Default location: {default_location}") def create_map(self, dogs_data: List[Dict]) -> Optional[str]: if not dogs_data: return self._create_empty_map() center_lat = sum(dog['latitude'] for dog in dogs_data) / len(dogs_data) center_lon = sum(dog['longitude'] for dog in dogs_data) / len(dogs_data) map_obj = folium.Map( location=[center_lat, center_lon], zoom_start=self.default_zoom, tiles='OpenStreetMap' ) self.add_markers(map_obj, dogs_data) self._add_plugins(map_obj) map_html = map_obj._repr_html_() return map_html def _create_empty_map(self) -> str: map_obj = folium.Map( location=self.default_location, zoom_start=self.default_zoom, tiles='OpenStreetMap' ) folium.Marker( location=self.default_location, popup="No dogs with location data yet", icon=folium.Icon(color='gray', icon='info-sign') ).add_to(map_obj) return map_obj._repr_html_() def add_markers(self, map_obj: folium.Map, dogs: List[Dict]): for dog in dogs: lat = dog['latitude'] lon = dog['longitude'] color = self.get_marker_color(dog.get('health_score')) popup_content = self.create_popup(dog) folium.Marker( location=[lat, lon], popup=folium.Popup(popup_content, max_width=300), tooltip=dog['name'], icon=folium.Icon( color=color, icon='info-sign', prefix='glyphicon' ) ).add_to(map_obj) def create_popup(self, dog_info: Dict) -> str: dog_id = dog_info['dog_id'] name = dog_info['name'] last_seen = dog_info.get('last_seen', 'Unknown') sightings = dog_info.get('total_sightings', 0) health_score = dog_info.get('health_score') health_status = dog_info.get('health_status') html = f"""

{name}

""" if health_score is not None: html += f""" """ if health_status: status_color = { 'Healthy': '#51cf66', 'Monitor': '#ffd43b', 'Concern': '#ff6b6b' }.get(health_status, '#868e96') html += f""" """ html += """
ID: #{dog_id}
Last Seen: {last_seen}
Sightings: {sightings}
Health Score: {health_score:.1f}/10
Status: {health_status}
""" return html def get_marker_color(self, health_score: Optional[float] = None) -> str: return 'blue' def _add_plugins(self, map_obj: folium.Map): plugins.Fullscreen( position='topright', title='Expand map', title_cancel='Exit fullscreen', force_separate_button=True ).add_to(map_obj) plugins.MeasureControl( position='topleft', primary_length_unit='meters', secondary_length_unit='kilometers', primary_area_unit='sqmeters', secondary_area_unit='hectares' ).add_to(map_obj) def create_heatmap(self, dogs_data: List[Dict]) -> Optional[str]: if not dogs_data: return self._create_empty_map() center_lat = sum(dog['latitude'] for dog in dogs_data) / len(dogs_data) center_lon = sum(dog['longitude'] for dog in dogs_data) / len(dogs_data) map_obj = folium.Map( location=[center_lat, center_lon], zoom_start=self.default_zoom, tiles='OpenStreetMap' ) heat_data = [[dog['latitude'], dog['longitude']] for dog in dogs_data] plugins.HeatMap(heat_data).add_to(map_obj) self._add_plugins(map_obj) return map_obj._repr_html_() def create_cluster_map(self, dogs_data: List[Dict]) -> Optional[str]: if not dogs_data: return self._create_empty_map() center_lat = sum(dog['latitude'] for dog in dogs_data) / len(dogs_data) center_lon = sum(dog['longitude'] for dog in dogs_data) / len(dogs_data) map_obj = folium.Map( location=[center_lat, center_lon], zoom_start=self.default_zoom, tiles='OpenStreetMap' ) marker_cluster = plugins.MarkerCluster().add_to(map_obj) for dog in dogs_data: lat = dog['latitude'] lon = dog['longitude'] popup_content = self.create_popup(dog) folium.Marker( location=[lat, lon], popup=folium.Popup(popup_content, max_width=300), tooltip=dog['name'] ).add_to(marker_cluster) self._add_plugins(map_obj) return map_obj._repr_html_()