Folium Choropleth + GeoJSON raises AttributeError: 'NoneType'

Folium Choropleth + GeoJSON raises AttributeError: 'NoneType'

我正在尝试使用 folium 进行等值统计,它在 GeoJSON、Pandas 和传单之间提供了很好的 link。

GeoJSON 格式如下:

{
  "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 数据框:

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"对应GeoJSON中的属性"insee"。我想在上面的 DataFrame 中使用变量 "CP_count" 做一个等值线。

这是我的代码(摘自 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')

我仍然一次又一次地收到此错误:

---------------------------------------------------------------------------
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'

我试过 key_on='feature.geometry.properties.insee' 但没有成功。

有 2 个问题:

1 - 对 'insee' 参数的正确访问是:key_on='feature.properties.insee'

找到正确 key_on 的最佳方法是使用 geoJSON dict 来确保调用正确的属性。

2- 获得正确的 key_on 参数后,您需要确保 geoJSON 中的所有可用键都包含在您的 Pandas DataFrame(否则会引发一个KeyError

在这种情况下,我使用以下命令行获取我的 geoJSON 中包含的所有 insee 键:

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

如果您遇到同样的问题,这应该可以解决您的问题。

我在使用 Folium 0.5.0 的 JupyterLab(在 labs.cognitiveclass.ai)上遇到了同样的问题。然后我复制了我的代码并将其 运行 复制到 PyCharm 中,它成功了!我不明白为什么,也许有一些后端问题 (?)

如果要在 Jupyter notebook 之外显示 folium 地图,必须将地图保存到 html:

map_france.save('map_france.html')

并在浏览器中打开 html。