Plotly:如何显示和过滤具有多个下拉列表的数据框? [英] Plotly: How to display and filter a dataframe with multiple dropdowns?

查看:54
本文介绍了Plotly:如何显示和过滤具有多个下拉列表的数据框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

好吧,我的问题是我想使用多个(累积)下拉按钮(在本例中为 2 个,但它可能更多)通过使用选定的原始数据过滤原始数据来过滤绘图图形下拉列表中的值.

num 标签颜色值1个红0.42个蓝色0.23 一个绿色 0.34个红0.65 一蓝 0.76个绿色0.47B蓝0.28 B 绿色 0.49B红0.410 B 绿色 0.211C红0.112C蓝0.313D红0.814D蓝0.415D绿色0.616D黄0.5

在这个例子中,如果我选择标签A"和颜色红色",我只想显示标签A"和颜色红色"的行的值,如下:

num 标签颜色值1个红0.44个红0.6

那么,图应该只显示 2 个值

1) 所以这是我目前拥有的代码(见下文),但我不知道如何继续.你有什么想法吗?

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

预先感谢您的帮助!

将pandas导入为pd导入 plotly.graph_objects as god = {'num' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],'标签' : ['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'D', 'D', 'D', 'D'],'颜色' : ['红色', '蓝色', '绿色', '红色', '蓝色', '绿色', '蓝色', '绿色', '红色', '绿色', '红色', '蓝色', '红色', '蓝色', '绿色', '黄色'],'值' : [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]}# 构建数据框df = pd.DataFrame(data=d)# 建立下拉标签标签 = df["label"].unique()buttonLabels = [dict(label = "所有标签",方法 = "重新设计",args = [{'y' : [df["value"] * 100]}] # 或者其他什么?)]对于标签中的标签:buttonLabels.append(dict(label = label,方法 = "重新设计",可见 = 真,#args = [{'y' : ???}]))# 构建下拉颜色颜色 = df["颜色"].unique()buttonColors = [dict(label = "所有颜色",方法 = "重新设计",args = [{'y' : [df["value"] * 100]}] # 或者其他什么?)]对于颜色中的颜色:buttonColors.append(dict(label = color,方法 = "重新设计",可见 = 真,# args = [{'y' : ???}]))# 显示图形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)])图.show()

解决方案

当然可以使用多个下拉列表来显示和过滤数据框.下面的代码片段将为您做到这一点.该代码段与您提供的代码有很多共同点,但我必须从头开始构建它以确保所有内容协调一致.运行下面的代码片段,然后选择 ARed 看看你实际上会得到:

num 标签颜色值1个红0.44个红0.6

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

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

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

还有改进的余地.有空我会完善代码,改进布局.首先,请告诉我这是否确实是您要找的.

完整代码:

# 导入导入 plotly.graph_objs as go将熊猫导入为 pd将 numpy 导入为 np# 源数据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},16: {'num': 17, 'label': 'E', 'color': 'purple', 'value': 0.68}}).Tdf_input = df.copy()# 按标签分割 df标签 = df['label'].unique().tolist()日期 = df['num'].unique().tolist()# 按标签分组的数据框集合dfs = {}对于标签中的标签:dfs[label]=pd.pivot_table(df[df['label']==label],值='值',index=['num'],列=['颜色'],aggfunc=np.sum)# 查找行和列联合common_cols = []common_rows = []对于 dfs.keys() 中的 df:common_cols = sorted(list(set().union(common_cols,list(dfs[df]))))common_rows = sorted(list(set().union(common_rows,list(dfs[df].index))))# 找到维度上通用的数据框df_common = pd.DataFrame(np.nan, index=common_rows, columns=common_cols)# 将每个 dfs[df] 重塑为公共维度dfc={}对于 dfs 中的 df_item:#print(dfs[未成形])df1 = dfs[df_item].copy()s=df_common.combine_first(df1)df_reshape = df1.reindex_like(s)dfc[df_item]=df_reshape# 情节开始fig = go.Figure()# 每个数据帧的每一列都有一个跟踪:AI 和 RANDOM对于 common_cols 中的 col:fig.add_trace(go.Scatter(x=dates,可见=真,标记=字典(大小=12,行=字典(宽度=2)),标记符号 = '钻石',name=col))# 菜单设置更新菜单= []# 菜单 1 的按钮,名称按钮=[]# 为每种颜色创建痕迹:# 为按钮构建 argVals 并创建按钮对于 dfc.keys() 中的 df:参数列表 = []对于 dfc[df] 中的 col:#print(dfc[df][col].values)argList.append(dfc[df][col].values)argVals = [ {'y':argList}]button.append(dict(method='update',标签=df,可见=真,args=argVals))# 菜单 2 的按钮,颜色b2_labels = common_cols# 矩阵为所有跟踪提供所有可见参数# 以便他们可以选择显示或隐藏b2_show = [list(b) for b in [e==1 for e in np.eye(len(b2_labels))]]按钮 2=[]button2.append({'method': 'update','label': '全部','args': [{'visible': [True]*len(common_cols)}]})# 创建按钮来显示或隐藏对于范围内的 i(0, len(b2_labels)):button2.append(dict(method='update',标签=b2_labels[i],args=[{'visible':b2_show[i]}]))# 为按钮二添加选项以隐藏所有button2.append(dict(method='update',标签='无',args=[{'visible':[False]*len(common_cols)}]))# 对更新菜单的一些调整更新菜单=[]your_menu=dict()updatemenu.append(your_menu)your_menu2=dict()updatemenu.append(your_menu2)更新菜单[1]updatemenu[0]['buttons']=buttonsupdatemenu[0]['direction']='down'updatemenu[0]['showactive']=Trueupdatemenu[1]['buttons']=buttons2更新菜单[1]['y']=0.6fig.update_layout(showlegend=False,updatemenus=updatemenu)fig.update_layout(yaxis=dict(range=[0,df_input['value'].max()+0.4]))# 标题fig.update_layout(标题=字典(text="<i>使用多个下拉按钮过滤</i>",font={'size':18},y=0.9,x=0.5,xanchor = '中心',yanchor = '顶'))# 按钮注释fig.update_layout(注释=[dict(text="<i>标签</i>", x=-0.2, xref="paper", y=1.1, yref="paper",align="left", showarrow=False, font = dict(size=16, color = 'steelblue')),dict(text="<i>颜色</i>", x=-0.2, xref="paper", y=0.7, yref="paper",align="left", showarrow=False, font = dict(size=16, color = 'steelblue'))])图.show()

I'm new to Python, Pandas and Plotly so maybe the answer is easy but I couldn't find anything on the forum or anywhere else …

I don’t want to use Dash nor ipywidgets since I want to be able to export in HTML using plotly.offline.plot (I need an interactive HTML file to dynamically control the figure without any server running like Dash seems to do).

Well my problem is that I would like to filter a plotly figure using several (cumulative) dropdown buttons (2 in this example, but it could be more) by filtering the original data with the selected value in the dropdown lists.

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

In this example, if I choose label ‘A’ and color ‘red’ I would like to display ONLY the values of rows with label ‘A’ AND color ‘red’, as follow :

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

Then, the figure should display only 2 values

1) So here is the code I have for the moment (see below) but I don’t know how to continue. Do you have any idea ?

