使用下拉菜单在 mapbox 布局中编辑 "layers" 属性(Plotly,Python)

Edit "layers" property in mapbox layout by using dropdown menu (Plotly, Python)

我正在尝试使用 Plotly 创建一个 Mapbox 图表。在创建轨迹并使用下拉列表选择要显示的轨迹方面一切顺利。

但是,我也在尝试在地图上绘制图层。当我在不使用下拉菜单的情况下执行此操作时,一切正常。但是当我尝试使用“updatemenus”功能将图层添加为选项时,图层将不会显示。

迹线和基本布局是这样创建的并且工作正常(有点简化,通常在循环中):

fig_dict = {
    "data": [],
    "layout": {}
}

data = dict(type='scattermapbox',
                lat=dft['lat'],
                lon=dft['lon'],
                mode='markers',
                marker=dict(size=3,
                            color=dft['Color']),
                showlegend=False,
                 )
                                                                                                          
        fig_dict["data"].append(data)

layout = dict(legend=dict(orientation="h",yanchor="bottom",y=1.02,xanchor="right",x=1),
              mapbox= dict(accesstoken=mapboxtoken,
                           center=dict(lat=52.1436,lon=5.383),
                           style="dark", 
                           zoom=6.25)
            )


fig_dict["layout"] = layout    

图层是这样创建的(与轨迹在同一个循环中):

        R = stand.iloc[0]['Distance in KM']/66.8
        R2 = (3/5)*R
        
        center_lon = dft.iloc[0,9]
        center_lat = dft.iloc[0,8]
        t = np.linspace(0, 2*pi, 100)
        circle_lon =center_lon + R*cos(t)
        circle_lat =center_lat +  R2*sin(t)
        
        
        coords=[]
        for lo, la in zip(list(circle_lon), list(circle_lat)):
            coords.append([lo, la]) 
        
        layer=dict(sourcetype = 'geojson',
                      source={ "type": "Feature",
                              "geometry": {"type": "LineString",
                                          "coordinates": coords
                                          }
                            },
                      templateitemname=dft.iloc[0,2],
                      visible=True,
                      color=  dft.iloc[0,13],
                      type = 'fill',   
                      opacity=0.5,
                      fill = dict(outlinecolor= 'white')
                    )
        layers.append(layer)

最后 updatemenus 部分的结构如下(基于在循环中创建的多个跟踪):

