Folium: Choropleth + GeoJson = 'NoneType' object has no attribute 'get'

Created on 3 May 2016  路  7Comments  路  Source: python-visualization/folium

GeoJSON Format is like below :

{
  "type":"FeatureCollection",
  "features":[
        {
          "type":"Feature",
          "geometry":
          {
              "type":"Polygon",
              "coordinates":[[[-1.6704591323124895,49.62681486270549], .....
              {
                  "insee":"50173",
                  "nom":"脡queurdreville-Hainneville",
                  "wikipedia":"fr:脡queurdreville-Hainneville",
                  "surf_m2":12940306}},

Pandas DataFrame :

postal_count.head(5)
Out[95]: 
  Code_commune_INSEE  count
0              75120    723
1              75115    698
2              75112    671
3              75118    627
4              75111    622

Here is my code (snippet from this notebook)

map_france = folium.Map(location=[47.000000, 2.000000], zoom_start=6)

map_france.choropleth(
                    geo_str=open(path + 'simplified_communes100m.json').read(),
                    data=postal_count,
                    columns=['Code_commune_INSEE', 'count'],
                    key_on='feature.geometry.properties.insee',
                    fill_color='YlGn',
)
map_france.save(table_path+ '/choro_test1.html')

I'm stilling getting this error again and again :

AttributeError                            Traceback (most recent call last)
<ipython-input-83-ea0fd2c1c207> in <module>()
      8                     fill_color='YlGn',
      9 )
---> 10 map_france.save('/media/flo/Stockage/Data/MesAides/map/choro_test1.html')

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/element.py in save(self, outfile, close_file, **kwargs)
    151 
    152         root = self.get_root()
--> 153         html = root.render(**kwargs)
    154         fid.write(html.encode('utf8'))
    155         if close_file:

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/element.py in render(self, **kwargs)
    357         """Renders the HTML representation of the element."""
    358         for name, child in self._children.items():
--> 359             child.render(**kwargs)
    360         return self._template.render(this=self, kwargs=kwargs)
    361 

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/element.py in render(self, **kwargs)
    665 
    666         for name, element in self._children.items():
--> 667             element.render(**kwargs)

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/element.py in render(self, **kwargs)
    661         script = self._template.module.__dict__.get('script', None)
    662         if script is not None:
--> 663             figure.script.add_children(Element(script(self, kwargs)),
    664                                        name=self.get_name())
    665 

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/jinja2/runtime.py in __call__(self, *args, **kwargs)
    434             raise TypeError('macro %r takes not more than %d argument(s)' %
    435                             (self.name, len(self.arguments)))
--> 436         return self._func(*arguments)
    437 
    438     def __repr__(self):

<template> in macro(l_this, l_kwargs)

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/jinja2/runtime.py in call(_Context__self, _Context__obj, *args, **kwargs)
    194                 args = (__self.environment,) + args
    195         try:
--> 196             return __obj(*args, **kwargs)
    197         except StopIteration:
    198             return __self.environment.undefined('value was undefined because '

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/features.py in style_data(self)
    352 
    353         for feature in self.data['features']:
--> 354             feature.setdefault('properties', {}).setdefault('style', {}).update(self.style_function(feature))  # noqa
    355         return json.dumps(self.data, sort_keys=True)
    356 

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/folium.py in style_function(x)
    671                 "color": line_color,
    672                 "fillOpacity": fill_opacity,
--> 673                 "fillColor": color_scale_fun(x)
    674             }
    675 

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/folium.py in color_scale_fun(x)
    659             def color_scale_fun(x):
    660                 return color_range[len(
--> 661                     [u for u in color_domain if
    662                      u <= color_data[get_by_key(x, key_on)]])]
    663         else:

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/folium.py in <listcomp>(.0)
    660                 return color_range[len(
    661                     [u for u in color_domain if
--> 662                      u <= color_data[get_by_key(x, key_on)]])]
    663         else:
    664             def color_scale_fun(x):

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/folium.py in get_by_key(obj, key)
    655                 return (obj.get(key, None) if len(key.split('.')) <= 1 else
    656                         get_by_key(obj.get(key.split('.')[0], None),
--> 657                                    '.'.join(key.split('.')[1:])))
    658 
    659             def color_scale_fun(x):

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/folium.py in get_by_key(obj, key)
    655                 return (obj.get(key, None) if len(key.split('.')) <= 1 else
    656                         get_by_key(obj.get(key.split('.')[0], None),
--> 657                                    '.'.join(key.split('.')[1:])))
    658 
    659             def color_scale_fun(x):

/home/flo/.virtualenvs/mesaides/lib/python3.4/site-packages/folium/folium.py in get_by_key(obj, key)
    653 
    654             def get_by_key(obj, key):
--> 655                 return (obj.get(key, None) if len(key.split('.')) <= 1 else
    656                         get_by_key(obj.get(key.split('.')[0], None),
    657                                    '.'.join(key.split('.')[1:])))

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

I tried playing with key_on='feature.geometry.properties.insee' without any success.

Most helpful comment

There were 2 problems :

1 - The correct access to 'insee' parameters is : key_on='feature.properties.insee'

2- My DataFrame did not contain all the available 'insee' keys, so it was raising a KeyError

After these 2 problems solved, it worked like a charm!

All 7 comments

There were 2 problems :

1 - The correct access to 'insee' parameters is : key_on='feature.properties.insee'

2- My DataFrame did not contain all the available 'insee' keys, so it was raising a KeyError

After these 2 problems solved, it worked like a charm!

Safe to close then :wink:

Hi,
sorry to open again this issue, but I have a similar error and can't figure out how to point to the right key_on attribute.

My geojson:

{
    "type":"Topology",
    "arcs":[...],
    "transform":{...},    
    "objects":
        "Com01012018_g_WGS84":{
            "type":"GeometryCollection",
            "geometries": [
                {
                    "arcs":[...],
                    "type":"Polygon",
                    "properties": {
                        "COMUNE": "Borgo Vercelli",
                        "PRO_COM": 2017,
                        ...
                    }
                },
                {...},
            ]
        }
}

My pandas df:

id     comune                  a11y-score   
0   Aquila d'Arroscia           65.17
1   Castel del Rio                 68.75
2   Castellaneta                 71.95
3   Castelvetrano                 77.27
4   Montescudo-Monte Colombo    59.65

I want to set the key on "COMUNE" and I am able to loop through geojson very easily:

with open('italy-comuni.json', encoding='utf-8') as json_file:
    data = json.load(json_file)
    obj = data['objects']
    for righe in obj["Com01012018_g_WGS84"]['geometries']:
        print(righe['properties']['COMUNE']) #print the name of the City

As suggested by @FloSugar I checked if both this json and my imported dataframe has the same "comune" value (to avoid raising KeyError ) and alla the values in a11y-score are filled (float values from 0 to 100).

Here my Leaflet code:

m = folium.Map(location=[42.833333, 12.833333],zoom_start=6,tiles="Mapbox Bright")
m.choropleth(
 geo_data=state_geo,
 name='choropleth',
 data=italia_df,
 columns=['comune', 'a11y-score'],
 key_on='object.geometry.properties.COMUNE',
 fill_color='YlOrRd',
 fill_opacity=0.7,
 line_opacity=0.2,
 legend_name='A11y Score'
)
folium.LayerControl().add_to(m)

Can't figure out how to set key_on properly.
Tried these but nothing actually works:

object.geometries.properties.COMUNE
objects.geometries.properties.comune
objects.Com01012018_g_WGS84.geometry.Polygon.properties.COMUNE
objects.Com01012018_g_WGS84.geometries.Polygon.properties.COMUNE
objects.geometry.Polygon.properties.COMUNE
objects.geometries.Polygon.properties.COMUNE
object.geometries.Polygon.properties.COMUNE
Com01012018_g_WGS84.geometry.properties.COMUNE

Errors:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-19-578cc4d527b5> in <module>()
      1 # Save to html
----> 2 m.save('italy-a11yscore.html')

~\Anaconda3\envs\py36\lib\site-packages\branca\element.py in save(self, outfile, close_file, **kwargs)
    159 
    160         root = self.get_root()
--> 161         html = root.render(**kwargs)
    162         fid.write(html.encode('utf8'))
    163         if close_file:

~\Anaconda3\envs\py36\lib\site-packages\branca\element.py in render(self, **kwargs)
    307         """Renders the HTML representation of the element."""
    308         for name, child in self._children.items():
--> 309             child.render(**kwargs)
    310         return self._template.render(this=self, kwargs=kwargs)
    311 

~\Anaconda3\envs\py36\lib\site-packages\folium\map.py in render(self, **kwargs)
    336             '</style>'), name='map_style')
    337 
--> 338         super(LegacyMap, self).render(**kwargs)
    339 
    340 

~\Anaconda3\envs\py36\lib\site-packages\branca\element.py in render(self, **kwargs)
    622 
    623         for name, element in self._children.items():
--> 624             element.render(**kwargs)

~\Anaconda3\envs\py36\lib\site-packages\branca\element.py in render(self, **kwargs)
    618         script = self._template.module.__dict__.get('script', None)
    619         if script is not None:
--> 620             figure.script.add_child(Element(script(self, kwargs)),
    621                                     name=self.get_name())
    622 

~\Anaconda3\envs\py36\lib\site-packages\jinja2\runtime.py in __call__(self, *args, **kwargs)
    573                             (self.name, len(self.arguments)))
    574 
--> 575         return self._invoke(arguments, autoescape)
    576 
    577     def _invoke(self, arguments, autoescape):

~\Anaconda3\envs\py36\lib\site-packages\jinja2\asyncsupport.py in _invoke(self, arguments, autoescape)
    108     def _invoke(self, arguments, autoescape):
    109         if not self._environment.is_async:
--> 110             return original_invoke(self, arguments, autoescape)
    111         return async_invoke(self, arguments, autoescape)
    112     return update_wrapper(_invoke, original_invoke)

~\Anaconda3\envs\py36\lib\site-packages\jinja2\runtime.py in _invoke(self, arguments, autoescape)
    577     def _invoke(self, arguments, autoescape):
    578         """This method is being swapped out by the async implementation."""
--> 579         rv = self._func(*arguments)
    580         if autoescape:
    581             rv = Markup(rv)

<template> in macro(l_1_this, l_1_kwargs)

~\Anaconda3\envs\py36\lib\site-packages\jinja2\runtime.py in call(_Context__self, _Context__obj, *args, **kwargs)
    260                 args = (__self.environment,) + args
    261         try:
--> 262             return __obj(*args, **kwargs)
    263         except StopIteration:
    264             return __self.environment.undefined('value was undefined because '

~\Anaconda3\envs\py36\lib\site-packages\folium\features.py in style_data(self)
    563 
    564         for feature in self.data['features']:
--> 565             feature.setdefault('properties', {}).setdefault('style', {}).update(self.style_function(feature))  # noqa
    566             feature.setdefault('properties', {}).setdefault('highlight', {}).update(self.highlight_function(feature))  # noqa
    567         return json.dumps(self.data, sort_keys=True)

~\Anaconda3\envs\py36\lib\site-packages\folium\folium.py in style_function(x)
    303                 'color': line_color,
    304                 'fillOpacity': fill_opacity,
--> 305                 'fillColor': color_scale_fun(x)
    306             }
    307 

~\Anaconda3\envs\py36\lib\site-packages\folium\folium.py in color_scale_fun(x)
    290             def color_scale_fun(x):
    291                 return color_range[len(
--> 292                     [u for u in color_domain if
    293                      get_by_key(x, key_on) in color_data and
    294                      u <= color_data[get_by_key(x, key_on)]])]

~\Anaconda3\envs\py36\lib\site-packages\folium\folium.py in <listcomp>(.0)
    291                 return color_range[len(
    292                     [u for u in color_domain if
--> 293                      get_by_key(x, key_on) in color_data and
    294                      u <= color_data[get_by_key(x, key_on)]])]
    295         else:

~\Anaconda3\envs\py36\lib\site-packages\folium\folium.py in get_by_key(obj, key)
    286                 return (obj.get(key, None) if len(key.split('.')) <= 1 else
    287                         get_by_key(obj.get(key.split('.')[0], None),
--> 288                                    '.'.join(key.split('.')[1:])))
    289 
    290             def color_scale_fun(x):

~\Anaconda3\envs\py36\lib\site-packages\folium\folium.py in get_by_key(obj, key)
    285             def get_by_key(obj, key):
    286                 return (obj.get(key, None) if len(key.split('.')) <= 1 else
--> 287                         get_by_key(obj.get(key.split('.')[0], None),
    288                                    '.'.join(key.split('.')[1:])))
    289 

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

Thank you for help!

Hi @nittolese, it seems you got the key_on value not right. From the docstring:

Variable in thegeo_dataGeoJSON file to bind the data to. Must start with 'feature' and be in JavaScript objection notation. Ex: 'feature.id' or 'feature.properties.statename'.

Can you try using key_on = 'feature.properties.COMUNE'?

Hi @Conengmo, if I try with

m.choropleth(
 geo_data=state_geo,
 name='choropleth',
 data=italia_df,
 columns=['comune', 'a11y-score'],
 key_on='feature.properties.comune',
 fill_color='YlOrRd',
 fill_opacity=0.7,
 line_opacity=0.2,
 legend_name='A11y Score'
)
folium.LayerControl().add_to(m)
m.save('italy-a11yscore.html')

UPDATE: I have edited my GeoJSON, now it looks like this:

{
  "type":"FeatureCollection",
  "features":[
                     "type":"Feature",
                     "geometry": {...},
                     "properties": {
                                           "comune": "Borgo Vercelli",
                                           "PRO_COM": 2017,
                                           ...

I get no error but the html page doesn't show anything of GeoJSON.
I am traversing the GeoJSON with feature.properties.comune . I have no idea why this happens.
You can find gist here

Thanks for your help, so much appreciated

@nittolese the same thing is happening to me. I get no error when I try to key on a lat/lon feature, but nothing shows up on the map.

Maybe you can check for the coordinate reference system (CRS). They should be EPSG:4326.

Here a possible solution

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AntonioLopardo picture AntonioLopardo  路  15Comments

achourasia picture achourasia  路  15Comments

Demetrio92 picture Demetrio92  路  18Comments

xhx509 picture xhx509  路  15Comments

ibayer picture ibayer  路  21Comments