将第二个图形添加到 Dash 中的问题 app.layout

Issue adding second Graph into Dash app.layout

下面的代码将 运行 并显示 127.0.0.1 地址中的图表,但只有第一个图表能正确显示。第二个图表是 scatter_mapbox,它显示按用户选择的卧室数量筛选的给定县的价格。

当前输出:

第二张图应该是这样的:

app.layout = html.Div([
    html.Div([
        # Stuff that will be going on the top of the page

        html.H1('King County Housing Data/Graphs'),  # Heading 1
    ]),

    html.Div([
        html.H5('King County sqft-living / price Plot: 1900-2015'),
        dcc.Dropdown(id='grade-selector',
                     options=[{'label': i, 'value': i} for i in df['grade'].unique()],
                     value=7,  # Default Value
                     multi=False,  # Does  not allow you to select multiple grades
                     style={'width': '40%'}),  # Styling of the dropdown
        html.Div(id='output-container'),  # Callbacks Output #1
        dcc.Graph(id='grade-price')  # Callback's Output #2
    ]),
    # Interactive Graph using a map
    html.Div([
        html.H5('Geospatial heatmap of King County: 1900-2015'),
        dcc.Dropdown(id='Number-Of-Bedrooms',
                     options=[{'label': b, 'value': b} for b in df['bedrooms'].unique()],
                     value=2,
                     multi=False,
                     style={'width': '30%'},
                     ),
        html.Div(),
        dcc.Graph(id='bedrooms-selector')
    ])
])


# ----------------------------------------------------------------------------------------------------------------------
# App Callback & Function for Scatter Plot

@app.callback(
    [Output(component_id='output-container', component_property='children'),  # Outputs the html.Div
     Output(component_id='grade-price', component_property='figure')],  # Calls the graph dcc.Graph
    [Input(component_id='grade-selector', component_property='value')]  # Takes the input you put in with the
    # dcc.Dropdown and passes it into the Output
)
def gupdate_output_div(grade_selector):  # Makes the graph function

    container = 'The grade the user selected was {}'.format(grade_selector)  # Prints out the grade the user selected

    dff = df.copy()  # Makes a copy of the DataFrame, best practice
    dff = dff[dff['grade'] == grade_selector]  # Selects the grade that the user inputs

    # Creates the Plotly Graph
    fig = px.scatter(dff, x='sqft_living', y='price', marginal_y='violin', marginal_x='box', trendline='ols',
                     template='ggplot2')

    return [container, fig]


# ----------------------------------------------------------------------------------------------------------------------
# App Callback & Function for Map

@app.callback(
    [Output(component_id='bedrooms-selector', component_property='figure'),
     Input(component_id='Number-Of-Bedrooms', component_property='value')])


def update_output_div1(bedroomFilter):
    dff = df.copy()  # Makes a copy of the DataFrame, best practice
    dff = dff[dff['bedrooms'] == bedroomFilter]  # Selects the number of bedrooms

    color_by = 'price'  # Setting the scale for teh price
    color_upper = dff['price'].quantile(.05)  # Excluding the bottom .05%
    color_lower = dff['price'].quantile(.95)  # Excluding the top .05%

    fig = px.scatter_mapbox(dff, lat="lat", lon="lon",
                            animation_frame="decade",
                            # animation_group="country",
                            hover_name="price", hover_data=['price'],
                            color_continuous_scale=px.colors.sequential.Viridis,
                            color=color_by, range_color=[color_lower, color_upper],
                            opacity=0.4,
                            zoom=8.5, height=600)
    fig.update_layout(mapbox_style="open-street-map")
    fig.update_geos(fitbounds="locations")

    fig.update_layout(
        title={
            'text': "Housing Price",
            'y': 1,
            'x': 0.5,
            'xanchor': 'center',
            'yanchor': 'auto'},
        legend=dict(
            title="Home Price",
            orientation="h",
            yanchor="top")
)
    return fig


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

数据:

           price  sqft_living  grade  bedrooms  decade
0      13.180632     7.501082      7         5    1900
1      13.515081     8.384804      8         3    1900
2      13.345507     7.306531      7         2    1900
3      13.296317     7.319865      7         2    1900
4      13.091904     7.244228      7         4    1900
          ...          ...    ...       ...     ...
21603  14.253765     8.169053      9         3    2010
21604  12.345835     6.946976      9         3    2010
21605  13.233905     7.408531      8         2    2010
21606  12.873774     7.365180      8         3    2010
21607  14.346139     8.281471     11         4    2010

主要问题是你的第二个回调的语法:

@app.callback(
    [
        Output(component_id="bedrooms-selector", component_property="figure"),
        Input(component_id="Number-Of-Bedrooms", component_property="value"),
    ]
)
def update_output_div1(bedroomFilter):
    # ...
    return fig

这给出:

dash.exceptions.InvalidCallbackReturnValue: The callback ..bedrooms-selector.figure.. is a multi-output. Expected the output type to be a list or tuple but got Figure...

删除围绕 OutputInput 的列表。

所以做这样的事情:

@app.callback(
    Output(component_id="bedrooms-selector", component_property="figure"),
    Input(component_id="Number-Of-Bedrooms", component_property="value"),
)
def update_output_div1(bedroomFilter):
    # ...
    return fig

如果您随后 运行 应用程序和 select 第二个下拉列表中的值,地图将会显示。