简体   繁体   English

为什么 plotly 不工作,它在一个回调中工作正常,但是当我添加第二个回调时,一切都崩溃了

[英]Why is plotly not working, it was working fine with one callback but when i added second callback everything crashed

Code was working with one callback function, but when i added a second callback(change title color feature) everything stopped working and i was given a blank canvas. I would like to be able to see the bar chart, with live adjutable size graph(first callback) and manually adjusting title color(second title) PLEASE HELP, THANK YOU IN ADVANCE: :>代码使用一个回调 function,但是当我添加第二个回调(更改标题颜色功能)时,一切都停止工作,我得到一个空白 canvas。我希望能够看到条形图,以及实时可调整大小的图表(第一次回调)和手动调整标题颜色(第二个标题)请帮助,提前谢谢你::>

有了这个数据框

from dash import Dash, dcc, html, Input, Output
import plotly.express as px
from jupyter_dash import JupyterDash
import dash_daq as daq

app = JupyterDash(__name__)

colors = {
    'background': '#111111',
    'text': '#7FDBFF'
}

picker_style = {'float': 'left', 'margin': 'auto'}

app.layout = html.Div([
    html.H1(
        children='Hello Dash',
        style={
            'textAlign': 'center',
            'color': colors['text']
        }
    ),
    html.P('Live adjustable graph-size(using Dash python)', style={'textAlign': 'center','color': colors['text']}),
    html.P('Please manually Change figure width of your choice(+-200px):', style={'textAlign': 'center','color': colors['text']}),
    # html.P("Change figure width:", style={'color': colors['text']}),
    # dcc.Slider(id='slider', min=500, max=1900, step=200, value=1700,
    #            marks={x: str(x) for x in [500, 700,900,1100,1300,1500,1700, 1900]},updatemode='drag',tooltip={"placement": "bottom", "always_visible": True}),
    dcc.Slider(id='slider', min=500, max=1200, step=100, value=1100,
               marks={x: str(x) for x in [500,600,700,800,900,1000,1100,1200]},updatemode='drag',tooltip={"placement": "bottom", "always_visible": True}),
    dcc.Graph(id="graph"),
    daq.ColorPicker(
        id='font', label='Font Color', size=150,
        style=picker_style, value=dict(hex='#119DFF')),
    daq.ColorPicker(
        id='title', label='Title Color', size=150,
        style=picker_style, value=dict(hex='#F71016')),
])


@app.callback(
    Output("graph", "figure"), 
    Input('slider', 'value'))
    
# def display_value(width):
#     return 'Width Value: {}'.format(width)

def resize_figure(width):
    fig = go.Figure(data=[
        go.Bar(name='Monthly Concession Passes',
               x=concession["cardholders"],
               y=concession["train_price"],
               text = concession["train_price"]),
        go.Bar(name='Average Fees using Card',
               x=concession["cardholders"],
               y = concession["MRT Fees"],
               text = round(concession["Average Card Fees"],1)),
        go.Bar(name='Single Trip Fees(cash)',
               x=concession["cardholders"],
               y=concession["Single Trip Fees(cash)"],
               text = round(concession["Single Trip Fees(cash)"],1))
    ])
    fig.update_layout(
        barmode='group',
        template="plotly_dark",
        paper_bgcolor=colors['background'],
        font_color=colors['text'],
        title_text=
        'Average Monthly Expenditure comparing Concession Passes, Card and Cash for buses',
        title_x=0.5,
        yaxis={
            'title': 'Fees ($)',
            # 'rangemode': 'tozero',
            'ticks': 'outside'
        })
    fig.update_layout(width=int(width))

    return fig

# @app.callback(
    # Output("graph", 'figure'), 
    # Input("font", 'value'),
    # Input("title", 'value')
    # )
# def update_bar_chart(font_color, title_color):
#     fig = go.Figure(data=[
#         go.Bar(name='Monthly Concession Passes',
#                x=concession["cardholders"],
#                y=concession["train_price"],
#                text = concession["train_price"]),
#         go.Bar(name='Average Fees using Card',
#                x=concession["cardholders"],
#                y = concession["MRT Fees"],
#                text = round(concession["Average Card Fees"],1)),
#         go.Bar(name='Single Trip Fees(cash)',
#                x=concession["cardholders"],
#                y=concession["Single Trip Fees(cash)"],
#                text = round(concession["Single Trip Fees(cash)"],1))
#     ])
#     fig.update_layout(
#         font_color=font_color['hex'],
#         title_font_color=title_color['hex'])
#     return fig


