Plotly : 다중 인덱스 드롭 다운 옵션을 만드는 방법은 무엇입니까?
아래와 같이 다른 시간대에 대해 동일한 인덱스 번호를 가진 데이터가 있습니다.
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
아래 코드를 사용하여 차트를 만들었습니다.
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()

다른 인덱스를 선택하고 그에 따라 차트 데이터가 변경되는 드롭 다운 메뉴를 원합니다. 예를 들어 드롭 다운 29600에서 선택하면 해당 인덱스 번호에 대한 데이터 만 표시되며 x 축 (시간)을 왼쪽에서 오른쪽으로 뒤집는 방법도 있습니다. 모든 솔루션에 미리 감사드립니다.
답변
편집 2-연결된 데이터 세트로 업데이트 된 제안
링크에 제공된 전체 데이터 세트를 사용하려면 해당 콘텐츠를 csv 파일로 다운로드하고 열고 콘텐츠를 복사 한 다음 아래 코드를 실행하여 다음 그림을 얻으십시오. 데이터는를 사용하여 선택됩니다 dfi = pd.read_clipboard(sep=',')
. 실제로 'Strike Price
인덱스 로 설정 하는 데 신경 쓸 필요가 없습니다 . 데이터 세트에는 많은 0
값이 있지만 예를 들어 선택하면 26100
최소한 의미있는 출력이 생성됩니다.

편집 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)
편집-축 반전으로 업데이트 된 제안
내 최신 제안은 섹션 아래 예에 빌드 Share data between callbacks
에서 dcc.Store 및 사용 사례에 대한 작업에 필요한 조정을합니다. 또한 다음을 사용하여 x 축 값을 뒤집는 기능을 통합했습니다.fig.update_layout(xaxis = dict(autorange='reversed'))
결과는 다음과 같습니다.

다음은 완전한 코드입니다.
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)
제안 1
수치를 사용 하는 방법 을 지정하지 않았습니다 . 그러나 JupyterLab에 있다고 가정하면 JupyterDash를 사용하는 것이 좋습니다. r 초보자 가 주석 의 링크 에서 지적했듯이 그림에 드롭 다운 기능을 직접 통합하는 것보다 훨씬 더 적합 합니다.
아래 코드 스 니펫 을 사용 하면 노트북 자체 에서'inline'
의미 하는 그림을 생성하도록 설정된 후속 앱에서 데이터를 표시 할 인덱스를 선택할 수 있습니다 . 이와 같은 접근 방식을 사용하는 데 관심이 있다면 x 축을 뒤집는 버튼도 구현할 수 있는지 확인할 수 있습니다.
앱:

완전한 코드
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)