import json import folium import pandas as pd from folium import Marker from folium.plugins import MarkerCluster from jinja2 import Template regions, countries, region_tree = json.load( open("resources/country_regions.json", encoding="utf-8") ) country_centers = json.load( open("resources/country_center_coordinates.json", encoding="utf-8") ) country_mappings = json.load(open("resources/country_mappings.json", encoding="utf-8")) WORLD_GEO_URL = "https://raw.githubusercontent.com/python-visualization/folium/master/examples/data/world-countries.json" ICON_CREATE_FUNCTIOM = """ function(cluster) { var markers = cluster.getAllChildMarkers(); var sum = 0; for (var i = 0; i < markers.length; i++) { sum += markers[i].options.props.resources; } return L.divIcon({ html: '' + sum + '', className: 'marker-cluster marker-cluster-small', iconSize: new L.Point(20, 20) }); } """ class MarkerWithProps(Marker): _template = Template( """ {% macro script(this, kwargs) %} var {{this.get_name()}} = L.marker( [{{this.location[0]}}, {{this.location[1]}}], { icon: new L.Icon.Default(), {%- if this.draggable %} draggable: true, autoPan: true, {%- endif %} {%- if this.props %} props : {{ this.props }} {%- endif %} } ) .addTo({{this._parent.get_name()}}); {% endmacro %} """ ) def __init__( self, location, popup=None, tooltip=None, icon=None, draggable=False, props=None ): super(MarkerWithProps, self).__init__( location=location, popup=popup, tooltip=tooltip, icon=icon, draggable=draggable, ) self.props = json.loads(json.dumps(props)) def get_region_center(region_name): latitudes = [] longitudes = [] for name in region_tree[region_name]: if name in region_tree: region_latitudes, region_longitudes = get_region_center(name) latitudes += region_latitudes longitudes += region_longitudes elif name in country_centers or name in country_mappings["to_center"]: country_center = country_centers[ country_mappings["to_center"].get(name, name) ] latitudes += [float(country_center["latitude"])] longitudes += [float(country_center["longitude"])] return latitudes, longitudes def get_region_countries(region_name): countries = [] for name in region_tree[region_name]: if name in region_tree: countries += get_region_countries(name) else: countries += [name] return countries def make_choro_map(resource_counts, marker_thres=0): world_map = folium.Map(tiles="cartodbpositron", location=[0, 0], zoom_start=1.5) marker_cluster = MarkerCluster(icon_create_function=ICON_CREATE_FUNCTIOM) marker_cluster.add_to(world_map) for name, count in resource_counts.items(): if name in country_centers or name in country_mappings["to_center"]: country_center = country_centers[ country_mappings["to_center"].get(name, name) ] MarkerWithProps( location=[country_center["latitude"], country_center["longitude"]], popup=f"{'Region' if name in region_tree else 'Country'} : {name}
\n Resources : {count}
", props={"name": name, "resources": count}, ).add_to(marker_cluster) # put a pin at the center of the region elif name in region_tree: latitudes, longitudes = get_region_center(name) if len(latitudes) > 0: lat = sum(latitudes) / len(latitudes) lon = sum(longitudes) / len(longitudes) MarkerWithProps( location=[lat, lon], popup=f"{'Region' if name in region_tree else 'Country'} : {name}
\n Resources : {count}
", props={"name": name, "resources": count}, ).add_to(marker_cluster) # for choropleth, add counts to all countries in a region choropleth_counts = {} for loc_name in list(resource_counts.keys()): if loc_name in region_tree: for country_name in get_region_countries(loc_name): choropleth_counts[country_name] = ( choropleth_counts.get(country_name, 0) + resource_counts[loc_name] ) else: choropleth_counts[loc_name] = ( choropleth_counts.get(loc_name, 0) + resource_counts[loc_name] ) df_resource_counts = pd.DataFrame( [ (country_mappings["to_outline"].get(n, n), c) for n, c in choropleth_counts.items() ], columns=["Name", "Resources"], ) folium.Choropleth( geo_data=WORLD_GEO_URL, name="resource map", data=df_resource_counts, columns=["Name", "Resources"], key_on="feature.properties.name", fill_color="PuRd", nan_fill_color="white", ).add_to(world_map) return world_map