Folium: GeoJSON feature ID creator fails when properties contain list/dict

Created on 25 May 2019  路  7Comments  路  Source: python-visualization/folium

This code throws a TypeError:
(edit: add geometry type to feature)

import folium
json = {
    "type": "FeatureCollection",
    "features": [
        {
            "bbox": [
                8.546326,
                47.417879,
                8.548813,
                47.420362
            ],
            "type": "Feature",
            "properties": {
                "summary": {
                    "distance": 343.2,
                    "duration": 50.5
                },
                "way_points": [
                    0,
                    15
                ]
            },
            "geometry": {
                "coordinates": [
                    [
                        8.548813,
                        47.420362
                    ],
                    [
                        8.548795,
                        47.420345
                    ],
                    [
                        8.548621,
                        47.420167
                    ]
                ],
                "type": "LineString"
            }
        }
    ]
}

m = folium.Map(location=[47.417879, 8.546326], zoom_start=13)

folium.features.GeoJson(json, style_function=lambda x: {'opacity': 1.0}).add_to(m)
m

Problem description

If a style_function is passed, folium tries to find an ID for the GeoJSON features. When no id field is present (not required in GeoJSONs AFAIK), it will try to pick a field from properties by checking if the values of the property fields are unique. However, the current implementation with set to check uniqueness fails when the property field values are dicts or lists.

Quick Fix

It works with a try/except around the the appropriate lines:

try:
    if len(set(feat['properties'][key] for feat in features)) == n:
        return 'feature.properties.{}'.format(key)
except TypeError:
    continue

I'd be happy with this if was my library, as far as I can see nothing else could raise a TypeError here. What do you think?

Output of 0.9.0

    530         for key in feature.get('properties', []):
    531             # try:
--> 532             if len(set(feat['properties'][key] for feat in features)) == n:
    533                 return 'feature.properties.{}'.format(key)
    534             # except TypeError:

TypeError: unhashable type: 'dict'
bug

All 7 comments

Thanks for your excellent bug report. This is indeed an issue. Your workaround seems fine, but I'll look into it a bit, see if we can do something a bit more explicit.

BTW there's an issue with the example geojson data, it needs a geometry type:

"geometry": {
    "type": "LineString",
    "coordinates": [ etc.

True! Sorry, I pasted a small part of a full routing request and must've forgotten to paste the type, I edited the issue.

Though your proposed quickfix does get the job done, I wanted to make the code work for all properties as allowed by the geojson spec.

If you have the time, do you want to check out the PR?

Yeah, on second thought I'd have done an isinstance check as well;) Very explicit now and easy to follow. I think that looks good! And I personally like this approach better than forcing embed=true or having id fields. Thanks a lot for the quick action!

Thanks for the review @nilsnolde. The fix just got released in version 0.9.1. Hope to hear from you again if something else comes up!

Oh great! Wow, you guys are really quick, thanks so much @Conengmo, works like a charm:) I'm using folium so much, hope I'll find some time to contribute soon.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ispmarin picture ispmarin  路  17Comments

EMarcantonio picture EMarcantonio  路  41Comments

achourasia picture achourasia  路  15Comments

Alcampopiano picture Alcampopiano  路  14Comments

nathan3leaf picture nathan3leaf  路  32Comments