#app.run_server(mode="inline")

this is data in dictionary:这是字典中的数据:

{'cardholders': {0: 'Primary Student',
  1: 'Secondary Student',
  2: 'Polytechnic Student',
  3: 'University Student',
  4: 'Full-time National Serviceman',
  5: 'Senior Citizen',
  6: 'Adult (Monthly Travel Pass)'},
 'bus_price': {0: 24.0, 1: 29.0, 2: 29.0, 3: 55.5, 4: 55.5, 5: 64.0, 6: 128.0},
 'train_price': {0: 21.0,
  1: 26.5,
  2: 26.5,
  3: 48.0,
  4: 48.0,
  5: 64.0,
  6: 128.0},
 'hybrid_price': {0: 43.5,
  1: 54.0,
  2: 54.0,
  3: 90.5,
  4: 90.5,
  5: 64.0,
  6: 128.0},
 'Average Card Fees': {0: 8.149223099487395,
  1: 8.149223099487395,
  2: 8.149223099487395,
  3: 8.149223099487395,
  4: 20.208239081660064,
  5: 11.538449007368001,
  6: 20.208239081660064},
 'Average Cash Fees': {0: 17.756768358801253,
  1: 17.756768358801253,
  2: 17.756768358801253,
  3: 17.756768358801253,
  4: 30.431152919426268,
  5: 22.514797400960248,
  6: 30.431152919426268},
 'Single Trip Fees(cash)': {0: 69.0,
  1: 69.0,
  2: 69.0,
  3: 69.0,
  4: 69.0,
  5: 69.0,
  6: 69.0},
 'MRT Fees': {0: 12.0, 1: 12.0, 2: 12.0, 3: 12.0, 4: 40.5, 5: 20.7, 6: 40.5}}

The main issue is that you cannot have duplicate callback outputs – this isn't supported in Dash (probably because it could lead to a race condition if you have multiple callbacks trying to modify the same figure and they execute at the same time).主要问题是你不能有重复的回调输出——这在 Dash 中不受支持(可能是因为如果你有多个回调试图修改同一个图形并且它们同时执行,它可能会导致竞争条件)。 I understand why you want to break up your callbacks, but in this case, we can actually condense down your code quite a bit anyway, and make your callback more focused.我理解你为什么要分解你的回调,但在这种情况下,我们实际上无论如何都可以压缩你的代码,让你的回调更加集中。

First, I would define the figure outside of the callback and use dcc.Graph(id="graph", figure=fig) so that the figure is present when the app starts running – this way we don't need to redefine the figure in the callback every time it's executed – we'll design the callback so it only modifies only the width, font color, and title color of the figure's layout.首先,我会在回调之外定义图形并使用dcc.Graph(id="graph", figure=fig)以便在应用程序开始运行时图形出现——这样我们就不需要重新定义图形每次执行时都在回调中——我们将设计回调,使其修改图形布局的宽度、字体颜色和标题颜色。

Then we can combine your two callbacks into one by collecting all of the inputs from both of your original callbacks, and also pass the figure as an input.然后我们可以通过收集来自两个原始回调的所有输入,将您的两个回调合并为一个,并将图形作为输入传递。

Note that when a figure is passed to the callback as an input, it will be in the form of a dictionary, so we'll want to convert the fig argument from the callback to a go.Figure object using something like plotly_fig = go.Figure(fig_dict) .请注意,当一个图形作为输入传递给回调时,它将采用字典的形式,因此我们需要将回调中的 fig 参数转换为go.Figure图 object 使用类似plotly_fig = go.Figure(fig_dict) Then you can modify the layout of plotly_fig based on the other inputs using plotly_fig.update_layout(...) .然后,您可以使用plotly_fig.update_layout(...)根据其他输入修改plotly_fig的布局。

Here is a working example:这是一个工作示例:

import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from dash import Dash, dcc, html, Input, Output
from jupyter_dash import JupyterDash
import dash_daq as daq

