Spaces:
Running
Running
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: '<b>' + sum + '</b>', | |
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}<br> \n Resources : {count} <br>", | |
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}<br> \n Resources : {count} <br>", | |
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 | |