【问题标题】:Edit "layers" property in mapbox layout by using dropdown menu (Plotly, Python)使用下拉菜单(Plotly,Python)在 mapbox 布局中编辑“图层”属性
【发布时间】:2022-01-12 12:12:07
【问题描述】:

我正在尝试使用 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)

我尝试了很多不同的方法来构建“更新菜单”,但都没有成功。以上是我最后一次尝试。就像我说的那样,我已经将我的原始代码减少了一点,以保持它更整洁(我对此很陌生),但基本要素是相同的。如果有完整的代码更好,我会提供!

编辑:

数据如下:

我有一个数据集,脚本循环通过该数据集为地图上的所有单独位置创建跟踪。每个 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

【问题讨论】:

    标签: python plotly mapbox dropdown layer


    【解决方案1】:
    • 从示例数据和代码中,生成了图形。在 updatemenus 中,我没有在数据中找到 季度
    • 已使用 geopandas 帮助计算圆的几何形状
    • 由此创建了一个 dict,它们是按位置划分的圆形多边形
    • 最后updatemenus我发现你不能只改变layers,它需要完成ma​​pbox设置。即 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
    

    已选择位置

    全部选中

    【讨论】:

    • 感谢您的精心回复!我将尝试看看我是否可以调整我的方法以使用 geopandas 并按照你的方式进行情节表达。
    • 如果您使用 dft 中的一些示例行更新您的问题,我可以将其用作起始几何。我不清楚使用什么/为什么使用 stand 数据框。它只是半径大小的常数吗?
    • 我已经添加了我的数据集示例,所以我希望这能让事情更清楚。我认为我的代码的主要问题是我如何设置更新菜单。我知道您是如何做到的,将图层添加到整体布局中,然后通过菜单使它们可选择。这是我将用我自己的代码尝试的东西。我已经调整了您为我自己的数据提供的代码,并且仅适用于图层,因此如果我无法调整自己的代码,我将使用您的代码,看看是否可以将它附加到所有数据点。再次感谢!
    • 已更新为使用您的示例数据。圈子现在基于 stock 中的数据
    • 我非常接近解决方案。下拉菜单现在有效(基于季度,而不是位置)。因此,各个点和层会改变我想要的方式。我唯一苦苦挣扎的是,我希望图层的颜色与不同位置对应的颜色与轨迹相同,但下拉菜单只能选择季度。这意味着图层字典必须只有两个可选组。但是,如果我在那里添加颜色属性,所有圆圈都有相同的颜色。我正在寻找一种将颜色属性添加到功能部分的方法,但遇到了麻烦
    猜你喜欢
    • 2022-07-06
    • 1970-01-01
    • 2019-09-09
    • 2016-02-03
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    相关资源
    最近更新 更多