Plotly: Comment créer une option de liste déroulante à index multiples?
J'ai des données avec le même numéro d'index pour une période différente comme ci-dessous
Time CallOI PutOI CallLTP PutLTP
29500 3:30 PM 502725 554775 343.70 85.50
29500 3:15 PM 568725 629700 357.15 81.70
29500 2:59 PM 719350 689850 337.85 95.45
29500 2:45 PM 786975 641575 360.00 108.35
29500 2:30 PM 823500 626875 336.50 127.80
29500 2:15 PM 812450 631800 308.55 143.00
29500 2:00 PM 974700 617750 389.80 120.00
29500 1:45 PM 1072675 547100 262.55 186.85
29500 1:30 PM 1272300 469600 206.85 232.00
29600 3:30 PM 502725 554775 343.70 85.50
29600 3:15 PM 568725 629700 357.15 81.70
29600 2:59 PM 719350 689850 337.85 95.45
29600 2:45 PM 786975 641575 360.00 108.35
29600 2:30 PM 823500 626875 336.50 127.80
29600 2:15 PM 812450 631800 308.55 143.00
29600 2:00 PM 974700 617750 389.80 120.00
29600 1:45 PM 1072675 547100 262.55 186.85
29600 1:30 PM 1272300 469600 206.85 232.00
29700 3:30 PM 502725 554775 343.70 85.50
29700 3:15 PM 568725 629700 357.15 81.70
29700 2:59 PM 719350 689850 337.85 95.45
29700 2:45 PM 786975 641575 360.00 108.35
29700 2:30 PM 823500 626875 336.50 127.80
29700 2:15 PM 812450 631800 308.55 143.00
29700 2:00 PM 974700 617750 389.80 120.00
29700 1:45 PM 1072675 547100 262.55 186.85
29700 1:30 PM 1272300 469600 206.85 232.00
en utilisant le code ci-dessous, j'ai fait un graphique:
subfig = make_subplots(specs=[[{"secondary_y": True}]])
# create two independent figures with px.line each containing data from multiple columns
fig = px.line(df,x='Time', y='Call OI')
fig2 = px.line(df,x='Time', y='Call LTP')
fig2.update_traces(yaxis="y2")
subfig.add_traces(fig.data + fig2.data)
subfig.layout.xaxis.title="Time"
subfig.layout.yaxis.title="OI"
subfig.layout.yaxis2.type="log"
subfig.layout.yaxis2.title="Price"
# recoloring is necessary otherwise lines from fig und fig2 would share each color
# e.g. Linear-, Log- = blue; Linear+, Log+ = red... we don't want this
subfig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
subfig.show()

Je veux un menu déroulant qui sélectionne différents index et les données du graphique changent en conséquence. Par exemple, si je sélectionne dans la liste déroulante 29600, il affiche uniquement les données pour ce numéro d'index et existe également un moyen de retourner l'axe des x (temps) de gauche à droite. Merci d'avance pour toute solution
Réponses
Edit 2 - Suggestion mise à jour avec ensemble de données lié
Pour utiliser l'ensemble de données complet fourni dans le lien , téléchargez simplement ce contenu sous forme de fichier csv, ouvrez-le et copiez le contenu, puis exécutez le code ci-dessous pour obtenir la figure suivante. Les données sont récupérées à l'aide de dfi = pd.read_clipboard(sep=',')
. Il n'y a vraiment pas besoin de se soucier de définir 'Strike Price
comme index. Veuillez noter que l'ensemble de données a beaucoup de 0
valeurs, mais la sélection, par exemple, 26100
produira au moins une sortie significative:

