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:
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:
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.
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: 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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With