7

My approach to creating a choropleth map via plotly seems pretty straightforward--load in the DataFrame, load in the geojson, assign the necessary features to the custom polygons, and plot.

Obviously there is a missed step somewhere when referencing of the custom polygons as only a blank map appears after a lengthy loading time.

One major thing to note is that about half of the polygons are located within states, but are their own custom polygon within the states. Therefore to my knowledge, choropleth_mapbox is the more suitable solution.

A sample of the image, showing custom polygons within the states: enter image description here

The code:

import pandas as pd
import plotly.express as px
import geopandas as gpd
from geojson import Polygon
import json

# reading in the dataframe
path = '/path/to/csv'
df = pd.read_csv(path)
geo_df = gpd.GeoDataFrame(df)

# reading in the geospatial data
with open('/path/to/geojson') as f:
    geojson = json.load(f)
    
# create the plot
fig = px.choropleth_mapbox(geo_df[0:50], #slicing for quick loading
                           geojson=geojson, 
                           color="MALL",
                           locations="MWS_ID", 
                           featureidkey="properties.MWS_ID",
                           center={"lat": 39, 
                                   "lon": -95},
                           mapbox_style="carto-positron", 
                           zoom=3)

fig.show()

The output:

enter image description here

Obviously data is missing.

I think the issue is in the geojson file. The only thing I can see that might be off about the geojson structure is that the coordinates of my geojson are in two brackets, whereas the geojson from the documentation's coordinates are in three brackets.

Below is my geojson.

