plotly.py icon indicating copy to clipboard operation
plotly.py copied to clipboard

Choropleth maps only render the first feature with a matching featureidkey, not all matching features

Open mathuin opened this issue 1 year ago • 0 comments

When px.choropleth() is called with a GeoJSON feature collection containing multiple features matching a single featureidkey value, only the first feature is rendered. I believe all features should be so rendered.

The following code generates two images: the first renders all four features, while the second renders only three. The first uses a featureidkey unique to all features, the second uses a featureidkey that is not unique -- only the first feature to match is rendered. :-(

#!/usr/bin/env python3

import pandas as pd
import plotly.express as px

# A simple GeoJSON with four features.  
# Each feature has a district.  
# One district has two features.
geojson = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {
                "name": "Alpha",
                "district": "One",
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[0, 0], [0, 5], [5, 5], [5, 0], [0, 0]]],
            },
        },
        {
            "type": "Feature",
            "properties": {
                "name": "Bravo",
                "district": "One",
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[5, 0], [5, 5], [10, 5], [10, 0], [5, 0]]],
            },
        },
        {
            "type": "Feature",
            "properties": {
                "name": "Charlie",
                "district": "Two",
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[0, 5], [0, 10], [5, 10], [5, 5], [0, 5]]],
            },
        },
        {
            "type": "Feature",
            "properties": {
                "name": "Delta",
                "district": "Three",
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": [[[5, 5], [5, 10], [10, 10], [10, 5], [5, 5]]],
            },
        },
    ],
}

districts = {
    f["properties"]["name"]: f["properties"]["district"] for f in geojson["features"]
}

# A simple dataframe relating names and districts from the above GeoJSON data.
# i.e., [{'name': 'Alpha', 'district': 'One'}, ...]
data = [f['properties'] for f in geojson['features']]

df = pd.DataFrame(data)

# This code generates two maps from the data:
# * The name map shows all four squares in the same color (count = 1)
# * The district map shows _three_ squares, one with one color (count = 2) and two with another color (count = 1)

# What I expected:
# * The district map should show all four squares, two with light color and two with dark
for key in ["name", "district"]:

    region_counts = df.groupby([key], observed=False).size().reset_index(name="count")

    fig = px.choropleth(
        region_counts,
        geojson=geojson,
        fitbounds='geojson',
        locations=key,
        color="count",
        featureidkey=f"properties.{key}",
    )

    fig.write_image(f"mwe-{key}.png")

mathuin avatar Jul 11 '24 00:07 mathuin