yaxis 可以动态添加到 graph_objects 布局中吗?

Can yaxis be dynamically added into an graph_objects Layout in plotly?

在我目前正在接受的实践培训中,有一个 python 脚本可以读取 CSV 文件并针对该文件的 selected 列进行绘图。然而 headers 的 selection 是硬编码的,所以如果有人想使用脚本,他们必须操纵代码。我的任务是让它变得动态,e。 G。脚本的用户可以通过控制台 select 任意数量的列 (argparse),脚本会自动创建轨迹,创建布局,将两者添加到图形并将其导出到 html 文件。

除了布局部分,我已经设法完成了所有这些。在脚本的当前(硬编码)状态下,有这些参数传递给 graph_objects.Layout 函数:

 layout = go.Layout(title=inFile,
                       plot_bgcolor='rgb(230, 230,230)', showlegend=True,
                       yaxis=dict(
                           title=df.columns[y1graph] # Note: 'ygraph' contains the index of the column
                       ),
                       yaxis2=dict(
                            title=df.columns[y2graph],
                            side='right',
                            overlaying='y'
                       ),
                       yaxis3=dict(
                            title=df.columns[y3graph],
                            side='right',
                            overlaying='y'
                       )
                    )

不幸的是,我都没有找到一种方法来使所有这些都动态化,因此“yaxis”参数是根据 selected 列的数量添加的。我也没有找到一种方法来为图表添加标题,使它们相互重叠并像 go.Layout 一样将它们放在右侧。当然有一种方法可以用 plotly express 添加标题,但是对于 overlayingside 参数,它对我来说有点不一样。

有什么想法吗?

请注意:这是我在 Whosebug 上的第一个问题,所以如果我做错了什么,请指教!另外,如果我遗漏了重要信息,请告诉我。

  • 模拟一个 CSV,一个包含 20 列的数据框
  • 模拟用户选择要绘制的列(随机抽取 20 列中的 4 列)
  • 构建图形,为每个轨迹分配不同的 yaxis
  • 最后根据问题,动态配置y轴
import numpy as np
import plotly.express as px
import pandas as pd

# simulate a CSV, 20 columns...
df = pd.DataFrame(
    {
        chr(ord("A") + i): np.random.uniform(miny, miny + 200, 30)
        for i, miny in zip(range(20), np.random.randint(30, 3000, 20))
    }
)

# simulate user passing columns to plot...
cols = pd.Series(df.columns).sample(4).tolist()

# build figure with each trace using it's own yaxis
fig = px.line(df, y=cols).for_each_trace(
    lambda t: t.update(yaxis=f"y{cols.index(t.name)+1 if cols.index(t.name)>0 else ''}")
).update_layout(yaxis={"title":cols[0]})

# dynamically update yaxes...
fig.update_layout(
    {
        t.yaxis.replace("y", "yaxis"): {
            "title": t.name,
            "overlaying": "y",
            "side": "right",
            "position":1-(i/15)
        }
        for i,t in enumerate(fig.data)
        if t.yaxis != "y"
    }
).update_layout(xaxis={"domain":[0,1-(len(cols)*.05)]}) # give some space for additional yaxes