Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

pandas - Folium Choropleth + GeoJSON raises AttributeError: 'NoneType'

I'm trying to do a choropleth using folium which offers a great link between GeoJSON, Pandas and leaflet.

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[98]: 
  Code_commune_INSEE  CP_count
0              75120       723
1              75115       698
2              75112       671
3              75118       627
4              75111       622

"Code_communes_INSEE" corresponds to the attribute "insee" in the GeoJSON. I'd like to do a choropleth using the variable "CP_count" in the above DataFrame.

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(geo_path + 'simplified_communes100m.json').read(),
                    data=postal_count,
                    columns=['Code_commune_INSEE', 'CP_count'],
                    key_on='feature.geometry.properties.insee',
                    fill_color='YlGn',
)
map_france.save(table_path + 'choro_test1.html')

I'm still 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There were 2 problems :

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

The best way to find the right key_on is to play with the geoJSON dict to make sure you are calling the right properties.

2- Once you have the right key_on parameters, you need to make sure that all the available keys in the geoJSON are contained in your Pandas DataFrame (otherwise it will raise a KeyError)

In this case, I used the following command line to get all the insee keys contained by my geoJSON:

ogrinfo -ro -al communes-20150101-100m.shp -geom=NO | grep insee > list_code_insee.txt

If you are experiencing the same issue, this should solve your problem.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share

2.1m questions

2.1m answers

62 comments

56.5k users

...