I am mapping data by zip code. I've pasted a screenshot of the geopandas DataFrame (geodata_mainland) below (apologies for not including it in an easily reproducible way, if anyone knows how to do that for geopandas geometry column, I am happy to update it). I have separate DataFrames called ak and hi for Alaska and Hawaii. I am using the following code to map the quartiles by zip code with insets for Alaska and Hawaii.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, figsize=(20,20))
geodata_mainland.plot(column='quartile', cmap='Purples', linewidth=0.1, ax=ax, edgecolor='black', legend = True,categorical=True)
ax2 = fig.add_axes([0.1, 0.25, 0.2, 0.2])
ak.plot(column='quartile', cmap='Purples', linewidth=0.1, ax=ax2, edgecolor='black', legend = False)
ax3 = fig.add_axes([0.32, 0.3, 0.1, 0.1])
hi.plot(column='quartile', cmap='Purples', linewidth=0.1, ax=ax3, edgecolor='black', legend = False)
ax.axis('off')
ax2.set_xticks([])
ax2.set_yticks([])
ax3.set_xticks([])
ax3.set_yticks([])
It works really well except that the mapping between quartiles and colors is different for Alaska and Hawaii. Specifically, all zip codes in both states are quartile 4, but because I am plotting them separately, they are showing up as the color for quartile 1. Is is possible to sync the mapping between colors and values across subplots? I've also inserted my current map for reference.
CodePudding user response:
- the solution is very simple, pass
vmin
andvmax
arguments toplot()
- have used geometry from GitHub and synthesized quartile
- colors are correct, insets are different probably due to different geometry
solution
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, figsize=(20, 20))
geodata_mainland.plot(
column="quartile",
cmap="Purples",
linewidth=0.1,
ax=ax,
edgecolor="black",
legend=True,
categorical=True,
)
ax2 = fig.add_axes([0.1, 0.25, 0.2, 0.2])
ak.plot(
column="quartile",
cmap="Purples",
vmin=1,
vmax=4,
linewidth=0.1,
ax=ax2,
edgecolor="black",
legend=False,
)
ax3 = fig.add_axes([0.32, 0.3, 0.1, 0.1])
hi.plot(
column="quartile",
cmap="Purples",
vmin=1,
vmax=4,
linewidth=0.1,
ax=ax3,
edgecolor="black",
legend=False,
)
ax.axis("off")
ax2.set_xticks([])
ax2.set_yticks([])
ax3.set_xticks([])
ax3.set_yticks([])
setup
- get geometry
- synthesise quartile where it is 4 for AK and HI
from pathlib import Path
import requests, urllib
import pandas as pd
import numpy as np
import geopandas as gpd
url = "https://raw.githubusercontent.com/gweissman86/three_digit_zips/main/three_dig_zips/three_dig_zips"
f = Path.cwd().joinpath("ZIP3")
if not f.is_dir():
f.mkdir()
for e in [".cpg", ".dbf", ".prj", ".shp", ".shx"]:
r = requests.get(f"{url}{e}", stream=True, headers={"User-Agent": "XY"})
with open(f.joinpath(f"three_dig_zips{e}"), "wb") as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
gdf = gpd.read_file(list(f.glob("*.shp"))[0])
gdf_states = gpd.read_file(
"https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/50m/cultural/ne_50m_admin_1_states_provinces.json"
).loc[lambda d: d["iso_a2"].eq("US"), ["iso_3166_2", "name", "region_sub", "geometry"]]
gdf = (
gdf.sjoin(gdf_states.to_crs(gdf.crs), how="left")
.assign(quartile=lambda d: np.random.randint(1, 5, len(d)))
.reset_index(drop=True)
)
gdf.loc[gdf["iso_3166_2"].isin(["US-AK", "US-HI"]), "quartile"] = 4
# final setup ...
geodata_mainland = gdf.loc[~gdf["iso_3166_2"].isin(["US-AK", "US-HI"])]
ak = gdf.loc[gdf["iso_3166_2"].isin(["US-AK"])]
hi = gdf.loc[gdf["iso_3166_2"].isin(["US-HI"])]
CodePudding user response:
There might be another way, but I found that it works to define a custom colormap. For example:
from matplotlib import colors
cmap = colors.ListedColormap([(0,1,0,0.25),(0, 0.75, 0.25,0.5),(0, 0.25, 0.75,0.75),(0,0,1,1)] )
boundaries = [0,1.1,2.1,3.1,4.1]
norm = colors.BoundaryNorm(boundaries, cmap.N, clip=True)
and then define a custom legend using the colormap:
from matplotlib.patches import Patch
legend_elements = [Patch(facecolor=(0,1,0,0.25), edgecolor='white',
label='First Quartile'),Patch(facecolor=(0, 0.75, 0.25,0.5), edgecolor='white',
label='Second Quartile'),Patch(facecolor=(0, 0.25, 0.75,0.75), edgecolor='white',
label='Third Quartile'),Patch(facecolor=(0,0,1,1), edgecolor='white',
label='Fourth Quartile')]
ax.legend(handles=legend_elements)