使 geopandas 颜色在子图中同步

Make geopandas colors sync across subplots

我正在按邮政编码映射数据。我在下面粘贴了 geopandas DataFrame (geodata_mainland) 的屏幕截图(很抱歉没有以易于重现的方式包含它,如果有人知道如何为 geopandas 几何列执行此操作,我很乐意更新它)。对于阿拉斯加和夏威夷,我有分别称为 ak 和 hi 的 DataFrame。我正在使用以下代码按邮政编码映射四分位数,其中包含阿拉斯加和夏威夷的插图。

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([])

除阿拉斯加和夏威夷的四分位数和颜色之间的映射不同外,它的效果非常好。具体来说,两个州的所有邮政编码都是四分位数 4,但因为我分别绘制它们,所以它们显示为四分位数 1 的颜色。是否可以同步子图中颜色和值之间的映射?我还插入了我当前的地图以供参考。

  • 解决方法很简单,将vminvmax参数传递给plot()
  • 使用了 GitHub 的几何图形并合成了 quartile
  • 颜色正确,插图不同可能是由于几何形状不同

解决方案

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([])

设置

  • 获取几何体
  • 合成四分位数 其中AK和HI为4
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"])]

可能还有另一种方法,但我发现它可以定义自定义颜色图。例如:

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)

然后使用颜色图定义自定义图例:

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)