Issues using Choropleth - python
Currently trying to learn cloropleth - fairly a noob with this.
Problem:
I'm currently using a Michigan Counties GeoJSON file and am trying to draw a map of the state showcasing the percentage of people that opted for John. In return though, I only get an empty colorless map of the US with a legend on the side. Like so:
Full dataset:
https://pastebin.com/x52E0Wii
My GeoJSON file can be found here: https://gis-michigan.opendata.arcgis.com/datasets/67a8ff23b5f54f15b7133b8c30981441/explore?location=44.847247%2C-86.594000%2C7.73
The code I'm using:
fig = px.choropleth(statistical_data,
locations = 'NAME',
locationmode = 'ISO-3',
geojson = michigan_counties,
color = '%John',
featureidkey = 'properties.NAME')
fig.show()
I was expecting a focused map of Michigan counties color coded with percentage of people who opted for John
The association between user data and geojosn is incorrect. In your data example, Maker, not fips, is the county name, so associate the name with the geojson property. Also, you do not need to set the location mode in this case. Since you presented 3 user data, the attached image shows only 3 regions. Also the geojosn data, but I could not get it correctly, so I used geosjon in the reference. Please make sure that the geojson property used has a name field.
from urllib.request import urlopen
import json
with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
counties = json.load(response)
import plotly.express as px
fig = px.choropleth(statistical_data,
locations = 'NAME',
geojson = counties,
color = '%John',
featureidkey = 'properties.NAME',
scope='usa')
fig.update_geos(fitbounds="locations", visible=False)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
Related
plotly choropleth not drawing any polygons
I have been following this https://plotly.com/python/choropleth-maps/ tutorial to draw a choropleth map of Australian suburbs. Using this https://github.com/tonywr71/GeoJson-Data/blob/master/australian-suburbs.geojson as the base geojson data, and then modifying it such that each feature has an 'id' property, which is the postcode for that feature. The final result looks like this: (available at https://github.com/meherGill/geojson_suburbs/blob/main/suburbsModified.geojson) The corresponding dataframe for this is and the code to draw the map is import plotly.express as px with open('./data/suburbsModified.geojson') as f: jsondata = json.loads(f.read()) fig = px.choropleth(df2, geojson=jsondata, locations='Postal', color='Status', color_continuous_scale="Viridis") fig.show() But my figure looks like this, a map with nothing drawn on it. Why is it not drawing a choropleth map of australian suburbs as defined in the geojson file
fundamentally your issues are the fact your geojson is problematic. Viewing on GitHub shows that modified geojson does not overlay Australia original geojson shows other issues, a few of the features have no geometry. Have used geopandas to filter this out have synthesized df2 from the geojson so that your code could be used approach I would recommend is using source geojson and supplementing postal code in data frame import requests import pandas as pd import numpy as np import plotly.express as px # original geojson url = "https://raw.githubusercontent.com/tonywr71/GeoJson-Data/master/australian-suburbs.geojson" # user's geojson url = "https://raw.githubusercontent.com/meherGill/geojson_suburbs/main/suburbsModified.geojson" fix = True # get geojson req = requests.get(url) jsondata = req.json() # well there is some invalid geomtry, exclude using geopandas if fix: gdf = gpd.GeoDataFrame.from_features(jsondata).set_index( pd.json_normalize(jsondata["features"])["id"] ) jsondata = gdf.loc[~gdf.geometry.isna()].__geo_interface__ # syntesize data frame df2 = pd.DataFrame({"Postal": pd.json_normalize(req.json()["features"])["id"]}).assign( Status=lambda d: np.random.randint(1, 400, len(d)) ) fig = px.choropleth( df2, geojson=jsondata, locations="Postal", color="Status", color_continuous_scale="Viridis", ) fig.show()
Fill U.S. counties by value using Python & Cartopy?
I'd like to know how to fill in a map of U.S. counties by value (i.e., a chloropleth map), using Python 3 and Cartopy, and I haven't yet found anything online to guide me in that. That filled value could be, for instance, highest recorded tornado rating (with counties left blank for no recorded tornadoes), or even something arbitrary such as whether I've visited (=1) or lived (=2) in the county. I found a helpful MetPy example to get the county boundaries on a map: https://unidata.github.io/MetPy/latest/examples/plots/US_Counties.html What I envision is somehow setting a list (or dictionary?) of county names to a certain value, and then each value would be assigned to a particular fill color. This is my current script, which generates a nice blank county map of the CONUS/lower 48 (though I'd eventually also like to add Alaska/Hawaii insets). import cartopy import cartopy.crs as ccrs import matplotlib as mpl import matplotlib.pyplot as plt from metpy.plots import USCOUNTIES plot_type = 'png' borders = cartopy.feature.BORDERS states = cartopy.feature.NaturalEarthFeature(category='cultural', scale='10m', facecolor='none', name='admin_1_states_provinces_lakes') oceans = cartopy.feature.OCEAN lakes = cartopy.feature.LAKES mpl.rcParams['figure.figsize'] = (12,10) water_color = 'lightblue' fig = plt.figure() ax = plt.axes(projection=ccrs.LambertConformal(central_longitude=-97.5, central_latitude=38.5, standard_parallels=(38.5,38.5))) ax.set_extent([-120, -74, 23, 50], ccrs.Geodetic()) ax.coastlines() ax.add_feature(borders, linestyle='-') ax.add_feature(states, linewidth=0.50, edgecolor='black') ax.add_feature(oceans, facecolor=water_color) ax.add_feature(lakes, facecolor=water_color, linewidth=0.50, edgecolor='black') ax.add_feature(USCOUNTIES.with_scale('500k'), linewidth=0.10, edgecolor='black') plt.savefig('./county_map.'+plot_type) plt.close() Any ideas or tips on how to assign values to counties and fill them accordingly?
So Cartopy's shapereader.Reader can give you access to all of the records in the shapefile, including their attributes. Putting this together with MetPy's get_test_data to get access to the underlying shapefile you can get what you want, assuming you have a dataset that maps e.g. FIPSCODE to EF rating: fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()) cmap = plt.get_cmap('magma') norm = plt.Normalize(0, 5) # Fake tornado dataset with a value for each county code tor_data = dict() # This will only work (have access to the shapefile's database of # attributes after it's been download by using `USCOUNTIES` or # running get_test_data() for the .shx and .dbf files as well. for rec in shpreader.Reader(get_test_data('us_counties_20m.shp', as_file_obj=False)).records(): # Mimic getting data, but actually getting a random number # GEOID seems to be the FIPS code max_ef = tor_data.get(rec.attributes['GEOID'], np.random.randint(0, 5)) # Normalize the data to [0, 1] and colormap manually color = tuple(cmap(norm(max_ef))) # Add the geometry to the plot, being sure to specify the coordinate system ax.add_geometries([rec.geometry], crs=ccrs.PlateCarree(), facecolor=color) ax.set_extent((-125, -65, 25, 48)) That gives me:
I'm not sure about passing in a dict, but you can pass in a list to facecolor. ax.add_feature(USCOUNTIES.with_scale('500k'), linewidth=0.10, edgecolor='black', facecolor=["red", "blue", "green"]) If you know how many counties there are you can make a list that long by: import matplotlib.cm as cm import numpy as np number_of_counties = 3000 color_scale = list(cm.rainbow(np.linspace(0, 1, number_of_counties))) ax.add_feature(USCOUNTIES.with_scale('500k'), linewidth=.10, edgecolor="black", facecolor=color_scale) but they didn't make it easy to extract the names from USCOUNTIES. You can see where it is defined in your source code: from metpy import plots print(plots.__file__) If you go inside the directory printed there is a file named cartopy_utils.py and inside the class definition for class MetPyMapFeature(Feature): you will see USCOUNTIES. You might have better luck than I did mapping county names to the geometric shapes. EDIT: Also, I just used cm.rainbow as an example, you can choose from any color map https://matplotlib.org/stable/tutorials/colors/colormaps.html. Not sure if it even goes up to 3000, but you get the idea.
Visualize scatter plot with labels on each point
i have a dataset longitude, latitude, its city, and the status of its city of coronavirus. I want to give a label on each point for city name. i dont have any idea if i use plt.text() one by one to give the labels. Here the code i use for creating dataset jabar = [ ['Depok',-6.385589,106.830711,'sedang',600], ['Tasikmalaya',-7.319563,108.202972,'sedang',600], ['Ciamis',-7.3299,108.3323,'sedang',600], ['Kuningan',-7.0138,108.5701,'sedang',600], ['Bogor',-6.497641,106.828224,'sedang',600], ['Bogor',-6.595038,106.816635,'sedang',600], ['Cirebon',-6.737246,108.550659,'sedang',600], ['Majalengka',-6.8364,108.2274,'sedang',600], ['Sumedang',-6.8381,107.9275,'sedang',600], ['Indramayu',-6.327583,108.324936,'sedang',600], ['Subang',-6.571589,107.758736,'sedang',600], ['Purwakarta',-6.538681,107.449944,'sedang',600], ['Karawang',-6.3227,107.3376,'sedang',600], ['Bekasi',-6.241586,106.992416,'sedang',600], ['Pangandaran',-7.6833,108.6500,'sedang',600], ['Sukabumi',-6.923700,106.928726,'sedang',600], ['Cimahi',-6.8841,107.5413,'sedang',600], ['Banjar',-7.374585,108.558189,'sedang',600], ['Cianjur',-6.734679,107.041252,'sedang',600], ['Bandung',-6.914864,107.608238,'tinggi',1000], ['Bandung',-6.905977,107.613144,'tinggi',1000], ['Bandung',-6.914744,107.609810,'tinggi',1000], ['Garut',-7.227906,107.908699,'sedang',600], ['Bandung Barat',-7.025253,107.519760,'sedang',600]] features=['City','longitude','latitude','status','status_size'] risk_map = pd.DataFrame(jabar, columns=features) and here it is the code i create for visualize to give the label each points. import matplotlib.pyplot as plt plt.figure(figsize=(14,8)) plt.scatter(risk_map['latitude'],risk_map['longitude'], c='orange', s=risk_map['status_size'], label='Risk region') plt.title('Peta Sebaran Covid-19', fontsize=20) plt.text(-7.227906,107.908699,'Garut') plt.show() actually i have two datasets exclude the code i write above, the another is about confirmed-positive-cases-covid-region which is the point about more than 500.000 points. I merge this two dataset to get the risk-region. But i get trouble when i want to giva a labels on each point. the plt.text() i write above is example to give a label on a point. it is impossible if i write one by one as same as the text code because my computer got cracked and blank after i executed that code. Anyone have any idea to give a label on each points that i write the code above? thank in advance
plotly mapbox provides very simple to use capabilities for what you want your longitude, latitude values are reversed. See in code sample below I've reversed them import plotly.express as px import pandas as pd jabar = [ ['Depok',-6.385589,106.830711,'sedang',600], ['Tasikmalaya',-7.319563,108.202972,'sedang',600], ['Ciamis',-7.3299,108.3323,'sedang',600], ['Kuningan',-7.0138,108.5701,'sedang',600], ['Bogor',-6.497641,106.828224,'sedang',600], ['Bogor',-6.595038,106.816635,'sedang',600], ['Cirebon',-6.737246,108.550659,'sedang',600], ['Majalengka',-6.8364,108.2274,'sedang',600], ['Sumedang',-6.8381,107.9275,'sedang',600], ['Indramayu',-6.327583,108.324936,'sedang',600], ['Subang',-6.571589,107.758736,'sedang',600], ['Purwakarta',-6.538681,107.449944,'sedang',600], ['Karawang',-6.3227,107.3376,'sedang',600], ['Bekasi',-6.241586,106.992416,'sedang',600], ['Pangandaran',-7.6833,108.6500,'sedang',600], ['Sukabumi',-6.923700,106.928726,'sedang',600], ['Cimahi',-6.8841,107.5413,'sedang',600], ['Banjar',-7.374585,108.558189,'sedang',600], ['Cianjur',-6.734679,107.041252,'sedang',600], ['Bandung',-6.914864,107.608238,'tinggi',1000], ['Bandung',-6.905977,107.613144,'tinggi',1000], ['Bandung',-6.914744,107.609810,'tinggi',1000], ['Garut',-7.227906,107.908699,'sedang',600], ['Bandung Barat',-7.025253,107.519760,'sedang',600]] features=['City','longitude','latitude','status','status_size'] risk_map = pd.DataFrame(jabar, columns=features) fig = px.scatter_mapbox(risk_map, lon="latitude", lat="longitude", color="status", hover_name="City",size="status_size" ) fig.update_layout(mapbox={"style":"carto-positron"}) fig
Plotly choropleth map draws 1 feature and fills background with one color
For a project I need to draw a choropleth map of Belgium and it's provinces. When I draw the map I get this as a result. I use the following python code to draw the map: import plotly.express as px import json import pandas as pd df = pd.read_csv("data/resulted_data/kmeans/CLUSTER_PROVINCES.csv") with open('geojson.json') as file: be = json.load(file) fig = px.choropleth(df, geojson=be, locations="PROVINCE", featureidkey="properties.NameDUT", projection="mercator", color="CLUSTER", hover_data=["PROVINCE", "INFECTION_RATE", "HOSPITALISATION_RATE", "TEST_POS_PERCENTAGE", "CLUSTER"]) fig.update_geos(fitbounds="locations") fig.show() The geojson file I use works on geojson.io. The result on geojson.io is the following: The used geojson file can be found here: https://raw.githubusercontent.com/mathiasleroy/Belgium-Geographic-Data/master/dist/polygons/geojson/Belgium.provinces.WGS84.geojson. The only thing I changed in the geojson file is the value of the Dutch names for the provinces to match the names in my dataset. I have no idea why it plots the province of Antwerp right but then covers the background with the same color.
The problem is that the geojson file is badly wound. A solution to the problem can be found here: Solution
Creating a choropleth chart Using plotly.graph_objects in Python to map data in Canada
I am using the plotly.graph_objects to map my data in Canda map. And, I am creating the fig as follows: fig = go.Figure(data=go.Choropleth( locations=df['state Abv'], z=df['total applications'].astype(float), locationmode='**UNKNOWN**', colorscale='Reds', autocolorscale=False, text=df['text'], marker_line_color='white', colorbar_title="Number of applications")) Is there a way to set locattionmode as "Canada" to map the data on Canada map? Thank you! Ben
You can use folium library to map countries easily. For example to map a country, just write coordinates of that place in location parameter:(I have plotted for India) import folium as fm world_map = fm.Map( location = [20.770685, 73.7200303], zoom_start = 6) And to add a popup and other features to it you can do:(I have added this popup for a place called onatrio.) ontario = fm.map.FeatureGroup() ontario.add_child(fm.CircleMarker([26.9127837,75.7411626], color = "red", radius = 5, fill_color = "Red") ) world_map.add_child(ontario) fm.Marker([26.9127837,75.7411626], popup = 'ontario').add_to(world_map) world_map.save('plot_data.html') from IPython.display import HTML HTML('<iframe src=plot_data.html width=700 height=450></iframe>') This code is not for jupyter. If you are using jupyter then cut the last part of IPython libray from this code. I hope you got my instructions. Happy coding!