Mapbox 中的多个不透明度和宽度 - Plotly for Python
Multiple opacities and widths in Mapbox - Plotly for Python
这是从前一个问题衍生出来的问题,可以在这里找到:
我遇到了一些关于在 Mapbox 地图上为多个轨迹设置多个不透明度的问题,每个不透明度都与数据框的特定值相关联。
在遵循了 Rob 的有用答案(参见上文 link),从而找到了第一个主题的解决方案之后,我发现自己陷入了另一个问题,因为我现在想对他的代码进行一些改动。
虽然我的第一个方法是只改变痕迹的不透明度,但我现在需要 both 不透明度的变化 and 每条轨迹的宽度,对应于特定数据帧上的不同值。
我继续复制粘贴 Rob 回答的第一部分,他在其中声明了一些函数并创建了一个数据框:
import requests
import geopandas as gpd
import plotly.graph_objects as go
import itertools
import numpy as np
import pandas as pd
from pathlib import Path
# get geometry of london underground stations
gdf = gpd.GeoDataFrame.from_features(
requests.get(
"https://raw.githubusercontent.com/oobrien/vis/master/tube/data/tfl_stations.json"
).json()
)
# limit to zone 1 and stations that have larger number of lines going through them
gdf = gdf.loc[gdf["zone"].isin(["1","2","3","4","5","6"]) & gdf["lines"].apply(len).gt(0)].reset_index(
drop=True
).rename(columns={"id":"tfl_id", "name":"id"})
# wanna join all valid combinations of stations...
combis = np.array(list(itertools.combinations(gdf.index, 2)))
# generate dataframe of all combinations of stations
gdf_c = (
gdf.loc[combis[:, 0], ["geometry", "id"]]
.assign(right=combis[:, 1])
.merge(gdf.loc[:, ["geometry", "id"]], left_on="right", right_index=True, suffixes=("_start_station","_end_station"))
)
gdf_c["lat_start_station"] = gdf_c["geometry_start_station"].apply(lambda g: g.y)
gdf_c["long_start_station"] = gdf_c["geometry_start_station"].apply(lambda g: g.x)
gdf_c["lat_end_station"] = gdf_c["geometry_end_station"].apply(lambda g: g.y)
gdf_c["long_end_station"] = gdf_c["geometry_end_station"].apply(lambda g: g.x)
gdf_c = gdf_c.drop(
columns=[
"geometry_start_station",
"right",
"geometry_end_station",
]
).assign(number_of_journeys=np.random.randint(1,10**5,len(gdf_c)))
gdf_c
f = Path.cwd().joinpath("SO.csv")
gdf_c.to_csv(f, index=False)
# there's an requirement to start with a CSV even though no sample data has been provided, now we're starting with a CSV
df = pd.read_csv(f)
# makes use of ravel simpler...
df["none"] = None
我的特殊问题从这里开始:当尝试创建两个“循环”(一个用于不透明度,一个用于宽度)时,我认为我可以执行以下操作:
BINS_FOR_OPACITY=10
opacity_a = np.geomspace(0.001,1, BINS_FOR_OPACITY)
BINS_FOR_WIDTH=10
width_a = np.geomspace(1,3, BINS_FOR_WIDTH)
fig = go.Figure()
# Note the double "for" statement that follows
for opacity, d in df.groupby(pd.cut(df["number_of_journeys"], bins=BINS_FOR_OPACITY, labels=opacity_a)):
for width, d in df.groupby(pd.cut(df["number_of_journeys"], bins=BINS_FOR_WIDTH, labels=width_a)):
fig.add_traces(
go.Scattermapbox(
name=f"{d['number_of_journeys'].mean():.2E}",
lat=np.ravel(d.loc[:,[c for c in df.columns if "lat" in c or c=="none"]].values),
lon=np.ravel(d.loc[:,[c for c in df.columns if "long" in c or c=="none"]].values),
line_width=width
line_color="blue",
opacity=opacity,
mode="lines+markers",
)
)
[Rob 的原始答案只有第一个 for
语句,没有第二个语句]
然而,以上显然不起作用,因为它产生的痕迹比它应该做的多得多(我真的无法解释为什么,但我想这可能是因为两个 for
语句)。
我突然想到 pd.cut
部分可能隐藏了某种解决方案,因为我需要 类似 的双切,但不能找到正确的方法。
我还通过以下方式创建了一个 Pandas 系列:
widths = pd.cut(df.["size"], bins=BINS_FOR_WIDTH, labels=width_a)
并迭代该系列,但得到了与以前相同的结果(痕迹过多)。
为了强调和澄清我自己,我不需要只有多个不透明度或多个宽度,但我需要两者[=51] =] 和 同时 ,这让我有些麻烦。
非常感谢任何帮助
- 假设您使用同一列来定义 width 和 opacity 您只需要一个循环
- for width 我认为线性 space 优于几何 space,因此创建了
width_a
如下
opacity
和 width
将同步移动,因为它按相同数量的 bins 切割同一列
排除数据来源的解决方案
BINS = 10
opacity_a = np.geomspace(0.001, 1, BINS)
width_a = np.linspace(0.1, 2, BINS)
fig = go.Figure()
for (opacity, width), d in df.groupby(
[
pd.cut(df["number_of_journeys"], bins=BINS, labels=opacity_a),
pd.cut(df["number_of_journeys"], bins=BINS, labels=width_a),
]
):
fig.add_traces(
go.Scattermapbox(
name=f"{d['number_of_journeys'].mean():.2E}",
lat=np.ravel(
d.loc[:, [c for c in df.columns if "lat" in c or c == "none"]].values
),
lon=np.ravel(
d.loc[:, [c for c in df.columns if "long" in c or c == "none"]].values
),
line_color="blue",
line_width=width,
opacity=opacity,
mode="lines+markers",
)
)
fig.update_layout(
mapbox={
"style": "carto-positron",
"center": {"lat": 51.520214996769255, "lon": -0.097792388774743},
"zoom": 9,
},
margin={"l": 0, "r": 0, "t": 0, "b": 0},
)
这是从前一个问题衍生出来的问题,可以在这里找到:
我遇到了一些关于在 Mapbox 地图上为多个轨迹设置多个不透明度的问题,每个不透明度都与数据框的特定值相关联。
在遵循了 Rob 的有用答案(参见上文 link),从而找到了第一个主题的解决方案之后,我发现自己陷入了另一个问题,因为我现在想对他的代码进行一些改动。
虽然我的第一个方法是只改变痕迹的不透明度,但我现在需要 both 不透明度的变化 and 每条轨迹的宽度,对应于特定数据帧上的不同值。
我继续复制粘贴 Rob 回答的第一部分,他在其中声明了一些函数并创建了一个数据框:
import requests
import geopandas as gpd
import plotly.graph_objects as go
import itertools
import numpy as np
import pandas as pd
from pathlib import Path
# get geometry of london underground stations
gdf = gpd.GeoDataFrame.from_features(
requests.get(
"https://raw.githubusercontent.com/oobrien/vis/master/tube/data/tfl_stations.json"
).json()
)
# limit to zone 1 and stations that have larger number of lines going through them
gdf = gdf.loc[gdf["zone"].isin(["1","2","3","4","5","6"]) & gdf["lines"].apply(len).gt(0)].reset_index(
drop=True
).rename(columns={"id":"tfl_id", "name":"id"})
# wanna join all valid combinations of stations...
combis = np.array(list(itertools.combinations(gdf.index, 2)))
# generate dataframe of all combinations of stations
gdf_c = (
gdf.loc[combis[:, 0], ["geometry", "id"]]
.assign(right=combis[:, 1])
.merge(gdf.loc[:, ["geometry", "id"]], left_on="right", right_index=True, suffixes=("_start_station","_end_station"))
)
gdf_c["lat_start_station"] = gdf_c["geometry_start_station"].apply(lambda g: g.y)
gdf_c["long_start_station"] = gdf_c["geometry_start_station"].apply(lambda g: g.x)
gdf_c["lat_end_station"] = gdf_c["geometry_end_station"].apply(lambda g: g.y)
gdf_c["long_end_station"] = gdf_c["geometry_end_station"].apply(lambda g: g.x)
gdf_c = gdf_c.drop(
columns=[
"geometry_start_station",
"right",
"geometry_end_station",
]
).assign(number_of_journeys=np.random.randint(1,10**5,len(gdf_c)))
gdf_c
f = Path.cwd().joinpath("SO.csv")
gdf_c.to_csv(f, index=False)
# there's an requirement to start with a CSV even though no sample data has been provided, now we're starting with a CSV
df = pd.read_csv(f)
# makes use of ravel simpler...
df["none"] = None
我的特殊问题从这里开始:当尝试创建两个“循环”(一个用于不透明度,一个用于宽度)时,我认为我可以执行以下操作:
BINS_FOR_OPACITY=10
opacity_a = np.geomspace(0.001,1, BINS_FOR_OPACITY)
BINS_FOR_WIDTH=10
width_a = np.geomspace(1,3, BINS_FOR_WIDTH)
fig = go.Figure()
# Note the double "for" statement that follows
for opacity, d in df.groupby(pd.cut(df["number_of_journeys"], bins=BINS_FOR_OPACITY, labels=opacity_a)):
for width, d in df.groupby(pd.cut(df["number_of_journeys"], bins=BINS_FOR_WIDTH, labels=width_a)):
fig.add_traces(
go.Scattermapbox(
name=f"{d['number_of_journeys'].mean():.2E}",
lat=np.ravel(d.loc[:,[c for c in df.columns if "lat" in c or c=="none"]].values),
lon=np.ravel(d.loc[:,[c for c in df.columns if "long" in c or c=="none"]].values),
line_width=width
line_color="blue",
opacity=opacity,
mode="lines+markers",
)
)
[Rob 的原始答案只有第一个 for
语句,没有第二个语句]
然而,以上显然不起作用,因为它产生的痕迹比它应该做的多得多(我真的无法解释为什么,但我想这可能是因为两个 for
语句)。
我突然想到 pd.cut
部分可能隐藏了某种解决方案,因为我需要 类似 的双切,但不能找到正确的方法。
我还通过以下方式创建了一个 Pandas 系列:
widths = pd.cut(df.["size"], bins=BINS_FOR_WIDTH, labels=width_a)
并迭代该系列,但得到了与以前相同的结果(痕迹过多)。
为了强调和澄清我自己,我不需要只有多个不透明度或多个宽度,但我需要两者[=51] =] 和 同时 ,这让我有些麻烦。
非常感谢任何帮助
- 假设您使用同一列来定义 width 和 opacity 您只需要一个循环
- for width 我认为线性 space 优于几何 space,因此创建了
width_a
如下 opacity
和width
将同步移动,因为它按相同数量的 bins 切割同一列
排除数据来源的解决方案
BINS = 10
opacity_a = np.geomspace(0.001, 1, BINS)
width_a = np.linspace(0.1, 2, BINS)
fig = go.Figure()
for (opacity, width), d in df.groupby(
[
pd.cut(df["number_of_journeys"], bins=BINS, labels=opacity_a),
pd.cut(df["number_of_journeys"], bins=BINS, labels=width_a),
]
):
fig.add_traces(
go.Scattermapbox(
name=f"{d['number_of_journeys'].mean():.2E}",
lat=np.ravel(
d.loc[:, [c for c in df.columns if "lat" in c or c == "none"]].values
),
lon=np.ravel(
d.loc[:, [c for c in df.columns if "long" in c or c == "none"]].values
),
line_color="blue",
line_width=width,
opacity=opacity,
mode="lines+markers",
)
)
fig.update_layout(
mapbox={
"style": "carto-positron",
"center": {"lat": 51.520214996769255, "lon": -0.097792388774743},
"zoom": 9,
},
margin={"l": 0, "r": 0, "t": 0, "b": 0},
)