concession = pd.DataFrame({'cardholders': {0: 'Primary Student',
  1: 'Secondary Student',
  2: 'Polytechnic Student',
  3: 'University Student',
  4: 'Full-time National Serviceman',
  5: 'Senior Citizen',
  6: 'Adult (Monthly Travel Pass)'},
 'bus_price': {0: 24.0, 1: 29.0, 2: 29.0, 3: 55.5, 4: 55.5, 5: 64.0, 6: 128.0},
 'train_price': {0: 21.0,
  1: 26.5,
  2: 26.5,
  3: 48.0,
  4: 48.0,
  5: 64.0,
  6: 128.0},
 'hybrid_price': {0: 43.5,
  1: 54.0,
  2: 54.0,
  3: 90.5,
  4: 90.5,
  5: 64.0,
  6: 128.0},
 'Average Card Fees': {0: 8.149223099487395,
  1: 8.149223099487395,
  2: 8.149223099487395,
  3: 8.149223099487395,
  4: 20.208239081660064,
  5: 11.538449007368001,
  6: 20.208239081660064},
 'Average Cash Fees': {0: 17.756768358801253,
  1: 17.756768358801253,
  2: 17.756768358801253,
  3: 17.756768358801253,
  4: 30.431152919426268,
  5: 22.514797400960248,
  6: 30.431152919426268},
 'Single Trip Fees(cash)': {0: 69.0,
  1: 69.0,
  2: 69.0,
  3: 69.0,
  4: 69.0,
  5: 69.0,
  6: 69.0},
 'MRT Fees': {0: 12.0, 1: 12.0, 2: 12.0, 3: 12.0, 4: 40.5, 5: 20.7, 6: 40.5}})

app = JupyterDash(__name__)

colors = {
    'background': '#111111',
    'text': '#7FDBFF'
}

picker_style = {'float': 'left', 'margin': 'auto'}

## define the figure 
fig = go.Figure(data=[
    go.Bar(name='Monthly Concession Passes',
           x=concession["cardholders"],
           y=concession["train_price"],
           text = concession["train_price"]),
    go.Bar(name='Average Fees using Card',
           x=concession["cardholders"],
           y = concession["MRT Fees"],
           text = round(concession["Average Card Fees"],1)),
    go.Bar(name='Single Trip Fees(cash)',
           x=concession["cardholders"],
           y=concession["Single Trip Fees(cash)"],
           text = round(concession["Single Trip Fees(cash)"],1))
])
fig.update_layout(
        barmode='group',
        template="plotly_dark",
        paper_bgcolor=colors['background'],
        font={
            'color': colors['text']
        },
        title_text=
        'Average Monthly Expenditure comparing Concession Passes, Card and Cash for buses',
        width=1100,
        title_x=0.5,
        title={
            'text': 'Fees ($)',
            'font': {'color': '#F71016'}
        },
        yaxis={
            # 'title': 'Fees ($)',
            # 'rangemode': 'tozero',
            'ticks': 'outside'
        })

app.layout = html.Div([
    html.H1(
        children='Hello Dash',
        style={
            'textAlign': 'center',
            'color': colors['text']
        }
    ),
    html.P('Live adjustable graph-size(using Dash python)', style={'textAlign': 'center','color': colors['text']}),
    html.P('Please manually Change figure width of your choice(+-200px):', style={'textAlign': 'center','color': colors['text']}),
    # html.P("Change figure width:", style={'color': colors['text']}),
    # dcc.Slider(id='slider', min=500, max=1900, step=200, value=1700,
    #            marks={x: str(x) for x in [500, 700,900,1100,1300,1500,1700, 1900]},updatemode='drag',tooltip={"placement": "bottom", "always_visible": True}),
    dcc.Slider(id='slider', min=500, max=1200, step=100, value=1100,
               marks={x: str(x) for x in [500,600,700,800,900,1000,1100,1200]},updatemode='drag',tooltip={"placement": "bottom", "always_visible": True}),
    dcc.Graph(id="graph", figure=fig),
    daq.ColorPicker(
        id='font', label='Font Color', size=150,
        style=picker_style, value=dict(hex='#119DFF')),
    daq.ColorPicker(
        id='title', label='Title Color', size=150,
        style=picker_style, value=dict(hex='#F71016')),
])

@app.callback(
    Output("graph", "figure"), 
    [Input("graph", "figure"),
    Input('slider', 'value'),
    Input("font", 'value'),
    Input("title", 'value')],
    prevent_initial_call=True
)
def update_figure(fig_dict, width, font_color, title_color):
    plotly_fig = go.Figure(fig_dict)
    plotly_fig.update_layout(
        width=int(width),
        font_color=font_color['hex'],
        title_font_color=title_color['hex']
    )
    return plotly_fig

## I ran this externally, but you can run this inline
app.run_server(mode="external", port=8050)

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM