问题
I have a dataframe like this:
import pandas as pd
df = pd.DataFrame()
df['category'] = ['G1', 'G1', 'G1', 'G1','G1', 'G1','G1', 'G2', 'G2', 'G2', 'G2', 'G2', 'G2', 'G2']
df['date'] = ['2012-04-01', '2012-04-05', '2012-04-09', '2012-04-11', '2012-04-16', '2012-04-23', '2012-04-30',
'2012-04-01', '2012-04-05', '2012-04-09', '2012-04-11', '2012-04-16', '2012-04-23', '2012-04-30']
df['col1'] = [54, 34, 65, 67, 23, 34, 54, 23, 67, 24, 64, 24, 45, 89]
df['col2'] = round(df['col1'] * 0.85)
I want to create a plotly figure that has one x (date
) and 2 ys (col1
and col2
). like this one, where the category dropdown button let's you select the category and updates the figure by filtering the col1
and col2
data for the selected category.
But I cannot make the dropdown to work and update the lines.
This is the code I tried:
# import plotly
from plotly.offline import init_notebook_mode, iplot, plot
import plotly.graph_objs as go
init_notebook_mode(connected=True)
x = 'date'
y1 = 'col1'
y2 = 'col2'
trace1 = {
'x': df[x],
'y': df[y1],
'type': 'scatter',
'mode': 'lines',
'name':'col 1',
'marker': {'color': 'blue'}
}
trace2={
'x': df[x],
'y': df[y2],
'type': 'scatter',
'mode': 'lines',
'name':'col 2',
'marker': {'color': 'yellow'}
}
data = [trace1, trace2]
# Create layout for the plot
layout=dict(
title='my plot',
xaxis=dict(
title='Date',
type='date',
tickformat='%Y-%m-%d',
ticklen=5,
titlefont=dict(
family='Old Standard TT, serif',
size=20,
color='black'
)
),
yaxis=dict(
title='values',
ticklen=5,
titlefont=dict(
family='Old Standard TT, serif',
size=20,
color='black'
)
)
)
# create the empty dropdown menu
updatemenus = list([dict(buttons=list()),
dict(direction='down',
showactive=True)])
total_codes = len(df.category.unique()) + 1
for s, categ in enumerate(df.category.unique()):
visible_traces = [False] * total_codes
visible_traces[s + 1] = True
updatemenus[0]['buttons'].append(dict(args=[{'visible': visible_traces}],
label='category',
method='update'))
updatemenus[0]['buttons'].append(dict(args=[{'visible': [True] + [False] * (total_codes - 1)}],
label='category',
method='update'))
layout['updatemenus'] = updatemenus
fig = dict(data = data, layout = layout)
iplot(fig)
I want make the category dropdown button with unique groups from category
column, and selecting the category
(either G1
or G2
) will filter that data and plot the x
and ys
for this selected category.
I already looked at dropdown page on plotly website but couldn't make the dropdown to work.
https://plot.ly/python/dropdowns/
回答1:
Plotly 3 implemented ipython widgets
native support, with this I'm not sure they are maintaining their old widgets. I suggest using ipython widgets
because they are more standard and flexible, also I find them a bit easier to use even when it takes some time to get used to them. Here's a working example:
from plotly import graph_objs as go
import ipywidgets as w
from IPython.display import display
import pandas as pd
df = pd.DataFrame()
df['category'] = ['G1', 'G1', 'G1', 'G1','G1', 'G1','G1', 'G2', 'G2', 'G2', 'G2', 'G2', 'G2', 'G2']
df['date'] = ['2012-04-01', '2012-04-05', '2012-04-09', '2012-04-11', '2012-04-16', '2012-04-23', '2012-04-30',
'2012-04-01', '2012-04-05', '2012-04-09', '2012-04-11', '2012-04-16', '2012-04-23', '2012-04-30']
df['col1'] = [54, 34, 65, 67, 23, 34, 54, 23, 67, 24, 64, 24, 45, 89]
df['col2'] = round(df['col1'] * 0.85)
x = 'date'
y1 = 'col1'
y2 = 'col2'
trace1 = {
'x': df[x],
'y': df[y1],
'type': 'scatter',
'mode': 'lines',
'name':'col 1',
'marker': {'color': 'blue'}
}
trace2={
'x': df[x],
'y': df[y2],
'type': 'scatter',
'mode': 'lines',
'name':'col 2',
'marker': {'color': 'yellow'}
}
data = [trace1, trace2]
# Create layout for the plot
layout=dict(
title='my plot',
xaxis=dict(
title='Date',
type='date',
tickformat='%Y-%m-%d',
ticklen=5,
titlefont=dict(
family='Old Standard TT, serif',
size=20,
color='black'
)
),
yaxis=dict(
title='values',
ticklen=5,
titlefont=dict(
family='Old Standard TT, serif',
size=20,
color='black'
)
)
)
# Here's the new part
fig = go.FigureWidget(data=data, layout=layout)
def update_fig(change):
aux_df = df[df.category.isin(change['new'])]
with fig.batch_update():
for trace, column in zip(fig.data, [y1, y2]):
trace.x = aux_df[x]
trace.y = aux_df[column]
drop = w.Dropdown(options=[
('All', ['G1', 'G2']),
('G1', ['G1']),
('G2', ['G2']),
])
drop.observe(update_fig, names='value')
display(w.VBox([drop, fig]))
note that now you don't even need to import offline
as the figure itself is an ipython widget. Plotly 3 also implemented an imperative way to write the code that I find to be really useful, you can read more about this and other plotly 3 features (that are sadly not really covered on the docs) in this post.
EDIT
for more than one dropdown something like this should work
def update_fig1(change):
aux_df = df[df.category == change['new']]
aux_df = aux_df[aux_df.category1 == drop2.value]
with fig.batch_update():
for trace, column in zip(fig.data, [y1, y2]):
trace.x = aux_df[x]
trace.y = aux_df[column]
def update_fig2(change):
aux_df = df[df.category1 == change['new']]
aux_df = aux_df[aux_df.category == drop1.value]
with fig.batch_update():
for trace, column in zip(fig.data, [y1, y2]):
trace.x = aux_df[x]
trace.y = aux_df[column]
drop1 = w.Dropdown(options=df.category.unique())
drop2 = w.Dropdown(options=df.category1.unique())
drop1.observe(update_fig1, names='value')
drop2.observe(update_fig2, names='value')
display(w.VBox([w.HBox([drop1, drop2]), fig]))
来源:https://stackoverflow.com/questions/56671386/create-dropdown-button-to-filter-based-on-a-categorical-column