fig_dict["layout"]["updatemenus"] = [dict(
            active=0,
            buttons=list([
                dict(label="Q3",
                     method="update",
                     args=[{"visible": [True, False],
                           {'title':'test1','mapbox':{'layers':layer1}}
                           ]),
                dict(label="Q4",
                     method="update",
                     args=[{"visible": [False, True],
                            {'title':'test2','mapbox':{'layers':layer2}}
                           ])
                    ])
                    )]

fig = go.Figure(fig_dict)

我尝试了很多不同的方法来构建“updatemenus”,但都没有成功。以上是我最后的尝试。就像我说的,我已经减少了一些原始代码以使其更整洁(我对此很陌生),但要点是相同的。如果有完整代码更好,我会提供!

编辑:

数据如下:

我有一个数据集,脚本循环通过该数据集为地图上的所有单个位置创建轨迹。每个 ID(约 3k)在地图上都有自己的点。颜色对应位置(dft):

    id  Location    lat lon
0   1   Leeuwarden  53.3238509  6.864812147
1   2   Leeuwarden  53.20375983 5.806213178
2   3   Enschede    52.28652282 6.845358477
3   4   Leeuwarden  53.18575506 5.833720622
4   5   Breda   51.81459037 5.851585979
5   6   Leeuwarden  53.20965451 5.777285517
6   7   Groningen   53.32373805 6.695864432
7   8   Leeuwarden  52.95470465 5.919419689
8   9   Leeuwarden  52.82104961 5.96997389
9   10  Enschede    52.50522699 6.612134113
10  11  Leeuwarden  53.15089124 5.844570929

然后根据此数据集(站)在地图上为每个位置创建一个图层:

    Location    lon lat Average distance in KM
0   Breda       4.234844574 51.45673726 15.1
1   Enschede    6.123570731 52.23459517 71.3
2   Groningen   6.234960418 53.12302082 22.2
3   Leeuwarden  5.795739613 53.19886105 30.0
  • 根据示例数据和代码,生成了图形。我没有在数据中的任何地方找到 quarter,正如 updatemenus
  • 中所暗示的那样
  • 已使用 geopandas 帮助计算圆的几何形状
  • 由此创建了一个 dict,它是 Location
  • 的圆形多边形
  • 最后 updatemenus 我确实发现你不能只更改 layers,它需要完成 mapbox 设置。即 stylezoomcenterlayers
import numpy as np
import pandas as pd
import geopandas as gpd
import requests, io
import plotly.express as px

dft = pd.read_csv(io.StringIO("""    id  Location    lat lon
0   1   Leeuwarden  53.3238509  6.864812147
1   2   Leeuwarden  53.20375983 5.806213178
2   3   Enschede    52.28652282 6.845358477
3   4   Leeuwarden  53.18575506 5.833720622
4   5   Breda   51.81459037 5.851585979
5   6   Leeuwarden  53.20965451 5.777285517
6   7   Groningen   53.32373805 6.695864432
7   8   Leeuwarden  52.95470465 5.919419689
8   9   Leeuwarden  52.82104961 5.96997389
9   10  Enschede    52.50522699 6.612134113
10  11  Leeuwarden  53.15089124 5.844570929"""), sep="\s+")


stock = pd.read_csv(
    io.StringIO(
        """    Location    lon lat "Average distance in KM"
0   Breda       4.234844574 51.45673726 15.1
1   Enschede    6.123570731 52.23459517 71.3
2   Groningen   6.234960418 53.12302082 22.2
3   Leeuwarden  5.795739613 53.19886105 30.0"""
    ),
    sep="\s+",
)

# calculate geometry of areas with appropriate radius
stock = gpd.GeoDataFrame(
    stock, geometry=gpd.points_from_xy(stock["lon"], stock["lat"]), crs="epsg:4326"
)

utm = stock.estimate_utm_crs()
stock = gpd.GeoDataFrame(
    stock,
    geometry=stock.to_crs(utm).apply(
        lambda r: r["geometry"].buffer(r["Average distance in KM"] * 1000), axis=1
    ),
    crs=utm,
).to_crs("epsg:4326")



# create scatter of points
fig = px.scatter_mapbox(
    dft, lat="lat", lon="lon", color="Location"
).update_layout(
    mapbox={"style": "carto-positron", "zoom": 5},
    margin={"t": 25, "b": 0, "l": 0, "r": 0},
)


# build a dict of layers that corresponds to traces
layers = {
    t.name: {
        "source": stock.loc[stock["Location"].eq(t.name), "geometry"].__geo_interface__,
        "type": "line",
        "color": t.marker.color,
    }
    for t in fig.data
}

# # add circles as layers...
fig = fig.update_layout(mapbox_layers=list(layers.values()))

# # finally build menus...
fig.update_layout(
    updatemenus=[
        {
            "buttons": [
                {
                    "label": q,
                    "method": "update",
                    "args": [
                        {"visible": [t2.name == q or q == "All" for t2 in fig.data]},
                        {
                            "title": q,
                            "mapbox": {
                                "style": fig.layout.mapbox.style,
                                "center": fig.layout.mapbox.center,
                                "zoom": fig.layout.mapbox.zoom,
                                "layers": [layers[q]]
                                if q != "All"
                                else list(layers.values()),
                            },
                        },
                    ],
                }
                for q in stock["Location"].unique().tolist() + ["All"]
            ],
        }
    ]
)
fig

已选择位置

全部选中