首页 > 解决方案 > 如何使用 updatemenues 优化绘图图?

问题描述

所以,我一直在使用 plotly,最近开始使用 updatemenus 方法来添加按钮。我已经用它创建了几个图表,但我发现很难找到一种有效的方法来更新 updatemenus 部分中的 args 部分。我有一个比示例更大的数据框,但它是相同的想法,所以我有 df:

name    unaregate   value   age
input1  in11           2    0
input1  in11           0    1
input1  in11           2    2
input1  in11           3    3
input1  in11           1    4
input1  in12           1    0
input1  in12           3    1
input1  in12           4    2
input1  in12           2    3
input1  in12           3    4
input1  in13           0    0
input1  in13           2    1
input1  in13           4    2
input1  in13           2    3
input1  in13           3    4
input2  in21           3    0
input2  in21           4    1
input2  in21           2    2
input2  in21           1    3
input2  in21           3    4
input2  in22           4    0
input2  in22           0    1
input2  in22           2    2
input2  in22           4    3
input2  in22           0    4
input2  in23           3    0
input2  in23           4    1
input2  in23           0    2
input2  in23           4    3
input2  in23           2    4
input3  in31           3    0
input3  in31           4    1
input3  in31           2    2
input3  in31           4    3
input3  in31           1    4
input3  in32           4    0
input3  in32           0    1
input3  in32           0    2
input3  in32           2    3
input3  in32           1    4
input3  in33           2    0
input3  in33           3    1
input3  in33           0    2
input3  in33           3    3
input3  in33           4    4
input3  in34           2    0
input3  in34           2    1
input3  in34           3    2
input3  in34           4    3
input3  in34           3    4

这是创建与此类似的数据框的一种超级低效的方法:

df = pd.DataFrame(index=range(5),columns=range(1))
df12 = pd.DataFrame(index=range(5),columns=range(1))
df13 = pd.DataFrame(index=range(5),columns=range(1))
df21 = pd.DataFrame(index=range(5),columns=range(1))
df22 = pd.DataFrame(index=range(5),columns=range(1))
df23 = pd.DataFrame(index=range(5),columns=range(1))
df31 = pd.DataFrame(index=range(5),columns=range(1))
df32 = pd.DataFrame(index=range(5),columns=range(1))
df33 = pd.DataFrame(index=range(5),columns=range(1))
df34 = pd.DataFrame(index=range(5),columns=range(1))
df["name"] = "input1"
df["unaregate"] = "in11"
df["value"] = np.random.randint(0,5, size=len(df))
df["age"] = range(0,len(df))
​
df12["name"] = "input1"
df12["unaregate"] = "in12"
df12["value"] = np.random.randint(0,5, size=len(df12))
df12["age"] = range(0,len(df12))
​
df13["name"] = "input1"
df13["unaregate"] = "in13"
df13["value"] = np.random.randint(0,5, size=len(df13))
df13["age"] = range(0,len(df13))
​
df21["name"] = "input2"
df21["unaregate"] = "in21"
df21["value"] = np.random.randint(0,5, size=len(df21))
df21["age"] = range(0,len(df21))
​
df22["name"] = "input2"
df22["unaregate"] = "in22"
df22["value"] = np.random.randint(0,5, size=len(df22))
df22["age"] = range(0,len(df22))
​
df23["name"] = "input2"
df23["unaregate"] = "in23"
df23["value"] = np.random.randint(0,5, size=len(df23))
df23["age"] = range(0,len(df23))
​
df31["name"] = "input3"
df31["unaregate"] = "in31"
df31["value"] = np.random.randint(0,5, size=len(df31))
df31["age"] = range(0,len(df31))
​
df32["name"] = "input3"
df32["unaregate"] = "in32"
df32["value"] = np.random.randint(0,5, size=len(df32))
df32["age"] = range(0,len(df32))
​
df33["name"] = "input3"
df33["unaregate"] = "in33"
df33["value"] = np.random.randint(0,5, size=len(df33))
df33["age"] = range(0,len(df33))
​
df34["name"] = "input3"
df34["unaregate"] = "in34"
df34["value"] = np.random.randint(0,5, size=len(df34))
df34["age"] = range(0,len(df34))
frames = [df,df12,df13,df21,df22,df23,df31,df32,df33,df34]
df = pd.concat(frames)
df = df.drop([0],axis=1)

