【问题标题】:How to correctly use the buttons for filtering data in Plotly如何在 Plotly 中正确使用按钮过滤数据
【发布时间】:2021-05-19 01:14:01
【问题描述】:

我有一个看起来像这样的数据框,其中“dni”是每一行的唯一 ID。我想在每个单独的 dni 的日期列中使用 plotly 堆叠条形图。

dni date col1 col2 col3
unique ids Datetime 5 7 1

我目前使用的代码如下所示:

fig = go.Figure()
buttons = []

for i,dni in enumerate(sorted(df_merged.dni.unique())):
  df = df_merged[df_merged['dni']==dni]
  for column in df.columns[3:-1]:
      fig.add_trace(go.Bar(
                        name = column,
                        x = pd.to_datetime(df.date.astype('str')),
                        y = df[column], 
                        visible = (i==0)
                      ))
  args = [False] * df_merged.dni.nunique()
  args[i] = True
    
  button = dict(label = dni,
                method = "update",
                args=[{"visible": args}])
      
  buttons.append(button)
        
fig.update_layout(
    updatemenus=[
        dict(
        type="dropdown",
        direction="down",
        buttons = buttons)
    ],
    barmode = "stack",)
fig.show()

这确实给了我一个带有过滤器的图,但它显示的数据总是不正确的。我正在努力理解我哪里出错了。它显示的唯一正确数据是第一个 dni,当我实际按下按钮时它也会改变。

谢谢!

编辑: 这是实际数据:

           id      date  bills  goalTrans  incomes  payments  savings
0  12345678901  2020-12    1.0        2.0      1.0       0.0      0.0
1  23456789012  2021-02    6.0        0.0      2.0       0.0      0.0
2  34567890123  2020-12    4.0        0.0      2.0       0.0      0.0
3  45678901234  2020-12    9.0        1.0      1.0       0.0      0.0
4  56789012345  2021-01    3.0        0.0      2.0       1.0      0.0

{'bills': {0: 1.0, 1: 6.0, 2: 4.0, 3: 9.0, 4: 3.0},
 'date': {0: '2020-12',
  1: '2021-02',
  2: '2020-12',
  3: '2020-12',
  4: '2021-01'},
 'id': {0: '12345678901',
  1: '23456789012',
  2: '34567890123',
  3: '45678901234',
  4: '56789012345'},
 'goalTrans': {0: 2.0, 1: 0.0, 2: 0.0, 3: 1.0, 4: 0.0},
 'incomes': {0: 1.0, 1: 2.0, 2: 2.0, 3: 1.0, 4: 2.0},
 'payments': {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 1.0},
 'savings': {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}}

【问题讨论】:

  • 请按照here的描述分享您的数据集样本
  • 更好。但这不是链接中描述的方法。
  • 完美。我加了一个赞成票 =)
  • 在字典中的示例数据框中,id 不应该是dni吗?
  • 我的建议对你有什么效果?

标签: python pandas plotly


【解决方案1】:

言归正传:

这可能是一个非常困难的问题,但是您错误地指定了 visible 属性,因为您的四个子集有三个跟踪,因此每个 arg 需要十二个规范,而不是您看起来的四个在您的设置中。

解决方案:

答案末尾的完整代码sn-p会产生下图,其中第一个按钮选项已经启动:

子集 1:

# 00820054194
   bills     date          dni  goalTrans  incomes  payments  savings
0    1.0  2020-12  00820054194        2.0      1.0       0.0      0.0

情节1:

如果您将Subset 1Plot 1 进行比较,您会发现到目前为止我们都很好。我将由您来验证所有子集,但这是最后一个来完成的:

子集 4:

# 04902852446
   bills     date          dni  goalTrans  incomes  payments  savings
3    9.0  2020-12  04902852446        1.0      1.0       0.0      0.0
4    3.0  2021-01  04902852446        0.0      2.0       1.0      0.0

情节4:

据我了解,这应该正是您正在寻找的。​​p>

详情:

在最后一次迭代中:

for i,dni in enumerate(sorted(df_merged.dni.unique())):

...args=[{"visible": args}] 中的args 看起来像这样:

[False, False, False, False, True]

这并没有涵盖您设置中的所有选项。你看,当method = 'update' 要查找并可能更改fig.data 中的visible 属性时,args=[{"visible": args}]) 中的args 会做什么,在你的情况下,它是一个带有 的元组十二 个元素,其中第一个看起来像这样:

(Bar({
     'name': 'goalTrans',
     'visible': True,
     'x': array([datetime.datetime(2020, 12, 1, 0, 0)], dtype=object),
     'y': array([2.])
 }),

为什么是 12?因为您有四个数据帧子集的三个go.Bar() 跟踪。因此,为了触发更新菜单的正确跟踪和正确选择选项(是的,按钮)的可见性,您不需要这样做:

[False, False, False, False, True]

但是这个:

[[True, True,True,False, False, False, False, False, False, False, False, False],
 [False, False, False, True, True, True, False, False, False, False, False, False],
 [False, False, False, False, False, False, True, True, True, False, False, False],
 [False, False, False, False, False, False, False, False, False, True, True, True]]

或者更确切地说,外部列表的每个元素都在迭代中:

for i, dni in enumerate(sorted(df_merged.dni.unique()[:])):

...像这样:

button =  dict(label=dni,
               method = 'restyle',
                args = ['visible',visibility[i]]
              )

...例如,visibility[2] 如下所示:

[False, False, False, False, False, False, False, False, False, True, True, True]

这就是下面完整代码中这个有点神秘的部分所需要处理的:

frames = len(df_merged.dni.unique())
bars = len(df.columns[3:-1])
scenarios = [list(s) for s in [e==1 for e in np.eye(frames)]]
visibility = [list(np.repeat(e, bars)) for e in scenarios]

您绝对可以考虑将其中一些行移出循环,因为它们重复了不必要的次数,但我发现让这些步骤彼此靠近更具可读性。还有问题吗?不要犹豫,问!以下是全部内容:

完整代码:

import pandas as pd
import numpy as np
import plotly.graph_objects as go
df_merged = pd.DataFrame({'bills': {0: 1.0, 1: 6.0, 2: 4.0, 3: 9.0, 4: 3.0},
                     'date': {0: '2020-12',
                      1: '2021-02',
                      2: '2020-12',
                      3: '2020-12',
                      4: '2021-01'},
                     'dni': {0: '00820054194',
                      1: '01717705014',
                      2: '02252584041',
                      3: '04902852446',
                      4: '04902852446'},
                     'goalTrans': {0: 2.0, 1: 0.0, 2: 0.0, 3: 1.0, 4: 0.0},
                     'incomes': {0: 1.0, 1: 2.0, 2: 2.0, 3: 1.0, 4: 2.0},
                     'payments': {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 1.0},
                     'savings': {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0}})

fig = go.Figure()
buttons = []

frames = len(df_merged.dni.unique())
for i, dni in enumerate(sorted(df_merged.dni.unique()[:])):
    df = df_merged[df_merged['dni']==dni]
    print(dni)
    print(df)
    
    args_data = []
    bars = len(df.columns[3:-1])
    for c, column in enumerate(df.columns[3:-1]):
        fig.add_trace(go.Bar(
                        name = column,
                        x = pd.to_datetime(df.date.astype('str')),
                        y = df[column], 
                        visible=False
                      ))
    
    frames = len(df_merged.dni.unique())
    bars = len(df.columns[3:-1])
    scenarios = [list(s) for s in [e==1 for e in np.eye(frames)]]
    visibility = [list(np.repeat(e, bars)) for e in scenarios]   
        
    button =  dict(label=dni,
                   method = 'restyle',
                    args = ['visible',visibility[i]]
                  )
    
    buttons.append(button)
       
fig.update_layout(
    updatemenus=[
        dict(
        type="dropdown",
        direction="down",
        buttons = buttons)
    ],
    barmode = "stack",)
f = fig.full_figure_for_development(warn=False)

fig.show()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-21
    • 2019-10-18
    • 2017-01-11
    • 2023-04-03
    • 2020-03-31
    • 1970-01-01
    • 2021-06-19
    • 2022-01-25
    相关资源
    最近更新 更多