Code complet pour l'édition 2
import collections
import dash
import pandas as pd
from dash.dependencies import Output, Input
from dash.exceptions import PreventUpdate
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from plotly.subplots import make_subplots
import plotly.graph_objects as go
dfi = pd.read_clipboard(sep=',')
df = dfi.copy()
idx = list(df['Strike Price'].unique())
app = JupyterDash()
app.layout = html.Div([
dcc.Store(id='memory-output'),
dcc.Dropdown(id='memory-countries', options=[
{'value': x, 'label': x} for x in idx
], multi=False, value=idx[0]),
dcc.Dropdown(id='memory-field', options=[
{'value': 'default', 'label': 'default'},
{'value': 'reverse', 'label': 'reverse'},
], value='default'),
html.Div([
dcc.Graph(id='memory-graph'),
])
])
@app.callback(Output('memory-output', 'data'),
[Input('memory-countries', 'value')])
def filter_countries(idx_selected):
if not idx_selected:
# Return all the rows on initial load/no country selected.
return(idx_selected)
return(idx_selected)
@app.callback(Output('memory-graph', 'figure'),
[Input('memory-output', 'data'),
Input('memory-field', 'value')])
def on_data_set_graph(data, field):
# print(data)
# global dff
if data is None:
raise PreventUpdate
# figure setup
fig = make_subplots(specs=[[{"secondary_y": True}]])
dff = df[df['Strike Price']==data]
fig.add_trace(go.Scatter(x=dff.Time, y = dff['Call OI'], name = 'Call'), secondary_y=True)
fig.add_trace(go.Scatter(x=dff.Time, y = dff['Call LTP'], name = 'Put'), secondary_y=False)
# flip axis
if field != 'default':
fig.update_layout(xaxis = dict(autorange='reversed'))
return(fig)
app.run_server(mode='inline', port = 8072, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True, debug=True)
Modifier - Suggestion mise à jour avec retournement d'axe
Ma dernière suggestion s'appuie sur un exemple sous la section Share data between callbacks
de dcc.Store et apporte les ajustements nécessaires pour fonctionner pour votre cas d'utilisation. J'ai également intégré une fonctionnalité pour inverser vos valeurs de l'axe des x en utilisant:fig.update_layout(xaxis = dict(autorange='reversed'))
Voici le résultat:

