绘制阿拉斯加和夏威夷的插图等值线(最好是 Mapbox)

Plotly create inset choropleth (Mapbox ideally) of Alaska and Hawaii

有没有办法创建额外的等值线(理想情况下是 Mapbox 等值线,但我会接受 Plotly 的标准等值线功能)地图并将它们分层放在基本等值线之上,以便我可以轻松显示与阿拉斯加和夏威夷与美国大陆?

Something like this image

不要相信我现有的代码一定有用,但这是我构建底图的方式(删除了我的自定义样式,以便任何人都应该能够生成)。

fig = px.choropleth_mapbox(
    df_mar,
    geojson=puma,
    locations="stpuma",
    color="inter_pct",
    range_color=(0,25),
    color_continuous_scale="Viridis",
    labels={"inter_pct": "Marriage (%)"},
    center={"lat": 37.0902, "lon": -95.7129},
    zoom=4.2,
    opacity=1.0,
    mapbox_style="white-bg"
)
fig.update_layout(
    coloraxis_colorbar=dict(
        bgcolor="rgba(22,33,49,1)",
        title="Marriage,<br>Percent Share",
        titlefont=dict(
            color="rgba(255,255,255,1)"
        ),
        tickfont=dict(
            color="rgba(255,255,255,1)"
        ),
    ),
    margin=dict(
        l=50,
        r=50,
        b=50,
        t=50,
        pad=4
    ),
    paper_bgcolor = "rgba(8,18,23,1)",
    plot_bgcolor = "rgba(8,18,23,1)",
    showlegend = True,
    annotations = [
        dict(
            x=-0.025,
            y=-0.04,
            xref='paper',
            yref='paper',
            text='Source: Census ACS 5 2015-2019',
            showarrow = False,
            font=dict(
                color="rgba(255,255,255,1)"
            ),
            bgcolor="rgba(8,18,23,1)",
        )
    ]
)
fig.update_traces(
    marker_line_width=0,
    below="waterway"
)
fig.show(width=1920, height=1080)
  • 可以用mapbox
  • 实现
  • 关键概念是修改几何图形以满足您的布局要求。因此已经https://shapely.readthedocs.io/en/stable/manual.html#affine-transformations移动阿拉斯加夏威夷
  • 还发现 阿拉斯加 几何形状因跨越日期变更线而出现问题。因此,转换后的几何体也会被剪裁
  • 添加 layers 以表明几何已被操纵
  • 包括海洋边界以演示如何将其扩展到其他几何形状
import geopandas as gpd
import shapely.geometry
import numpy as np
import plotly.express as px
import requests, io
from pathlib import Path
from zipfile import ZipFile
import urllib
import pandas as pd
from shapely.affinity import affine_transform as T

# US geometry
urls = [
    "https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_state_5m.zip",
    "https://maritimeboundaries.noaa.gov/downloads/USMaritimeLimitsAndBoundariesSHP.zip",
]
gdfs = {}
for url in urls:
    f = Path.cwd().joinpath(urllib.parse.urlparse(url).path.split("/")[-1])

    if not f.exists():
        r = requests.get(url, stream=True, headers={"User-Agent": "XY"})
        with open(f, "wb") as fd:
            for chunk in r.iter_content(chunk_size=128):
                fd.write(chunk)
        zfile = ZipFile(f)
        zfile.extractall(f.stem)

    gdfs[f.stem] = gpd.read_file(
        list(f.parent.joinpath(f.stem).glob("*.shp"))[0]
    )  # .to_crs("EPSG:4326")

gdf2 = gdfs["cb_2018_us_state_5m"]
gdf2 = gdf2.set_index("STUSPS", drop=False)
gdf2["color"] = gdf2["STATEFP"].astype(int)


# move alaska and hawaii using affine transform
t = {"AK": [0.6, 0, 0, 0.6, -20, -15], "HI": [3, 0, 0, 3, 385, -42]}
clip = (-179, 15, 0, 150)
gdf3 = gdf2.copy()
gdf3.loc[t.keys(), "geometry"] = gdf3.loc[t.keys(), ["geometry"]].apply(
    lambda g: shapely.ops.clip_by_rect(T(g["geometry"], t[g.name]), *clip), axis=1
)

gdf_m = gdfs["USMaritimeLimitsAndBoundariesSHP"]
gdf_m = gdf_m.dissolve("REGION")
tm = {"Alaska": "AK", "Hawaiian Islands": "HI"}
gdf_m.loc[tm.keys(), "geometry"] = gdf_m.loc[tm.keys(), ["geometry"]].apply(
    lambda g: shapely.ops.clip_by_rect(
        T(g["geometry"], t[tm[g.name]]), *gdf3.loc[tm[g.name]].geometry.bounds
    ),
    axis=1,
)


px.choropleth_mapbox(
    gdf3,
    geojson=gdf3.geometry.__geo_interface__,
    locations=gdf3.index,
    color="color",
    hover_name="NAME",
).update_layout(
    mapbox={
        "style": "carto-positron",
        "center": {"lon": -98, "lat": 33},
        "zoom": 2.5,
        "layers": [
            {
                "source": shapely.geometry.box(
                    *gdf3.loc[box].geometry.bounds
                ).__geo_interface__,
                "type": "fill",
                "color": "blue",
                "opacity": 0.1,
            }
            for box in t.keys()
        ]
        + [
            {
                "source": gdf_m.geometry.__geo_interface__,
                "type": "line",
                "color": "blue",
                "line": {"width": 1},
            }
        ],
    },
    margin={"l": 0, "r": 0, "t": 0, "b": 0},
)