Plotly Dash:如何在单击按钮时更改图像

Plotly Dash: How to change image on button click

我在尝试使用该示例来完成我的用例时无意中添加了以下线程的答案部分:

我正在寻找一个非常相似的解决方案,并且我尝试了建议 2(来自上述线程),因为我想根据用户选择的单击按钮来显示图像。我在一个目录下有 image_1image_2image_3image_4。到目前为止,我已经尝试过如下:

import dash
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 = dash.Dash()

# controls
controls = dcc.Card(
    [dcc.FormGroup(
        [
            dcc.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'}
                           )
        ],
    ),
        dcc.FormGroup(
            [dcc.Label(""), ]
        ),
    ],
    body=True,
    style={'font-size': 'large'})

app.layout = dcc.Container(
    [
        html.H1("Button for predictions"),
        html.Hr(),
        dcc.Row([
            dcc.Col([controls], xs=4),
            dcc.Col([
                dcc.Row([
                    dcc.Col(dcc.Graph(id="predictions")),
                ])
            ]),
        ]),
        html.Br(),
        dcc.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(debug=True)

但我收到以下错误,无法继续。

line 24, in <module>
    controls = dcc.Card(
AttributeError: module 'dash_core_components' has no attribute 'Card'

问题在于代码中使用的不同组件定义在不同的库中(dash_core_componentsdash_html_componentsdash_bootstrap_components),而您正试图从同一个库 (dash_core_components) 获取所有组件。例如,dcc.Card 应替换为 dbc.Card,其中 dbc 代表 dash_bootstrap_components,请参见下面的代码。

import pandas as pd
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import plotly.graph_objs as go

# 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 = dash.Dash()

# controls
controls = dbc.Card([

        dbc.FormGroup([

            html.Label('Options'),

            dcc.RadioItems(
                id='display_figure',
                options=[
                    {'label': 'None', 'value': 'None'},
                    {'label': 'Figure 1', 'value': 'Figure1'},
                    {'label': 'Figure 2', 'value': 'Figure2'},
                    {'label': 'Figure 3', 'value': 'Figure3'}
                ],
                value='None',
                labelStyle={
                    'display': 'inline-block',
                    'width': '10em',
                    'line-height': '0.5em'
                }
            )

        ]),

    ],

    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')),
                ])

            ]),
        ]),

    ],

    fluid=True,

)


@app.callback(
    Output('predictions', 'figure'),
    [Input('display_figure', 'value')],
)
def make_graph(display_figure):

    y = 'Prices'
    y2 = 'Predicted_prices'

    if 'Figure1' in display_figure:
        fig = go.Figure(go.Scatter(name=y, x=df.index, y=df[y], mode='lines'))
        fig.add_trace(go.Scatter(name=y, x=df.index, y=df[y2], mode='lines'))
        fig.update_layout(template='plotly_dark')
        fig.update_layout(title='Prices and predictions')

    elif 'Figure2' in display_figure:
        fig = go.Figure((go.Scatter(name=y, x=df.index, y=df[y], mode='lines')))
        fig.add_trace(go.Scatter(name=y, x=df.index, y=df[y2], mode='lines'))
        fig.update_layout(template='seaborn')
        fig.update_layout(title='Prices and predictions')

    elif 'Figure3' in display_figure:
        fig = go.Figure((go.Scatter(name=y, x=df.index, y=df[y], mode='lines')))
        fig.add_trace(go.Scatter(name=y, x=df.index, y=df[y2], mode='lines'))
        fig.update_layout(template='plotly_white')
        fig.update_layout(title='Prices and predictions')

    else:
        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)'))
        )

    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')

    return fig

if __name__ == '__main__':
    app.run_server(host='127.0.0.1', debug=True)

解决此问题后,您可以更新应用以显示静态 PNG 文件而不是交互式图形,如下所示。请注意,dcc.Graph 组件已被 html.Img 组件替换,figure 属性 已被 src 属性 替换。

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output

# app setup
app = dash.Dash()

# controls
controls = dbc.Card([

        dbc.FormGroup([

            html.Label('Options'),

            dcc.RadioItems(
                id='display_figure',
                options=[
                    {'label': 'None', 'value': 'None'},
                    {'label': 'Figure 1', 'value': 'Figure1'},
                    {'label': 'Figure 2', 'value': 'Figure2'},
                    {'label': 'Figure 3', 'value': 'Figure3'}
                ],
                value='None',
                labelStyle={
                    'display': 'inline-block',
                    'width': '10em',
                    'line-height': '0.5em'
                }
            )

        ]),

    ],

    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(html.Img(id='predictions')),
                ])

            ]),
        ]),

    ],

    fluid=True,

)

@app.callback(
    Output('predictions', 'src'),
    [Input('display_figure', 'value')],
)
def make_graph(display_figure):

    if 'Figure1' in display_figure:
        return app.get_asset_url('image_1.png')

    elif 'Figure2' in display_figure:
        return app.get_asset_url('image_2.png')

    elif 'Figure3' in display_figure:
        return app.get_asset_url('image_3.png')

    else:
        return None

if __name__ == '__main__':
    app.run_server(host='127.0.0.1', debug=True)

另请注意,PNG 文件需要保存在 assets 文件夹中,如下所示: