在 Plotly 的图例中将每个 "graph dimension" 分组

Group each "graph dimension" in the legend of Plotly

我想在 plotly.express 生成的 Plotly“标准图例”中添加每个“图表维度”,将此类特征的所有痕迹组合在一起。由于从前面的描述中可能很难理解我想做什么,所以让我举个例子。我有一个使用以下行生成绘图的代码:

px.line(
    df,
    x = 'x values',
    y = 'y values',
    color = 'Device specs', # This is what I call "color dimension".
    symbol = 'Device', # This is what I call "symbol dimension".
    line_dash = 'Contact type', # This is what I call "line_dash dimension".
)

情节看起来像这样(对于某些特定数据):

我想在这个图例下方为每个“维度”添加一个图例,即 color 的一个图例,将每种颜色的所有痕迹分组,一个用于 symbol,一个用于line_dash,像这样:

并且,如果可能的话,如果我点击,例如contact=dot 它将所有虚线痕迹的可见性设置在一起。

Plotly Express 可以做到这一点吗?

  • 生成具有您已定义的特征的数据框
  • 创建核心人物很简单 - 只需使用您的代码
  • 为图例添加尺寸。这使用图例显示图形中所有痕迹的核心概念。因此要扩展图例,需要额外的痕迹
  • 跟踪是在 列表 理解中构建的,其参数符合您的要求。这些迹线被特意赋予了一个 y 值,不会包含在 y 轴范围
import pandas as pd
import numpy as np
import plotly.express as px

SIZE = 10
# generate a dataset with all required attributes
df = pd.DataFrame(
    {
        "x values": np.tile(np.linspace(0, SIZE - 1, SIZE), SIZE),
        "y values": np.sort(np.random.uniform(1, 1000, SIZE ** 2)),
        "Device": np.concatenate(
            [np.full(SIZE, np.random.choice([52, 36, 34], 1)) for _ in range(SIZE)]
        ),
        "Contact type": np.concatenate(
            [np.full(SIZE, np.random.choice(["dot", "ring"], 1)) for _ in range(SIZE)]
        ),
        "Device specs": np.concatenate(
            [
                np.full(SIZE, np.random.choice(["laptop", "tablet", "console"], 1))
                for _ in range(SIZE)
            ]
        ),
    }
)
df.loc[df["x values"].eq(SIZE - 1), "y values"] = np.nan

# build the standard figure
fig = px.line(
    df,
    x="x values",
    y="y values",
    color="Device specs",  # This is what I call "color dimension".
    symbol="Device",  # This is what I call "symbol dimension".
    line_dash="Contact type",  # This is what I call "line_dash dimension".
)

# build additional traces for items wanted in legend
legend_traces = [
    px.line(
        df,
        x="x values",
        y=np.full(len(df), -1000),
        **param["px"],
    ).update_traces(**param["lg"], legendgroup=str(param["px"]))
    for param in [
        {"px": {"color": "Device specs"}, "lg": {"legendgrouptitle_text": "Spec"}},
        {"px": {"symbol": "Device"}, "lg": {"legendgrouptitle_text": "Device"}},
        {
            "px": {"line_dash": "Contact type"},
            "lg": {"legendgrouptitle_text": "Contact type"},
        },
    ]
]

for t in legend_traces:
    fig.add_traces(t.data)

# hide the dummy traces for extra legend entries (given y-value of -1000)
fig.update_yaxes(range=[0, df["y values"].max()])
fig.update_layout(height=500)