python - Plotly:单击按钮后如何显示图形?

标签 python plotly plotly-dash plotly-python

我想使用 plotly 仅在单击按钮后显示图形,但不确定如何使其工作。我的图存储在以下代码位中

    fig1 = go.Figure(data=plot_data, layout=plot_layout)
然后我使用以下代码位定义我的应用程序布局:
app.layout = html.Div([
                #button
                html.Div(className='submit', children=[

                html.Button('Forecast', id='submit', n_clicks=0)
                ]),
                #loading 
                dcc.Loading(
                id="loading-1",
                type="default",
                children=html.Div(id="loading-output-1")
                ),
                #graph
                dcc.Graph(id= 'mpg-scatter',figure=fig),
    
                #hoverdata
                html.Div([
                    dcc.Markdown(id='hoverdata-text')
                ],style={'width':'50%','display':'inline-block'})
])

@app.callback(Output('hoverdata-text','children'),
             [Input('mpg-scatter','hoverData')])

def callback_stats(hoverData):
    return str(hoverData)


if __name__ == '__main__':
    app.run_server()
但问题是我只想首先显示按钮。然后当有人点击预测按钮时,加载功能出现,一秒钟后图表显示。我定义了一个 dcc.loading 组件,但不确定如何定义此功能的回调。

最佳答案

