如果未单击第一张图,则不会加载第二张图(Plotly Dash)

If First Graph Not Clicked, 2nd Graph Does Not Load (Plotly Dash)

我正在做一个可视化美国总统选举数据的 Dash Plotly 项目。我的项目的一部分显示了可以通过选择不同的州来更改的县等值线图。这张地图的右边是两党在任何县的每次选举中获得的选票百分比。这第二张图是通过点击分区统计县地图来填充的。

一切正常,但我遇到的问题是,当我切换状态时,分区统计图更新得很好,但第二个图表变为空白并且在我再次单击地图之前不会填充。

我试图通过将第二个图表设置为在点击一个县之前切换状态时首先按字母顺序显示第一个县来解决这个问题。但是,它似乎无法正常工作。

这是我的代码的一小段:

import pandas as pd
import numpy as np
import dash
import os
from urllib.request import urlopen
import json
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.express as px
import plotly.graph_objects as go
from flask import Flask, Response

with urlopen(
    "https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json"
) as response:
    counties = json.load(response)

data = [
    ["Delaware", "Kent County", 10001, 0.467, 0.517, -75.513210, 39.156876, 2012],
    ["Delaware", "New Castle County", 10003, 0.322, 0.663, -75.513210, 39.156876, 2012],
    ["Delaware", "Sussex County", 10005, 0.559, 0.428, -75.513210, 39.156876, 2012],
    [
        "District of Columbia",
        "District of Columbia",
        11001,
        0.0712,
        0.913,
        -77.014468,
        38.910270,
        2012,
    ],
    ["Delaware", "Kent County", 10001, 0.498, 0.449, -75.513210, 39.156876, 2016],
    ["Delaware", "New Castle County", 10003, 0.327, 0.623, -75.513210, 39.156876, 2016],
    ["Delaware", "Sussex County", 10005, 0.591, 0.371, -75.513210, 39.156876, 2016],
    [
        "District of Columbia",
        "District of Columbia",
        11001,
        0.041,
        0.928,
        -77.014468,
        38.910270,
        2016,
    ],
    ["Delaware", "Kent County", 10001, 0.471, 0.511, -75.513210, 39.156876, 2020],
    ["Delaware", "New Castle County", 10003, 0.307, 0.678, -75.513210, 39.156876, 2020],
    ["Delaware", "Sussex County", 10005, 0.550, 0.438, -75.513210, 39.156876, 2020],
    [
        "District of Columbia",
        "District of Columbia",
        11001,
        0.053,
        0.921,
        -77.014468,
        38.910270,
        2020,
    ],
]


data = pd.DataFrame(
    data,
    columns=[
        "State",
        "County",
        "fips_code",
        "perc_gop",
        "perc_dem",
        "lon",
        "lat",
        "year",
    ],
)
state_choices = data["State"].sort_values().unique()

app = dash.Dash(__name__, assets_folder=os.path.join(os.curdir, "assets"))
server = app.server
app.layout = html.Div(
    [
        html.Div(
            [
                dcc.Dropdown(
                    id="dropdown1",
                    options=[{"label": i, "value": i} for i in state_choices],
                    value=state_choices[0],
                )
            ],
            style={"width": "100%", "display": "inline-block", "text-align": "center"},
        ),
        # State Map with County Choropleth
        html.Div(
            [dcc.Graph(id="state_map")],
            style={"width": "50%", "display": "inline-block", "text-align": "center"},
        ),
        # Party Line % Graph
        html.Div(
            [dcc.Graph(id="party_line_graph")],
            style={"width": "50%", "display": "inline-block", "text-align": "center"},
        ),
        html.Pre(id="click-data"),
    ]
)


