情节:单击按钮后如何显示图形?

时间:2020-09-09 12:19:06

标签: python plotly plotly-dash plotly-python

我只想在单击按钮后才使用图来显示图形,但不确定如何使它工作。我的身材存储在以下代码位中

    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组件,但是不确定如何定义此功能的回调。

1 个答案:

答案 0 :(得分:2)


建议3-dcc.Store()dcc.Loading

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

  1. 启动仅显示按钮的应用。
  2. 单击按钮以显示加载图标,然后
  3. 显示数字。
  4. 再次单击以显示三个数字的序列中的下一个数字。
  5. 用完图形序列后再次开始。

启动后,该应用将如下所示:

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 2Figure 3的加载时间设置为2秒。但是您可以轻松更改它。

当您单击三次以上时,我们将从头开始:

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 here

Figure 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


此建议将直接针对:

我想仅在单击按钮后才使用绘图显示图形

这意味着我不认为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

此外,如果您想进一步扩展此示例,此设置将使您可以轻松地处理 multiple 跟踪的 multiple 预测。试试看,让我知道如何为您解决问题。如果不清楚,那么当您发现时间时,我们可以深入研究细节。

在未启用预测功能的情况下,应用程序的外观如下:

关闭

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)