使用下拉菜单在 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 设置。即 style、zoom、center 和 layers
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
已选择位置
全部选中
我正在尝试使用 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 设置。即 style、zoom、center 和 layers
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