建议 3 - dcc.Store()dcc.Loading此建议使用 dcc.Store()组件,一个 html.Button()和一个 dcc.Loading组件来生成我现在理解的所需设置:

  • 启动一个只显示一个按钮的应用程序。
  • 单击按钮以显示加载图标,然后单击
  • 显示一个数字。
  • 再次单击以显示三个数字序列中的下一个数字。
  • 当图形序列用完时重新开始。

  • 启动后,该应用程序将如下所示:
    enter image description here
    现在您可以点击Figures一次搞定Figure 1下面,但只有在享受以下加载图标之一后:['graph', 'cube', 'circle', 'dot', or 'default']其中'dot'将触发 ptsd,和 'cube'恰好是我的最爱:
    正在加载...
    enter image description here
    图1
    enter image description here
    现在您可以继续点击 Figure 2Figure 3 .我已经为 Figure 1 设置了加载时间不少于 5 秒,然后是 Figure 2 的 2 秒和 Figure 3 .但是你可以很容易地改变它。
    当您单击超过 3 次时,我们将重新从头开始:
    enter image description here
    我希望我终于找到了您真正想要的解决方案。下面代码片段中的设置建立在描述的设置 here 的基础上,但已进行调整,希望能满足您的需求。让我知道这对你有什么作用!
    import pandas as pd
    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output, State
    import plotly.graph_objects as go
    from jupyter_dash import JupyterDash
    import dash_table
    from dash.exceptions import PreventUpdate
    import dash_bootstrap_components as dbc
    import time
    time.sleep(5) # Delay for 5 seconds.
    
    global_df = pd.DataFrame({'value1':[1,2,3,4],
                              'value2':[10,11,12,14]})
    
    # app = JupyterDash(__name__)
    app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
    
    df = pd.DataFrame({'Value 1': [1,2,3],
                       'Value 2':[10,11,12],
                       'Value 3':[14,12,9]})
    
    df.set_index('Value 1', inplace = True)
    
    app.layout = html.Div([
        # The memory store reverts to the default on every page refresh
        dcc.Store(id='memory'),
        # The local store will take the initial data
        # only the first time the page is loaded
        # and keep it until it is cleared.
        # Same as the local store but will lose the data
        # when the browser/tab closes.
        html.Table([
            html.Thead([
                html.Tr(html.Th('Click to launch figure:')),
                html.Tr([
                    html.Th(html.Button('Figures', id='memory-button')),
                ]),
            ]),
        ]),    
         dcc.Loading(id = "loading-icon",
                      #'graph', 'cube', 'circle', 'dot', or 'default'
                     type = 'cube',
                    children=[html.Div(dcc.Graph(id='click_graph'))])
    ])
    
    # Create two callbacks for every store.
    # add a click to the appropriate store.
    @app.callback(Output('memory', 'data'),
                  [Input('memory-button', 'n_clicks')],
                  [State('memory', 'data')])
    def on_click(n_clicks, data):
        if n_clicks is None:
            # prevent the None callbacks is important with the store component.
            # you don't want to update the store for nothing.
            raise PreventUpdate
    
        # Give a default data dict with 0 clicks if there's no data.
        data = data or {'clicks': 0}
        data['clicks'] = data['clicks'] + 1
        if data['clicks'] > 3: data['clicks'] = 0
        
        return data
    
    # output the stored clicks in the table cell.
    @app.callback(Output('click_graph', 'figure'),
                  # Since we use the data prop in an output,
                  # we cannot get the initial data on load with the data prop.
                  # To counter this, you can use the modified_timestamp
                  # as Input and the data as State.
                  # This limitation is due to the initial None callbacks
                  # https://github.com/plotly/dash-renderer/pull/81
                  [Input('memory', 'modified_timestamp')],
                  [State('memory', 'data')])
    def on_data(ts, data):
        if ts is None:
             #raise PreventUpdate
            fig = go.Figure()
            fig.update_layout(plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
                              yaxis = dict(showgrid=False, zeroline=False, tickfont = dict(color = 'rgba(0,0,0,0)')),
                              xaxis = dict(showgrid=False, zeroline=False, tickfont = dict(color = 'rgba(0,0,0,0)')))
            return(fig)
        data = data or {}
        0
        # plotly
        y = 'Value 2'
        y2 = 'Value 3'
        
        fig = go.Figure()
        fig.update_layout(plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
                              yaxis = dict(showgrid=False, zeroline=False, tickfont = dict(color = 'rgba(0,0,0,0)')),
                              xaxis = dict(showgrid=False, zeroline=False, tickfont = dict(color = 'rgba(0,0,0,0)')))
        
        if data.get('clicks', 0) == 1:
            fig = go.Figure(go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines'))
            fig.add_traces(go.Scatter(name=y, x=df.index, y=df[y2], mode = 'lines'))
            fig.update_layout(template='plotly_dark',
                              title = 'Plot number ' + str(data.get('clicks', 0)))
        
            # delay only after first click
            time.sleep(2)
        
        if data.get('clicks', 0) == 2:
            fig = go.Figure((go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines')))
            fig.add_traces(go.Scatter(name=y, x=df.index, y=df[y2], mode = 'lines'))
            fig.update_layout(template='seaborn',
                              title = 'Plot number ' + str(data.get('clicks', 0)))
            
        if data.get('clicks', 0) == 3:
            fig = go.Figure((go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines')))
            fig.add_traces(go.Scatter(name=y, x=df.index, y=df[y2], mode = 'lines'))
            fig.update_layout(template='plotly_white',
                              title = 'Plot number ' + str(data.get('clicks', 0)))
    
        # Aesthetics
        fig.update_layout(margin= {'t':30, 'b':0, 'r': 50, 'l': 50, 'pad': 0},
                          hovermode = 'x',
                          legend=dict(x=1,y=0.85),
                          uirevision='constant')
        
        # delay for every figure
        time.sleep(2)
        return fig
    
    app.run_server(mode='external', port = 8070, dev_tools_ui=True,
              dev_tools_hot_reload =True, threaded=True)
    

    建议2

    经过一些交流,我们现在知道您想要:
  • 只先显示一个按钮(问题)
  • 当底部显示图 1 时单击按钮,第二次单击显示图 2,第三次单击显示图 3(评论)

  • 我做了一个新的设置,应该满足上述所有标准。起初,只显示控制选项。然后您可以选择要显示的图形:Fig1, Fig2 or Fig3 .对我来说,如果您必须循环浏览图形以选择要显示的图形,这似乎是一个非最佳的用户界面。所以我选择了这样的单选按钮:
    enter image description here
    现在您可以自由选择要显示的图形,或返回不显示任何内容,如下所示:
    启动时或 None 时显示被选中:
    enter image description hereFigure 1被选中
    enter image description here
    您仍未提供数据样本,因此我仍在使用来自 Suggestion 1 的合成数据。 ,而是让不同的布局指示显示的是哪个图形。我希望这适合您的需求,因为您似乎希望为不同的图形使用不同的布局。
    完整代码 2
    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_bootstrap_components as dbc
    import dash_core_components as dcc
    import dash_html_components as html
    import pandas as pd
    import plotly.graph_objs as go
    from dash.dependencies import Input, Output
    import numpy as np
    from plotly.subplots import make_subplots
    import plotly.express as px
    pd.options.plotting.backend = "plotly"
    from datetime import datetime
    
    palette = px.colors.qualitative.Plotly
    
    # sample data
    df = pd.DataFrame({'Prices': [1,10,7,5, np.nan, np.nan, np.nan],
                        'Predicted_prices':[np.nan, np.nan, np.nan, 5, 8,6,9]})
    
    # app setup
    app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
    
    # controls
    controls = dbc.Card(
          [dbc.FormGroup(
                [
                    dbc.Label("Options"),
                                    dcc.RadioItems(id="display_figure", 
                                    options=[   {'label': 'None', 'value': 'Nope'},
                                                {'label': 'Figure 1', 'value': 'Figure1'},
                                                {'label': 'Figure 2', 'value': 'Figure2'},
                                                {'label': 'Figure 3', 'value': 'Figure3'}
                                    ],
                                    value='Nope',
                                    labelStyle={'display': 'inline-block', 'width': '10em', 'line-height':'0.5em'}
                                    ) 
                ], 
            ),
            dbc.FormGroup(
                [dbc.Label(""),]
            ),
        ],
        body=True,
        style = {'font-size': 'large'})
    
    app.layout = dbc.Container(
        [
            html.H1("Button for predictions"),
            html.Hr(),
            dbc.Row([
                dbc.Col([controls],xs = 4),
                dbc.Col([
                    dbc.Row([
                        dbc.Col(dcc.Graph(id="predictions")),
                    ])
                ]),
            ]),
            html.Br(),
            dbc.Row([
     
            ]), 
        ],
        fluid=True,
    )
    
    @app.callback(
        Output("predictions", "figure"),
        [Input("display_figure", "value"),
    
        ],
    )
    def make_graph(display_figure):
    
        # main trace
        y = 'Prices'
        y2 = 'Predicted_prices'
    #     print(display_figure)
        if 'Nope' in display_figure:
            fig = go.Figure()
            fig.update_layout(plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
                              yaxis = dict(showgrid=False, zeroline=False, tickfont = dict(color = 'rgba(0,0,0,0)')),
                              xaxis = dict(showgrid=False, zeroline=False, tickfont = dict(color = 'rgba(0,0,0,0)')))
            return fig
    
        if 'Figure1' in display_figure:
            fig = go.Figure(go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines'))
            fig.add_traces(go.Scatter(name=y, x=df.index, y=df[y2], mode = 'lines'))
            fig.update_layout(template='plotly_dark')
    
        # prediction trace
        if 'Figure2' in display_figure:
            fig = go.Figure((go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines')))
            fig.add_traces(go.Scatter(name=y, x=df.index, y=df[y2], mode = 'lines'))
            fig.update_layout(template='seaborn')
    
        if 'Figure3' in display_figure:
            fig = go.Figure((go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines')))
            fig.add_traces(go.Scatter(name=y, x=df.index, y=df[y2], mode = 'lines'))
            fig.update_layout(template='plotly_white')
    
        # Aesthetics
        fig.update_layout(margin= {'t':30, 'b':0, 'r': 0, 'l': 0, 'pad': 0})
        fig.update_layout(hovermode = 'x')
        fig.update_layout(showlegend=True, legend=dict(x=1,y=0.85))
        fig.update_layout(uirevision='constant')
        fig.update_layout(title = "Prices and predictions")
    
        return(fig)
    
    app.run_server(mode='external', port = 8005)
    

    建议 1

    该建议将直接侧重于:

    I want to use plotly to display a graph only after a button is clicked


    这意味着我不认为 dcc.Loading()必须是答案的一部分。

    我发现 dcc.Checklist()是一个非常通用且用户友好的组件。如果设置正确,它将显示为必须单击的按钮(或必须标记的选项)才能触发某些功能或可视化。
    这是一个基本设置:
    dcc.Checklist(
        id="display_columns",                    
        options=[{"label": col + ' ', "value": col} for col in df.columns],
        value=[df.columns[0]],
        labelStyle={'display': 'inline-block', 'width': '12em', 'line-height':'0.5em'}
    
    这是它的样子:
    enter image description here
    除其他外,还有以下几行 dcc.Checklist()组件会让你转动 Prediction随心所欲地打开和关闭。
    # main trace
    y = 'Prices'
    fig = make_subplots(specs=[[{"secondary_y": True}]])
    if 'Prices' in display_columns:
        fig.add_trace(go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines'), secondary_y=False)
    
    # prediction trace
    if 'Predicted_prices' in display_columns:
        fig.add_trace(go.Scatter(name = 'predictions', x=df.index, y=df['Predicted_prices'], mode = 'lines'), secondary_y=False
    
    除此之外,如果您想进一步扩展此示例,此设置将让您轻松处理多个跟踪的多个预测。试一试,让我知道它对你有用。如果有什么不清楚的,那么我们可以在您找到时间时深入了解细节。
    以下是应用程序在启用和不启用预测的情况下的外观:
    关闭
    enter image description here
    开启
    enter image description here
    完整代码:
    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_bootstrap_components as dbc
    import dash_core_components as dcc
    import dash_html_components as html
    import pandas as pd
    import plotly.graph_objs as go
    from dash.dependencies import Input, Output
    import numpy as np
    from plotly.subplots import make_subplots
    import plotly.express as px
    pd.options.plotting.backend = "plotly"
    from datetime import datetime
    
    palette = px.colors.qualitative.Plotly
    
    # sample data
    df = pd.DataFrame({'Prices': [1,10,7,5, np.nan, np.nan, np.nan],
                        'Predicted_prices':[np.nan, np.nan, np.nan, 5, 8,6,9]})
    
    # app setup
    app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
    
    # input controls
    controls = dbc.Card(
          [dbc.FormGroup(
                [
                    dbc.Label("Options"),
                                    dcc.Checklist(
                                        id="display_columns",                    
                                        options=[{"label": col + ' ', "value": col} for col in df.columns],
                                        value=[df.columns[0]],
                                        labelStyle={'display': 'inline-block', 'width': '12em', 'line-height':'0.5em'}
                        #clearable=False,
                        #multi = True
                    ),
                ], 
            ),
    
            dbc.FormGroup(
                [dbc.Label(""),]
            ),
        ],
        body=True,
        style = {'font-size': 'large'})
    
    app.layout = dbc.Container(
        [
            html.H1("Button for predictions"),
            html.Hr(),
            dbc.Row([
                dbc.Col([controls],xs = 4),
                dbc.Col([
                    dbc.Row([
                        dbc.Col(dcc.Graph(id="predictions")),
                    ])
                ]),
            ]),
            html.Br(),
            dbc.Row([
     
            ]), 
        ],
        fluid=True,
    )
    
    @app.callback(
        Output("predictions", "figure"),
        [Input("display_columns", "value"),
    
        ],
    )
    def make_graph(display_columns):
    
        # main trace
        y = 'Prices'
        fig = make_subplots(specs=[[{"secondary_y": True}]])
        if 'Prices' in display_columns:
            fig.add_trace(go.Scatter(name=y, x=df.index, y=df[y], mode = 'lines'), secondary_y=False)
        
        # prediction trace
        if 'Predicted_prices' in display_columns:
            fig.add_trace(go.Scatter(name = 'predictions', x=df.index, y=df['Predicted_prices'], mode = 'lines'), secondary_y=False)
        
        # Aesthetics
        fig.update_layout(margin= {'t':30, 'b':0, 'r': 0, 'l': 0, 'pad': 0})
        fig.update_layout(hovermode = 'x')
        fig.update_layout(showlegend=True, legend=dict(x=1,y=0.85))
        fig.update_layout(uirevision='constant')
        fig.update_layout(template='plotly_dark',
                          plot_bgcolor='#272B30', 
                          paper_bgcolor='#272B30')
        fig.update_layout(title = "Prices and predictions")
        return(fig)
    
    app.run_server(mode='external', port = 8005)
    

    关于python - Plotly:单击按钮后如何显示图形?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63811550/

    相关文章:

    python - 多迹线图表上不必要的额外边距

    python - 无法在 Microsoft Azure 上运行 Dash 应用程序

    python - Dash,如何根据点击的按钮进行回调?

    python - 如果有新数据到来,则显示加载状态几秒钟,然后显示图形,否则保持 Dash 应用程序 python 中的图形不变

    python - 如何将多迹线图制作为可重用代码?

    python - Jupyter笔记本: module not found even after pip install

    python - 哪种序列类型不支持 "extend slicing"?

    Python3,在另一个类中使用对象实例

    javascript - Plotly.js 自动缩放

    python - 我们如何才能在 plotly boxplot 背后获得不同的统计数据?