Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
270 views
in Technique[技术] by (71.8m points)

python - Drop down menu for Plotly graph

Here is my dataframe:

df = pd.DataFrame({"Date":["2020-01-27","2020-02-27","2020-03-27","2020-04-27", "2020-05-27", "2020-06-27", "2020-07-27",
                          "2020-01-27","2020-02-27","2020-03-27","2020-04-27", "2020-05-27", "2020-06-27", "2020-07-27"],
                   "A_item":[2, 8, 0, 1, 8, 10, 4, 7, 2, 15, 5, 12, 10, 7],
                   "B_item":[1, 7, 10, 6, 5, 9, 2, 5, 6, 1, 2, 6, 15, 8],
                   "C_item":[9, 2, 9, 3, 9, 18, 7, 2, 8, 1, 2, 8, 1, 3],
                   "Channel_type":["Chanel_1", "Chanel_1", "Chanel_1", "Chanel_1", "Chanel_1", "Chanel_1", "Chanel_1", 
                                   "Chanel_2", "Chanel_2", "Chanel_2", "Chanel_2", "Chanel_2", "Chanel_2", "Chanel_2"]
                   })

I want to plot a group Bar chart with the dropdown filter on the Channel_type col. That's what I am trying:

trace2 = go.Bar(x=df["Date"], y=df[["B_item"]])
trace3 = go.Bar(x=df["Date"], y=df[["C_item"]])

list_updatemenus = [{'label': 'All',
  'method': 'update',
  'args': [{'visible': [True, True]}, {'title': 'All'}]},
 {'label': 'Chanel_1',
  'method': 'update',
  'args': [{'visible': [True, False]}, {'title': 'Chanel_1'}]},
 {'label': 'Chanel_2',
  'method': 'update',
  'args': [{'visible': [False, True]}, {'title': 'Chanel_2'}]}]


data = [trace1,trace2,trace3]

layout=go.Layout(title='Distribution of Sales by Region',updatemenus=list([dict(buttons= list_updatemenus)]),width=1000,height=800,barmode='group')


fig = go.Figure(data,layout)

fig.show()

And not getting the desired output:Plot 1

As it filters the graph by the "A_item", "B_item" and "C_item" while I would like to filter it by the Channel_type col as mentioned.

So the ideal result would be the below graph, but with the dropdown menu that changes the graph based on Channel_type :

Plot 2

I am able to solve the problem with Ipywidgets in the Jupyter notebook, but it’s not really working for my particular task. Here is the code:

from plotly import graph_objs as go
import ipywidgets as w
from IPython.display import display

x  = 'Date'
y1 = 'A_item'
y2 = 'B_item'
y3 = 'C_item'

trace1 = {
 'x': df[x],
 'y': df[y1],
 'type': 'bar',
 'name':'A_item'
}

trace2={
 'x': df[x],
 'y': df[y2],
 'type': 'bar',
 'name':'B_item'
}

trace3 = {
 'x': df[x],
 'y': df[y3],
 'type': 'bar',
 'name':'C_item',
 
}

data = [trace1, trace2, trace3]

# Create layout for the plot
layout=dict(
 title='Channels', 
 width=1200, height=700, title_x=0.5,
 paper_bgcolor='#fff',
 plot_bgcolor="#fff",
 xaxis=dict(
     title='Date', 
     type='date', 
     tickformat='%Y-%m-%d',
     gridcolor='rgb(255,255,255)',
     zeroline= False,
 ),
 yaxis=dict(
     title='My Y-axis',
     zeroline= False
         )
     )

fig = go.FigureWidget(data=data, layout=layout)

def update_fig(change):
 aux_df = df[df.Channel_type.isin(change['new'])]
 with fig.batch_update():
     for trace, column in zip(fig.data, [y1, y2, y3]):
         trace.x = aux_df[x]
         trace.y = aux_df[column]

drop = w.Dropdown(options=[
 ('All', ['Chanel_1', 'Chanel_2']),
 ('Chanel_1', ['Chanel_1']),
 ('Chanel_2', ['Chanel_2']),
])
drop.observe(update_fig, names='value')



display(w.VBox([drop, fig]))

And here is the output:

Output

The problem is that I am not able to wrap the VBox into an HTML file and save the dropdown menu. Also, it isn’t working in the Python shell as it is intended for the Jupyter notebook, and I need to share it.

So the ideal result would be to wrap the last figure within the Plotly fig only without the ipywidgets.

Any help be really appreciated!

Thank you!

question from:https://stackoverflow.com/questions/65670966/drop-down-menu-for-plotly-graph

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The most important thing to note is that for go.Bar, if you have n dates in the x parameter and you pass a 2D array of dimension (m, n) to the y parameter of go.Bar, Plotly understands to create a grouped bar chart with each date n having m bars.

For your DataFrame, something like df[df['Channel_type'] == "Channel_1"][items].T.values will reshape it as needed. So we can apply this to the y field of args that we pass the to the buttons we make.

Credit to @vestland for the portion of the code making adjustments to the buttons to make it a dropdown.

import pandas as pd
import plotly.graph_objects as go

df = pd.DataFrame({"Date":["2020-01-27","2020-02-27","2020-03-27","2020-04-27", "2020-05-27", "2020-06-27", "2020-07-27",
                          "2020-01-27","2020-02-27","2020-03-27","2020-04-27", "2020-05-27", "2020-06-27", "2020-07-27"],
                   "A_item":[2, 8, 0, 1, 8, 10, 4, 7, 2, 15, 5, 12, 10, 7],
                   "B_item":[1, 7, 10, 6, 5, 9, 2, 5, 6, 1, 2, 6, 15, 8],
                   "C_item":[9, 2, 9, 3, 9, 18, 7, 2, 8, 1, 2, 8, 1, 3],
                   "Channel_type":["Channel_1", "Channel_1", "Channel_1", "Channel_1", "Channel_1", "Channel_1", "Channel_1", 
                                   "Channel_2", "Channel_2", "Channel_2", "Channel_2", "Channel_2", "Channel_2", "Channel_2"]
                   })

fig = go.Figure()

colors = ['#636efa','#ef553b','#00cc96']
items = ["A_item","B_item","C_item"]
for item, color in zip(items, colors):
    fig.add_trace(go.Bar(
        x=df["Date"], y=df[item], marker_color=color
        ))

# one button for each df column
# slice the DataFrame and apply transpose to reshape it correctly
updatemenu= []
buttons=[]
for channel in df['Channel_type'].unique():
    buttons.append(dict(method='update',
                        label=channel,
                        args=[{
                        'y': df[df['Channel_type'] == channel][items].T.values
                        }])
                  )

## add a button for both channels
buttons.append(dict(
    method='update',
    label='Both Channels',
    args=[{
    'y': df[items].T.values
    }])
)

# some adjustments to the updatemenu
# from code by vestland
updatemenu=[]
your_menu=dict()
updatemenu.append(your_menu)
updatemenu[0]['buttons']=buttons
updatemenu[0]['direction']='down'
updatemenu[0]['showactive']=True

fig.update_layout(updatemenus=updatemenu)

fig.show()

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...