Search code examples
pythonpandasgeojsonfoliumchoropleth

Making choropleth map from dataframe using folium


I'm trying to make a choropleth map using pandas to read csv data. I followed a tutorial online, but didn't get my code to work.

Tutorial link: https://towardsdatascience.com/choropleth-maps-with-folium-1a5b8bcdd392. Here is the code i'm trying to get to work:

# CHOLOPLETH MAP
import json
kunnat_geo = r'kunnat.geojson'
coords = pd.read_csv('taulu2.csv')

map_cholo = folium.Map(location=[65,26], zoom_start=4, tiles='stamenwatercolor')
map_cholo.choropleth(
    geo_data=kunnat_geo,
    data=coords,
    columns=['ALUE', 'MIELENTERVEYDEN KUNTOUTUSKOTIEN ASIAKKAAT VUONNA 2018'],
    key_on='features.properties.Kunta',
    fill_color='YlGnBu', 
    fill_opacity=1, 
    line_opacity=1,
    legend_name='MIELENTERVEYDEN KUNTOUTUSKOTIEN ASIAKKAAT VUONNA 2018',
    smooth_factor=0)

map_cholo

However it gives me an attribute error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-74-026c8c7bfd66> in <module>
     14     line_opacity=1,
     15     legend_name='MIELENTERVEYDEN KUNTOUTUSKOTIEN ASIAKKAAT VUONNA 2018',
---> 16     smooth_factor=0)
     17 
     18 map_cholo

D:\Anaconda3\lib\site-packages\folium\folium.py in choropleth(self, *args, **kwargs)
    416         )
    417         from folium.features import Choropleth
--> 418         self.add_child(Choropleth(*args, **kwargs))
    419 
    420     def keep_in_front(self, *args):

D:\Anaconda3\lib\site-packages\folium\features.py in __init__(self, geo_data, data, columns, key_on, bins, fill_color, nan_fill_color, fill_opacity, nan_fill_opacity, line_color, line_weight, line_opacity, name, legend_name, overlay, control, show, topojson, smooth_factor, highlight, **kwargs)
   1249                 style_function=style_function,
   1250                 smooth_factor=smooth_factor,
-> 1251                 highlight_function=highlight_function if highlight else None)
   1252 
   1253         self.add_child(self.geojson)

D:\Anaconda3\lib\site-packages\folium\features.py in __init__(self, data, style_function, highlight_function, name, overlay, control, show, smooth_factor, tooltip, embed, popup)
    456             self.convert_to_feature_collection()
    457             if self.style:
--> 458                 self._validate_function(style_function, 'style_function')
    459                 self.style_function = style_function
    460                 self.style_map = {}

D:\Anaconda3\lib\site-packages\folium\features.py in _validate_function(self, func, name)
    521         """
    522         test_feature = self.data['features'][0]
--> 523         if not callable(func) or not isinstance(func(test_feature), dict):
    524             raise ValueError('{} should be a function that accepts items from '
    525                              'data[\'features\'] and returns a dictionary.'

D:\Anaconda3\lib\site-packages\folium\features.py in style_function(x)
   1223 
   1224         def style_function(x):
-> 1225             color, opacity = color_scale_fun(x)
   1226             return {
   1227                 'weight': line_weight,

D:\Anaconda3\lib\site-packages\folium\features.py in color_scale_fun(x)
   1204 
   1205             def color_scale_fun(x):
-> 1206                 key_of_x = get_by_key(x, key_on)
   1207                 if key_of_x is None:
   1208                     raise ValueError("key_on `{!r}` not found in GeoJSON.".format(key_on))

D:\Anaconda3\lib\site-packages\folium\features.py in get_by_key(obj, key)
   1201                 return (obj.get(key, None) if len(key.split('.')) <= 1 else
   1202                         get_by_key(obj.get(key.split('.')[0], None),
-> 1203                                    '.'.join(key.split('.')[1:])))
   1204 
   1205             def color_scale_fun(x):

D:\Anaconda3\lib\site-packages\folium\features.py in get_by_key(obj, key)
   1200             def get_by_key(obj, key):
   1201                 return (obj.get(key, None) if len(key.split('.')) <= 1 else
-> 1202                         get_by_key(obj.get(key.split('.')[0], None),
   1203                                    '.'.join(key.split('.')[1:])))
   1204 

AttributeError: 'NoneType' object has no attribute 'get'

Here is the geojson file im using: https://raw.githubusercontent.com/varmais/maakunnat/master/kunnat.geojson

And the data: https://pastebin.com/SdEXDM89


Solution

  • The geojson you are using contains multiple flaws. Just an example, look at

    {"id":49,"type":"Feature","geometry":{"coordinates":[[[[25.134789950981,65.0613390595066],[24.9509796014637,65.1411214235741],[24.1149334366251,65.1739425977789],[24.1374948169974,65.2416484128856],[24.6071512739822,65.211492673253],[25.2249108920834,65.2366422852267],[25.319454962569,65.2626286706296],[25.5524286749097,65.2529182323504],[25.6623616596278,65.260748036272],[25.7723806903971,65.2919894627541],[25.9132907485861,65.2931966157892],[26.0266782370841,65.2703735338041],[25.993210256336,65.1914324603082],[25.736352838218,65.2201254797071],[25.5637124399186,65.1919505955019],[25.635197316715,65.1390540421563],[25.6086182968484,65.0816350751541],[25.3775958184099,65.1070832092577],[25.2892903033333,65.0817828240486],[25.134789950981,65.0613390595066]]]],"type":"MultiPolygon"},"properties":{"nationalCode":84,"Country":"FI","name_fi":"Haukipudas","name_se":"Haukipudas"}}
    

    It does not have Kunta in properties. This makes your geojson bad-formed. I suggest you to replace that geojson, or edit it as the very last resort.