Plotly : 다중 인덱스 드롭 다운 옵션을 만드는 방법은 무엇입니까?

Nov 19 2020

아래와 같이 다른 시간대에 대해 동일한 인덱스 번호를 가진 데이터가 있습니다.

           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 축 (시간)을 왼쪽에서 오른쪽으로 뒤집는 방법도 있습니다. 모든 솔루션에 미리 감사드립니다.

답변

1 vestland Nov 22 2020 at 01:16

편집 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)