【问题标题】:Plotly create inset choropleth (Mapbox ideally) of Alaska and Hawaii绘制阿拉斯加和夏威夷的插图(理想情况下为 Mapbox)
【发布时间】:2022-01-10 20:19:21
【问题描述】:

有没有办法创建额外的等值线(最好是 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)

【问题讨论】:

    标签: python plotly mapbox plotly-python


    【解决方案1】:
    • 可以通过ma​​pbox实现
    • 关键概念是修改几何以满足您的布局要求。因此已经完成https://shapely.readthedocs.io/en/stable/manual.html#affine-transformations 移动阿拉斯加夏威夷
    • 还发现 阿拉斯加 几何形状会出现问题,因为它跨越了日期变更线。因此,变换后的几何图形也被剪裁了
    • 添加以表明几何图形已被操纵
    • 包括海洋边界以演示如何将其扩展到其他几何形状
    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},
    )
    

    【讨论】:

    • 谢谢!我想唯一的缺点是这种方法不会移动底层的 Mapbox 层,对吧?我遇到的问题是我将水砖投射到我的痕迹上,以便在海岸线上获得更精细的细节。任何不移动水层的轨迹移动都会丢失该细节。你以前遇到过这个问题吗?
    • 这种方法适用于所有几何图形,您需要以相同的方式移动关联的几何图形。即,如果阿拉斯加有定义的水几何形状,则将其移至。如您所见,color 可以与移动的阿拉斯加和夏威夷几何图形一起正常工作
    • 已经扩展了海洋几何图形来展示它是如何工作的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多