情节:如何显示和过滤具有多个下拉菜单的数据框?

问题描述 投票:3回答:1

我是Python,Pandas和Plotly的新手,所以也许答案很简单,但我在论坛或其他任何地方都找不到任何东西……

我不想使用Dash或ipywidgets,因为我希望能够使用plotly.offline.plot以HTML格式导出(我需要一个交互式HTML文件来动态控制图形,而没有任何服务器像Dash一样运行) 。

我的问题是,我想使用几个(累积的)下拉按钮(在此示例中为2个,但可能会更多)来过滤一个绘图图形,方法是使用下拉菜单中的选定值过滤原始数据列表。

num label   color   value
1   A       red     0.4
2   A       blue    0.2
3   A       green   0.3
4   A       red     0.6
5   A       blue    0.7
6   A       green   0.4
7   B       blue    0.2
8   B       green   0.4
9   B       red     0.4
10  B       green   0.2
11  C       red     0.1
12  C       blue    0.3
13  D       red     0.8
14  D       blue    0.4
15  D       green   0.6
16  D       yellow  0.5

在此示例中,如果我选择标签'A'和颜色'红色',我只显示标签'A'和颜色'红色'的行的值,如下所示:

num label   color   value
1   A       red     0.4
4   A       red     0.6

然后,图形应仅显示2个值

1)这是我目前拥有的代码(请参见下文),但我不知道如何继续。你有什么主意吗?

2)额外的问题:是否可以使用复选框而不是下拉列表,以便能够在条件内选择多个值,例如:标签过滤器可以是A或B,而不是列表中的一个…

感谢您的帮助!

import pandas as pd
import plotly.graph_objects as go