2) Extra question : is it possible to use checkboxes instead of dropdown lists, to be able to select multiple values inside a criteria, for example : Labels filter could be A or B, not only one in the list …

Thanks in advance for your help !

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()

解决方案

It's certainly possible to display and filter a dataframe with multiple dropdowns. The code snippet below will do exactly that for you. The snippet has quite a few elements in common with your provided code, but I had to build it from scratch to make sure everything harmonized. Run the snippet below, and select A and Red to see that you will in fact get:

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

Plot 1: Label = A, color = Red

Here's the same plot for another selection:

Plot 2: Label = B, color = All

There's still room for improvement. I'll polish the code and improve the layout when I find the time. First, please let me know if this is in fact what you were looking for.

Complete code:

# 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},
                    16: {'num': 17, 'label': 'E', 'color': 'purple', 'value': 0.68}}
                    ).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:
    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] into common dimensions
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()
# one trace for each column per dataframe: AI and RANDOM
for col in common_cols:
    fig.add_trace(go.Scatter(x=dates,
                             visible=True,
                             marker=dict(size=12, line=dict(width=2)),
                             marker_symbol = 'diamond',name=col
                  )
             )

# menu setup    
updatemenu= []

# buttons for menu 1, names
buttons=[]

# create traces for each color: 
# build argVals for buttons and create buttons
for df in dfc.keys():
    argList = []
    for col in dfc[df]:
        #print(dfc[df][col].values)
        argList.append(dfc[df][col].values)
    argVals = [ {'y':argList}]

    buttons.append(dict(method='update',
                        label=df,
                        visible=True,
                        args=argVals))

# buttons for menu 2, colors
b2_labels = common_cols

# 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]*len(common_cols)}]})

# 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]*len(common_cols)}]
                        )
                   )

# 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]))

# title
fig.update_layout(
    title=dict(
        text= "<i>Filtering with multiple dropdown buttons</i>",
        font={'size':18},
        y=0.9,
        x=0.5,
        xanchor= 'center',
        yanchor= 'top'))

# button annotations
fig.update_layout(
    annotations=[
        dict(text="<i>Label</i>", x=-0.2, xref="paper", y=1.1, yref="paper",
            align="left", showarrow=False, font = dict(size=16, color = 'steelblue')),
        dict(text="<i>Color</i>", x=-0.2, xref="paper", y=0.7, yref="paper",
            align="left", showarrow=False, font = dict(size=16, color = 'steelblue')

                             )
    ])

fig.show()

这篇关于Plotly:如何显示和过滤具有多个下拉列表的数据框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