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

Posted

技术标签:

【中文标题】将第二个图表添加到 Dash app.layout 的问题【英文标题】:Issue adding second Graph into Dash app.layout 【发布时间】:2021-10-12 07:17:05 【问题描述】:

下面的代码将运行并显示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

【问题讨论】:

【参考方案1】:

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

@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:回调 ..bedrooms-selector.figure.. 是一个多输出。 期望输出类型是列表或元组,但得到了 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

如果您随后运行该应用程序并从第二个下拉列表中选择一个值,则会显示地图。

【讨论】:

非常感谢您的帮助!所以回调需要[]的唯一时间是回调中有多个输出时?在我的第一个回调中,我需要 [ ]。 不,这甚至没有必要。你也可以为所有回调省略[],但是你会返回一个元组而不是一个列表:return output_val1output_val2而不是return [output_val1, output_val2]。重要的部分是输入、输出和状态不在同一个列表中。

以上是关于将第二个图表添加到 Dash app.layout 的问题的主要内容,如果未能解决你的问题,请参考以下文章

将第二个 UIToolbar 添加到 UITableViewController

将第二个表中的第二个(条件)结果添加到 SQL 查询

将第二个输入语句添加到代码后出错 [关闭]

将第二个功能添加到单个按钮

TypeError:将第二个图例添加到绘图时,“PathCollection”对象不可迭代

无法将第二个自引用 FK 添加到模型,导致无法确定主体结束错误