d = {
    'num' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
    'label' : ['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'D', 'D', 'D', 'D'],
    'color' : ['red', 'blue', 'green', 'red', 'blue', 'green', 'blue', 'green', 'red', 'green', 'red', 'blue', 'red', 'blue', 'green', 'yellow'],
    'value' : [0.4, 0.2, 0.3, 0.6, 0.7, 0.4, 0.2, 0.4, 0.4, 0.2, 0.1, 0.3, 0.8, 0.4, 0.6, 0.5]
    }

# Build dataframe
df = pd.DataFrame(data=d)

# Build dropdown Labels
labels = df["label"].unique()
buttonsLabels = [dict(label = "All labels",
                            method = "restyle",
                            args = [{'y' : [df["value"] * 100]}] # or what else ?
                            )]
for label in labels:
    buttonsLabels.append(dict(label = label,
                              method = "restyle",
                              visible = True,
                              #args = [{'y' : ??? }]
                              ))
# Build dropdown Colors
colors = df["color"].unique()
buttonsColors = [dict(label = "All colors",
                            method = "restyle",
                            args = [{'y' : [df["value"] * 100]}] # or what else ?
                            )]
for color in colors:
    buttonsColors.append(dict(label = color,
                              method = "restyle",
                              visible = True,
                              # args = [{'y' : ??? }]
                              ))

# Display figure
fig = go.Figure(data = [ go.Scatter(x = df["num"], y = df["value"] * 100 ) ])

fig.update_layout(updatemenus = [
   dict(buttons = buttonsLabels, showactive = True),
   dict(buttons = buttonsColors, showactive = True, y = 0.8)
   ])

fig.show()
python pandas plotly
1个回答
0
投票

是的,当然可以显示和过滤具有多个下拉菜单的数据框。下面的代码段将为您完成此操作。该代码段与您提供的代码中包含的元素很少,但是我必须从头开始构建它,以确保所有内容协调一致。运行以下代码段,然后依次选择ARed,您实际上会得到:

num label   color   value
1   A       red     0.4
4   A       red     0.6

图1:标签= A,颜色=红色

enter image description here

这是另一个选择的相同情节:

图2:标签= B,颜色=全部

enter image description here

完整代码:

# Imports
import plotly.graph_objs as go
import pandas as pd
import numpy as np

# source data
df = pd.DataFrame({0: {'num': 1, 'label': 'A', 'color': 'red', 'value': 0.4},
                    1: {'num': 2, 'label': 'A', 'color': 'blue', 'value': 0.2},
                    2: {'num': 3, 'label': 'A', 'color': 'green', 'value': 0.3},
                    3: {'num': 4, 'label': 'A', 'color': 'red', 'value': 0.6},
                    4: {'num': 5, 'label': 'A', 'color': 'blue', 'value': 0.7},
                    5: {'num': 6, 'label': 'A', 'color': 'green', 'value': 0.4},
                    6: {'num': 7, 'label': 'B', 'color': 'blue', 'value': 0.2},
                    7: {'num': 8, 'label': 'B', 'color': 'green', 'value': 0.4},
                    8: {'num': 9, 'label': 'B', 'color': 'red', 'value': 0.4},
                    9: {'num': 10, 'label': 'B', 'color': 'green', 'value': 0.2},
                    10: {'num': 11, 'label': 'C', 'color': 'red', 'value': 0.1},
                    11: {'num': 12, 'label': 'C', 'color': 'blue', 'value': 0.3},
                    12: {'num': 13, 'label': 'D', 'color': 'red', 'value': 0.8},
                    13: {'num': 14, 'label': 'D', 'color': 'blue', 'value': 0.4},
                    14: {'num': 15, 'label': 'D', 'color': 'green', 'value': 0.6},
                    15: {'num': 16, 'label': 'D', 'color': 'yellow', 'value': 0.5}}).T

df_input = df.copy()

# split df by labels
labels = df['label'].unique().tolist()
dates = df['num'].unique().tolist()

# dataframe collection grouped by labels
dfs = {}
for label in labels:
    #print(label)
    dfs[label]=pd.pivot_table(df[df['label']==label],
                             values='value',
                             index=['num'],
                             columns=['color'],
                             aggfunc=np.sum)

# find row and column unions
common_cols = []
common_rows = []
for df in dfs.keys():
    common_cols = sorted(list(set().union(common_cols,list(dfs[df]))))
    common_rows = sorted(list(set().union(common_rows,list(dfs[df].index))))

# find dimensionally common dataframe
df_common = pd.DataFrame(np.nan, index=common_rows, columns=common_cols)

# reshape each dfs[df] int common dimension
dfc={}
for df_item in dfs:
    #print(dfs[unshaped])
    df1 = dfs[df_item].copy()
    s=df_common.combine_first(df1)
    df_reshaped = df1.reindex_like(s)
    dfc[df_item]=df_reshaped

# plotly start 
fig = go.Figure()

# get column names from first dataframe in the dict
colNames = list(dfs[list(dfs.keys())[0]].columns)


# one trace for each column per dataframe: AI and RANDOM
for col in colNames:
    fig.add_trace(go.Scatter(x=dates,
                             visible=True,
                             #name=col
                  )
             )

# menu setup    
updatemenu= []

# buttons for menu 1, names
buttons=[]

# create traces for each color: 
for df in dfc.keys():
    buttons.append(dict(method='update',
                        label=df,
                        visible=True,
                        args=[ {'y':[dfc[df]['blue'].values,
                                    dfc[df]['green'].values,
                                    dfc[df]['red'].values,
                                    dfc[df]['yellow'].values]}]))

# buttons for menu 2, colors
b2_labels = colNames

# matrix to feed all visible arguments for all traces
# so that they can be shown or hidden by choice
b2_show = [list(b) for b in [e==1 for e in np.eye(len(b2_labels))]]
buttons2=[]
buttons2.append({'method': 'update',
                 'label': 'All',
                 'args': [{'visible': [True]*4}]})

# create buttons to show or hide
for i in range(0, len(b2_labels)):
    buttons2.append(dict(method='update',
                        label=b2_labels[i],
                        args=[{'visible':b2_show[i]}]
                        )
                   )

# add option for button two to hide all
buttons2.append(dict(method='update',
                        label='None',
                        args=[{'visible':[False]*4}]
                        )
                   )

# some adjustments to the updatemenus
updatemenu=[]
your_menu=dict()
updatemenu.append(your_menu)
your_menu2=dict()
updatemenu.append(your_menu2)
updatemenu[1]
updatemenu[0]['buttons']=buttons
updatemenu[0]['direction']='down'
updatemenu[0]['showactive']=True
updatemenu[1]['buttons']=buttons2
updatemenu[1]['y']=0.6

fig.update_layout(showlegend=False, updatemenus=updatemenu)
fig.update_layout(yaxis=dict(range=[0,df_input['value'].max()+0.4]))
fig.show()
© www.soinside.com 2019 - 2024. All rights reserved.