Et voici le code complet:
import collections
import dash
import pandas as pd
from dash.dependencies import Output, Input
from dash.exceptions import PreventUpdate
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from plotly.subplots import make_subplots
import plotly.graph_objects as go
df = pd.DataFrame({'Time': {(29500, '3:30'): 'PM',
(29500, '3:15'): 'PM',
(29500, '2:59'): 'PM',
(29500, '2:45'): 'PM',
(29500, '2:30'): 'PM',
(29500, '2:15'): 'PM',
(29500, '2:00'): 'PM',
(29500, '1:45'): 'PM',
(29500, '1:30'): 'PM',
(29600, '3:30'): 'PM',
(29600, '3:15'): 'PM',
(29600, '2:59'): 'PM',
(29600, '2:45'): 'PM',
(29600, '2:30'): 'PM',
(29600, '2:15'): 'PM',
(29600, '2:00'): 'PM',
(29600, '1:45'): 'PM',
(29600, '1:30'): 'PM',
(29700, '3:30'): 'PM',
(29700, '3:15'): 'PM',
(29700, '2:59'): 'PM',
(29700, '2:45'): 'PM',
(29700, '2:30'): 'PM',
(29700, '2:15'): 'PM',
(29700, '2:00'): 'PM',
(29700, '1:45'): 'PM',
(29700, '1:30'): 'PM'},
'CallOI': {(29500, '3:30'): 502725,
(29500, '3:15'): 568725,
(29500, '2:59'): 719350,
(29500, '2:45'): 786975,
(29500, '2:30'): 823500,
(29500, '2:15'): 812450,
(29500, '2:00'): 974700,
(29500, '1:45'): 1072675,
(29500, '1:30'): 1272300,
(29600, '3:30'): 502725,
(29600, '3:15'): 568725,
(29600, '2:59'): 719350,
(29600, '2:45'): 786975,
(29600, '2:30'): 823500,
(29600, '2:15'): 812450,
(29600, '2:00'): 974700,
(29600, '1:45'): 1000000,
(29600, '1:30'): 1272300,
(29700, '3:30'): 502725,
(29700, '3:15'): 568725,
(29700, '2:59'): 719350,
(29700, '2:45'): 786975,
(29700, '2:30'): 823500,
(29700, '2:15'): 812450,
(29700, '2:00'): 974700,
(29700, '1:45'): 1172675,
(29700, '1:30'): 1272300},
'PutOI': {(29500, '3:30'): 554775,
(29500, '3:15'): 629700,
(29500, '2:59'): 689850,
(29500, '2:45'): 641575,
(29500, '2:30'): 626875,
(29500, '2:15'): 631800,
(29500, '2:00'): 617750,
(29500, '1:45'): 547100,
(29500, '1:30'): 469600,
(29600, '3:30'): 554775,
(29600, '3:15'): 629700,
(29600, '2:59'): 689850,
(29600, '2:45'): 641575,
(29600, '2:30'): 626875,
(29600, '2:15'): 631800,
(29600, '2:00'): 617750,
(29600, '1:45'): 547100,
(29600, '1:30'): 469600,
(29700, '3:30'): 554775,
(29700, '3:15'): 629700,
(29700, '2:59'): 689850,
(29700, '2:45'): 641575,
(29700, '2:30'): 626875,
(29700, '2:15'): 631800,
(29700, '2:00'): 617750,
(29700, '1:45'): 547100,
(29700, '1:30'): 469600},
'CallLTP': {(29500, '3:30'): 343.7,
(29500, '3:15'): 357.15,
(29500, '2:59'): 337.85,
(29500, '2:45'): 360.0,
(29500, '2:30'): 336.5,
(29500, '2:15'): 308.55,
(29500, '2:00'): 389.8,
(29500, '1:45'): 262.55,
(29500, '1:30'): 206.85,
(29600, '3:30'): 343.7,
(29600, '3:15'): 357.15,
(29600, '2:59'): 337.85,
(29600, '2:45'): 360.0,
(29600, '2:30'): 336.5,
(29600, '2:15'): 308.55,
(29600, '2:00'): 389.8,
(29600, '1:45'): 262.55,
(29600, '1:30'): 206.85,
(29700, '3:30'): 343.7,
(29700, '3:15'): 357.15,
(29700, '2:59'): 337.85,
(29700, '2:45'): 360.0,
(29700, '2:30'): 336.5,
(29700, '2:15'): 308.55,
(29700, '2:00'): 389.8,
(29700, '1:45'): 262.55,
(29700, '1:30'): 206.85},
'PutLTP': {(29500, '3:30'): 85.5,
(29500, '3:15'): 81.7,
(29500, '2:59'): 95.45,
(29500, '2:45'): 108.35,
(29500, '2:30'): 127.8,
(29500, '2:15'): 143.0,
(29500, '2:00'): 120.0,
(29500, '1:45'): 186.85,
(29500, '1:30'): 232.0,
(29600, '3:30'): 85.5,
(29600, '3:15'): 81.7,
(29600, '2:59'): 95.45,
(29600, '2:45'): 108.35,
(29600, '2:30'): 127.8,
(29600, '2:15'): 143.0,
(29600, '2:00'): 120.0,
(29600, '1:45'): 186.85,
(29600, '1:30'): 232.0,
(29700, '3:30'): 85.5,
(29700, '3:15'): 81.7,
(29700, '2:59'): 95.45,
(29700, '2:45'): 108.35,
(29700, '2:30'): 127.8,
(29700, '2:15'): 143.0,
(29700, '2:00'): 120.0,
(29700, '1:45'): 186.85,
(29700, '1:30'): 232.0}})
df = df.reset_index()
idx = list(df['level_0'].unique())
app = JupyterDash()
app.layout = html.Div([
dcc.Store(id='memory-output'),
dcc.Dropdown(id='memory-countries', options=[
{'value': x, 'label': x} for x in idx
], multi=False, value=idx[0]),
dcc.Dropdown(id='memory-field', options=[
{'value': 'default', 'label': 'default'},
{'value': 'reverse', 'label': 'reverse'},
], value='default'),
html.Div([
dcc.Graph(id='memory-graph'),
])
])
@app.callback(Output('memory-output', 'data'),
[Input('memory-countries', 'value')])
def filter_countries(idx_selected):
if not idx_selected:
# Return all the rows on initial load/no country selected.
return(idx_selected)
return(idx_selected)
@app.callback(Output('memory-graph', 'figure'),
[Input('memory-output', 'data'),
Input('memory-field', 'value')])
def on_data_set_graph(data, field):
# print(data)
if data is None:
raise PreventUpdate
# figure setup
fig = make_subplots(specs=[[{"secondary_y": True}]])
dff = df[df['level_0']==data]
fig.add_trace(go.Scatter(x=dff.level_1, y = dff.CallOI, name = 'Call'), secondary_y=True)
fig.add_trace(go.Scatter(x=dff.level_1, y = dff.PutOI, name = 'Put'), secondary_y=False)
# flip axis
if field != 'default':
fig.update_layout(xaxis = dict(autorange='reversed'))
return(fig)
app.run_server(mode='inline', port = 8072, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True, debug=True)
Suggestion 1
Vous n'avez pas précisé comment vous utilisez vos chiffres. Mais en supposant que ce soit dans JupyterLab, je recommanderais vivement d'utiliser JupyterDash. Je trouve cela beaucoup plus agréable que d'incorporer des fonctionnalités de liste déroulante directement dans la figure, comme l'ont souligné les r-débutants dans le lien dans les commentaires.
L'extrait de code ci-dessous vous permettra de sélectionner l'index à partir duquel afficher les données dans l'application suivante qui est définie pour produire la figure 'inline'
qui signifie dans le bloc-notes lui-même. Si vous souhaitez utiliser une approche comme celle-ci, je peux voir si je peux également implémenter un bouton pour inverser l'axe des x.
App:

Code complet
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from plotly.subplots import make_subplots
from dash.dependencies import Input, Output, State
# data
df = pd.DataFrame({'Time': {(29500, '3:30'): 'PM',
(29500, '3:15'): 'PM',
(29500, '2:59'): 'PM',
(29500, '2:45'): 'PM',
(29500, '2:30'): 'PM',
(29500, '2:15'): 'PM',
(29500, '2:00'): 'PM',
(29500, '1:45'): 'PM',
(29500, '1:30'): 'PM',
(29600, '3:30'): 'PM',
(29600, '3:15'): 'PM',
(29600, '2:59'): 'PM',
(29600, '2:45'): 'PM',
(29600, '2:30'): 'PM',
(29600, '2:15'): 'PM',
(29600, '2:00'): 'PM',
(29600, '1:45'): 'PM',
(29600, '1:30'): 'PM',
(29700, '3:30'): 'PM',
(29700, '3:15'): 'PM',
(29700, '2:59'): 'PM',
(29700, '2:45'): 'PM',
(29700, '2:30'): 'PM',
(29700, '2:15'): 'PM',
(29700, '2:00'): 'PM',
(29700, '1:45'): 'PM',
(29700, '1:30'): 'PM'},
'CallOI': {(29500, '3:30'): 502725,
(29500, '3:15'): 568725,
(29500, '2:59'): 719350,
(29500, '2:45'): 786975,
(29500, '2:30'): 823500,
(29500, '2:15'): 812450,
(29500, '2:00'): 974700,
(29500, '1:45'): 1072675,
(29500, '1:30'): 1272300,
(29600, '3:30'): 502725,
(29600, '3:15'): 568725,
(29600, '2:59'): 719350,
(29600, '2:45'): 786975,
(29600, '2:30'): 823500,
(29600, '2:15'): 812450,
(29600, '2:00'): 974700,
(29600, '1:45'): 1000000,
(29600, '1:30'): 1272300,
(29700, '3:30'): 502725,
(29700, '3:15'): 568725,
(29700, '2:59'): 719350,
(29700, '2:45'): 786975,
(29700, '2:30'): 823500,
(29700, '2:15'): 812450,
(29700, '2:00'): 974700,
(29700, '1:45'): 1172675,
(29700, '1:30'): 1272300},
'PutOI': {(29500, '3:30'): 554775,
(29500, '3:15'): 629700,
(29500, '2:59'): 689850,
(29500, '2:45'): 641575,
(29500, '2:30'): 626875,
(29500, '2:15'): 631800,
(29500, '2:00'): 617750,
(29500, '1:45'): 547100,
(29500, '1:30'): 469600,
(29600, '3:30'): 554775,
(29600, '3:15'): 629700,
(29600, '2:59'): 689850,
(29600, '2:45'): 641575,
(29600, '2:30'): 626875,
(29600, '2:15'): 631800,
(29600, '2:00'): 617750,
(29600, '1:45'): 547100,
(29600, '1:30'): 469600,
(29700, '3:30'): 554775,
(29700, '3:15'): 629700,
(29700, '2:59'): 689850,
(29700, '2:45'): 641575,
(29700, '2:30'): 626875,
(29700, '2:15'): 631800,
(29700, '2:00'): 617750,
(29700, '1:45'): 547100,
(29700, '1:30'): 469600},
'CallLTP': {(29500, '3:30'): 343.7,
(29500, '3:15'): 357.15,
(29500, '2:59'): 337.85,
(29500, '2:45'): 360.0,
(29500, '2:30'): 336.5,
(29500, '2:15'): 308.55,
(29500, '2:00'): 389.8,
(29500, '1:45'): 262.55,
(29500, '1:30'): 206.85,
(29600, '3:30'): 343.7,
(29600, '3:15'): 357.15,
(29600, '2:59'): 337.85,
(29600, '2:45'): 360.0,
(29600, '2:30'): 336.5,
(29600, '2:15'): 308.55,
(29600, '2:00'): 389.8,
(29600, '1:45'): 262.55,
(29600, '1:30'): 206.85,
(29700, '3:30'): 343.7,
(29700, '3:15'): 357.15,
(29700, '2:59'): 337.85,
(29700, '2:45'): 360.0,
(29700, '2:30'): 336.5,
(29700, '2:15'): 308.55,
(29700, '2:00'): 389.8,
(29700, '1:45'): 262.55,
(29700, '1:30'): 206.85},
'PutLTP': {(29500, '3:30'): 85.5,
(29500, '3:15'): 81.7,
(29500, '2:59'): 95.45,
(29500, '2:45'): 108.35,
(29500, '2:30'): 127.8,
(29500, '2:15'): 143.0,
(29500, '2:00'): 120.0,
(29500, '1:45'): 186.85,
(29500, '1:30'): 232.0,
(29600, '3:30'): 85.5,
(29600, '3:15'): 81.7,
(29600, '2:59'): 95.45,
(29600, '2:45'): 108.35,
(29600, '2:30'): 127.8,
(29600, '2:15'): 143.0,
(29600, '2:00'): 120.0,
(29600, '1:45'): 186.85,
(29600, '1:30'): 232.0,
(29700, '3:30'): 85.5,
(29700, '3:15'): 81.7,
(29700, '2:59'): 95.45,
(29700, '2:45'): 108.35,
(29700, '2:30'): 127.8,
(29700, '2:15'): 143.0,
(29700, '2:00'): 120.0,
(29700, '1:45'): 186.85,
(29700, '1:30'): 232.0}})
df = df.reset_index()
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
# options for dropdown
criteria = list(df['level_0'].unique())
options = [{'label': i, 'value': i} for i in criteria]
options.append
# app layout
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(id='linedropdown',
options=options,
value=options[0]['value'],),
],
),
],className='row'),
html.Div([
html.Div([
dcc.Graph(id='linechart'),
],
),
],
),
])
@app.callback(
[Output('linechart', 'figure')],
[Input('linedropdown', 'value')]
)
def update_graph(linedropdown):
# selection using linedropdown
dff = df[df['level_0']==linedropdown]
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add trace 1
fig.add_trace(
go.Scatter(x=dff['level_1'], y=dff['CallOI'], name="Call OI"),
secondary_y=True,
)
# Add trace 2
fig.add_trace(
go.Scatter(x=dff['level_1'], y=dff['CallLTP'], name="Call LTP"),
secondary_y=False,
)
fig.update_layout(title = 'Index: ' + str(linedropdown))
return ([fig])
# Run app and display result inline in the notebook
app.run_server(mode='inline', port = 8040, dev_tools_ui=True, debug=True,
dev_tools_hot_reload =True, threaded=True)