@app.callback(Output("state_map", "figure"), Input("dropdown1", "value"))
def update_figure3(state_select):
    new_df = data[data["State"] == state_select]

    avg_lat = new_df["lat"].mean()
    avg_lon = new_df["lon"].mean()

    fig = px.choropleth_mapbox(
        new_df,
        geojson=counties,
        locations="fips_code",
        color="perc_gop",
        color_continuous_scale="balance",
        mapbox_style="carto-positron",
        zoom=6,
        center={"lat": avg_lat, "lon": avg_lon},
        opacity=0.5,
        labels={
            "State": "State",
            "County": "County",
            "perc_gop": "% Republican",
            "perc_dem": "% Democratic",
        },
        hover_data={
            "fips_code": False,
            "perc_gop": False,
            "State": True,
            "County": True,
            "perc_gop": True,
            "perc_dem": True,
        },
    )
    fig.update_layout(
        margin={"r": 0, "t": 0, "l": 0, "b": 0}, coloraxis_showscale=False
    )
    return fig


@app.callback(
    Output("party_line_graph", "figure"),
    Input("dropdown1", "value"),
    Input("state_map", "clickData"),
)
def update_figure4(state_select, click_county_select):
    if click_county_select is not None:
        new_df = data[data["State"] == state_select]
        county_id = click_county_select["points"][0]["customdata"][3]
        new_df2 = new_df[new_df["County"] == county_id]
    else:
        new_df = data[data["State"] == state_select]
        county_id = new_df["County"][0]
        new_df2 = new_df[new_df["County"] == county_id]

    fig = go.Figure()
    fig.add_trace(
        go.Scatter(
            x=new_df2["year"],
            y=new_df2["perc_gop"],
            name="GOP %",
            line=dict(color="firebrick", width=4),
        )
    )
    fig.add_trace(
        go.Scatter(
            x=new_df2["year"],
            y=new_df2["perc_dem"],
            name="DEM %",
            line=dict(color="royalblue", width=4),
        )
    )
    fig.update_layout(height=350, title=f"Results from {county_id}")
    fig.update_layout(
        title={"x": 0.5, "xanchor": "center", "yanchor": "top"}, yaxis_tickformat="%"
    )
    return fig


app.run_server(host="0.0.0.0", port="8051")

有人可以帮我找到我丢失的部分吗?任何帮助,将不胜感激! 谢谢!

问题出在您的 update_figure4 回调中的这一行(在 else 语句内):

county_id = new_df["County"][0]

如果您加载页面并且 select District of Columbia 在下拉列表中 new_df["County"] 的值如下:

3     District of Columbia
7     District of Columbia
11    District of Columbia
Name: County, dtype: object

如您所见,返回的数据中没有索引为 0 的行,因此 new_df["County"][0] 将失败。

new_df["County"][3] 在这种情况下会起作用,但问题当然是当您在数据集中可能并不总是有索引为 3 的行在回调中访问它。

改为使用iloc:

county_id = new_df["County"][0]

根据评论更新

if I click a county even just once and THEN switch to a new state from the dropdown menu, the second graph goes blank again

这样做的原因是,您还需要考虑 selected 县的情况,但该县与下拉列表中 selected 的州不对应。

由于您的 else 子句中已经有逻辑,如果没有县 selected,则可以为右侧的图表提供默认值,您可以在县从点击数据与 selected 状态不对应。

所以你可以这样做:

if click_county_select:
    new_df = data[data["State"] == state_select]
    county_id = click_county_select["points"][0]["customdata"][3]
    new_df2 = new_df[new_df["County"] == county_id]

    counties = new_df["County"].values
    if county_id not in counties:
        new_df = data[data["State"] == state_select]
        county_id = new_df["County"].iloc[0]
        new_df2 = new_df[new_df["County"] == county_id]
else:
    new_df = data[data["State"] == state_select]
    county_id = new_df["County"].iloc[0]
    new_df2 = new_df[new_df["County"] == county_id]

现在我只是懒洋洋地复制粘贴了新 if 语句中 else 子句中的代码,但是您可以在其自己的函数中提取重用逻辑,然后多次调用这个符合不要重复你自己。