【问题标题】:Multiple opacities and widths in Mapbox - Plotly for PythonMapbox 中的多个不透明度和宽度 - Plotly for Python
【发布时间】:2022-01-03 11:38:35
【问题描述】:

这是一个源自上一个问题的问题,可以在这里找到Multiple opacities in Mapbox - Plotly for Python

我遇到了一些问题,即 Mapbox 地图上的多条轨迹有多个不透明度,每个不透明度都与数据框的特定值相关联。

在遵循 Rob 的有用答案(参见上面的链接),这导致了第一个主题的解决方案之后,我发现自己遇到了另一个问题,因为我现在想对他的代码进行一些改动。

虽然我的第一种方法是仅对迹线的不透明度进行更改,但我现在需要对不透明度每条迹线的宽度进行更改,将它们中的每一个对应到特定数据帧上的不同值。

我继续复制粘贴 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 部分中,因为我需要 类似的东西双重切割,但找不到正确执行此操作的方法.

我还设法通过以下方式创建了熊猫系列:

widths = pd.cut(df.["size"], bins=BINS_FOR_WIDTH, labels=width_a)

并迭代该系列,但得到与以前相同的结果(过多的痕迹)。

为了强调和澄清我自己,我不需要只有多个不透明度或多个宽度,但我需要同时在同时,这就是给我带来一些麻烦的原因。

我非常感谢任何帮助

【问题讨论】:

    标签: python pandas plotly mapbox


    【解决方案1】:
    • 假设您使用同一列来定义 widthopacity 您只需要一个循环
    • 对于宽度我认为线性空间比几何空间好,因此创建了width_a如下
    • opacitywidth 都将同步移动,因为它通过相同数量的 bin 切割同一列

    不包括数据源的解决方案

    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},
    )
    
    

    【讨论】:

    • 哇!不知道可以将两个pd.cut 参数传递给df.groupby。它工作得非常好。感谢您的所有帮助!
    猜你喜欢
    • 2022-01-17
    • 2021-07-26
    • 2018-04-13
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多