{'type': 'FeatureCollection',
 'features': [{'type': 'Feature',
   'geometry': {'type': 'Polygon',
    'coordinates': [[-89.299965, 36.508405],
     [-89.414355, 36.499866],
     [-89.424498, 36.476321],
     .....
   'properties': {'MWS_ID': 'TN_1'}},

  {'type': 'Feature',
   'geometry': {'type': 'Polygon',
    'coordinates': [[-111.043999, 44.139903],
     [-111.040171, 42.227952],
     [-111.040773, 41.820698],
     .....

And below is the documentation's geojson

{'type': 'FeatureCollection',
 'features': [{'type': 'Feature',
   'geometry': {'type': 'MultiPolygon',
    'coordinates': [[[[-73.6363215300962, 45.5759177646435],
       [-73.6362833815582, 45.5758266113331],
       .....
       [-73.6363215300962, 45.5759177646435]]],
     [[[-73.6561004885273, 45.5841347974261],
       .....
       [-73.6561004885273, 45.5841347974261]]]]},
   'properties': {'district': '11-Sault-au-Récollet'},
   'id': '11'},

  {'type': 'Feature',
   'geometry': {'type': 'Polygon',
    'coordinates': [[[-73.6217484540132, 45.5544783077209],
      [-73.6235005117779, 45.5536358848324],
      [-73.6278096771011, 45.5513024018691],

Here is how I created the geojson

# Create the GeoJSON
names_merged = names_1 + names_2
geoms_merged = geoms_1 + geoms_2

geojson = {'type':'FeatureCollection', 'features':[]}

for i in range(len(names_merged)):
    feature = Feature(geometry=geoms_merged[i])
    geojson['features'].append(feature)
    geojson['features'][i]['properties']['MWS_ID'] = names_merged[i]
    
with open('/path/to/geojson', 'w') as f:
   dump(geojson, f)

Where names_merged is a list of MWS_IDs in str format and geoms_merged is a list of polygons in the geojson.geometry.Polygon format.

Verifying the dataframe and geojson have the same keys.

print(geo_df['MWS_ID'][3])
print(geojson["features"][28]['properties']["MWS_ID"])

The output

AZ_2
AZ_2

But the map is still blank.

Thank you for your continued help S.O. community.

Jkiefn1
  • 91
  • 3
  • 16
  • 1
    In px.choropleth(), location is not the polygon information, but the abbreviation of the state name, etc. In addition, we need 'usa' as the scope of the map. Please refer to the official [reference](https://plotly.com/python/choropleth-maps/#using-builtin-country-and-state-geometries). – r-beginners May 03 '21 at 04:36
  • @r-beginners, I appreciate the response! However, can you elaborate as to what I should point the custom polygons found in the ‘Geometry’ column to? The polygons are custom polygons, I.e. not tied to fips or coordinates accessible via plotly. The ‘Geometry’ columns houses the custom polygons. The ‘MWS_ID’ houses the information I’d like to display on hover. – Jkiefn1 May 03 '21 at 19:16
  • Do you mind to provide a [mcve](/help/mcve)? In particular a sample of your data? – rpanai May 04 '21 at 02:04
  • If you set locations='MWS_ID' and edit MWS_ID to 'TX' in any one line of geo_df, will you see the colored area? – r-beginners May 04 '21 at 02:11
  • @rpanai I have edited the original post to include a more user-friendly sample of the data. – Jkiefn1 May 04 '21 at 04:36
  • @r-beginners That would work! However, as you can see in the now edited original post, there are some 'MWS_ID' s that will not be as straightforward--they are custom polygons within the states. As such, I don't know if the recommended edit is as relevant as I made it originally seem. – Jkiefn1 May 04 '21 at 04:38
  • @r-beginners, I've edited the original post to make clearer what I meant--there are some polygons that are located within states' boundaries. AL_1, CA_1 and AR_1 are examples of this. Tying those zones to fips won't work because there are AL_2, CA_2, AR_2, etc. zones that also lie within those states. – Jkiefn1 May 04 '21 at 13:16
  • I finally understood the intent of the question. Then I should use px.choropleth_mapbox() or something like that. see [this](I finally understood the intent of the question. Then I should use px.choropleth_mapbox() or something like that.) – r-beginners May 04 '21 at 13:37
  • @r-beginners if you were referencing something with your comment above, the "see [this]" link was broken or didn't copy correctly. Thank you for your continued help! – Jkiefn1 May 06 '21 at 14:52
  • [this](https://plotly.com/python/mapbox-county-choropleth/#indexing-by-geojson-properties) I wanted to introduce the official reference, but I ran out of time to edit it and couldn't do it. – r-beginners May 07 '21 at 01:33
  • @r-beginners thanks to your advice I've made some headway, but the map is still not populating. I separated out the data and the geospatial info into a data frame and a geojson file. – Jkiefn1 May 07 '21 at 05:04
  • The only thing I can find that seems to differ between the documentation's geojson and my own is the amount of brackets in the geometry feature. @r-beginners – Jkiefn1 May 09 '21 at 04:33
  • Could you share a complete geojson snippet? Or even better, link to the whole file? And do you prefer a mapbox based solution, or would e.g. a leaflet solution be accepted? – emher May 20 '21 at 18:19
  • I'd prefer a solution written in plotly. Here is a link to the data, the geojson, and the sample code. https://github.com/jkiefn1/Ployly-GeoJSON-SO-Question – Jkiefn1 May 21 '21 at 19:34
  • @emher forgot to tag you above. Thank you for your time and consideration. Hopefully the data I provided is helpful! It's the whole dataset. – Jkiefn1 May 21 '21 at 19:40

1 Answers1

5

Your output is not a choropleth_mapbox, it is a choropleth. Are you missing showing us any layout code? Without seeing all of your code, it's hard to determine the root cause of your issue so instead I'll show you a simple working example of how to connect a geojson to a dataframe and display it as a choropleth_mapbox below.

import pandas as pd
import plotly.express as px

df = pd.DataFrame({'letter':['A','B','C'],'name':['AZ_1','BV_2','CD_3'],'value':[2,5,7]})


gj = {
    'type': 'FeatureCollection',
    'features': [
        {
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates':[[
                    [-82.899205,33.653817],
                    [-82.771500,32.516301],
                    [-80.914171,32.133138],
                    [-79.710831,33.171969],
                    [-82.899205,33.653817]
                ]]
            },
            'properties': {'unique_id': 'AZ_1', 'name': 'shape A'}
        },
                {
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates':[[
                    [-80.883651,33.080687],
                    [-80.835692,33.797411],
                    [-82.095711,34.396734],
                    [-82.945897,33.168320],
                    [-80.883651,33.080687]
                ]]
            },
            'properties': {'unique_id': 'BV_2', 'name': 'shape B'}
        },
                {
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates':[[
                    [-79.471035,33.255865],
                    [-78.202296,34.086771],
                    [-78.629569,34.855954],
                    [-81.446082,34.698384],
                    [-79.471035,33.255865]
                ]]
            },
            'properties': {'unique_id': 'CD_3', 'name': 'shape C'}
        },
    ]
}

fig = px.choropleth_mapbox(df, geojson=gj,color=df.value,
                           locations=df.name, featureidkey="properties.unique_id",
                           center={"lat": 33.33012299999999, "lon": -81.08463033333332},
                           mapbox_style="carto-positron", zoom=5)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

When using a geojson with custom Polygons, you just need to insure that the featureidkey matches the locations dataframe column so that you can apply other dataframe values to the Polygon (like color, text, etc.).

The simple code above should output:enter image description here This is what a choropleth_mapbox should output- a tile-based map. Your output is not tile-based which is why I'm asking if you have additional layout code that is changing the type of map displayed. Even if your choropleth_mapbox is malformed, the output won't be what you have.

Editing answer

Your geojson is malformed- a Polygon coordinates array should be a 3-dimensional array not 2-dimensional. Run this code to update your coordinates array:

old_features = [feature for feature in geojson['features']]
new_features = [feature for feature in geojson['features']]
for i in range(len(old_features)):
    new_features[i]['geometry']['coordinates'] = [new_features[i]['geometry']['coordinates']]
new_geojson = {
    'type': 'FeatureCollection',
    'features': new_features

Now creating the map should work:

fig = px.choropleth_mapbox(df, geojson=new_geojson,color=df.MALL,
                           locations=df.MWS_ID, featureidkey="properties.MWS_ID",
                           center={"lat": 39, "lon": -95},
                           mapbox_style="carto-positron", zoom=3)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
}

Here is the output I get with your csv and geojson:

enter image description here

zerOpRiME
  • 360
  • 3
  • 8
  • Thank you very much for the answer! However, there is no other formatting going into the code other than what was shown. Here is a link to a GitHub containing the data, the code, and the geojson. https://github.com/jkiefn1/Ployly-GeoJSON-SO-Question – Jkiefn1 May 21 '21 at 19:35
  • Your edited answer does the trick for this solution, and sheds light on the error for any future attempt. Thank you! – Jkiefn1 May 22 '21 at 17:00