这是我为情节采用的方法:

fig = go.Figure()
names = df.name.unique()
for i in names:
    db = df[df["name"]==i]
    uni = db.unaregate.unique()
    for f in uni:
        fig.add_trace(go.Scatter(
            x=db[db.unaregate==f].age,
            y=db[db.unaregate==f].value,
        connectgaps=False ,visible=False,
        mode='lines', legendgroup=f,name=f))
fig.update_layout(
    template="simple_white",
    xaxis=dict(title_text="age"),
    yaxis=dict(title_text="Value"),
    width=1000, height = 600
)
fig.update_layout(
    updatemenus=[
        dict(
#             type="buttons",
#             direction="down",
            active=0,
#             x=0.7,
#             y=1.2,
#             showactive=True,
            buttons=list(
                [ dict(
                        label="Select name",
                        method="update",
                        args=[
                            {"visible": [False,False,False,
                                         False,False,False,
                                         False,False,False,False
                                         ]},
                        ],
                    ),
                 dict(
                        label="input 1",
                        method="update",
                        args=[
                            {"visible": [True,True,True,
                                         False,False,False,
                                         False,False,False,False
                                         ]},
                        ],
                    ),
                 dict(
                        label="input 2",
                        method="update",
                        args=[
                            {"visible": [False,False,False,
                                         True,True,True,
                                         False,False,False,False
                                         ]},
                        ],
                    ),
                 dict(
                        label="input 3",
                        method="update",
                        args=[
                            {"visible": [False,False,False,
                                         False,False,False,
                                         True,True,True,True
                                         ]},
                        ],
                    ),
]
            ),
#             showactive=True,
        )
    ]
)
fig

在部分是真假是,有没有办法在循环中添加它们,所以当我有超过五十行时,我不必添加超过 50 个真假?欢迎任何帮助我只想能够为任何类型的类似数据运行此脚本,并且数据的长度无关紧要。

标签: pythonpandasdataframegraphplotly

解决方案


  • 可以简化数据框的创建。使用带有列表推导的pandas构造函数功能
  • 使用plotly express创建图形/轨迹要简单得多
  • 核心问题——动态创建可见列表
    • 如果跟踪在同名组中,则它是可见的。这里按钮名称对应于跟踪的名称级别
import pandas as pd
import numpy as np
import plotly.express as px

df = (
    pd.DataFrame(
        [
            {
                "name": f"input{a}",
                "unaregate": f"in{a}{b}",
                "value": np.random.randint(0, 5, 5),
            }
            for a in range(1, 4)
            for b in range(1, 4)
        ]
    )
    .explode("value")
    .pipe(lambda d: d.assign(age=np.random.randint(0, 5, len(d))))
)

# get valid combinations that will create traces
combis = df.groupby(["name","unaregate"]).size().index

# for this example - it's far simpler to use plotly express to create traces
fig = px.line(df, x="age", y="value", color="unaregate").update_traces(visible=False)

# use list comprehesions to populate visible lists
fig.update_layout(
    updatemenus=[
        {
            "active": 0,
            "buttons": [
                {
                    "label": "Select name",
                    "method": "update",
                    "args": [{"visible": [False for t in fig.data]}],
                }
            ]
            + [
                {
                    "label": n,
                    "method": "update",
                    "args": [{"visible": [n == t for t in combis.get_level_values(0)]}],
                }
                for n in combis.get_level_values(0).unique()
            ],
        }
    ],
    template="simple_white"
)

推荐阅读