✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🐇 Announcing Dash VTK for 3d simulation graphics. Check out the March webinar.

Unresponsive Plots

Hello,

I’m having a reoccurring issue with certain plots inside my dash application. As shown below, certain graphs lose their interactive capabilities, including zooming, clicking on the legend, resetting axes, etc., until I refresh the page. It only happens with certain plots but does not appear to be restricted to one type. I’ve had the issue occur with line graphs, stacked bar charts, and scatter plots. The only consistent theme is there a part of a dash application with several graphs that can be switched between with a dropdown Has anyone else had this issue and found a fix? Thanks!

Screen Recording 2021-02-17 at 12.04.35 AM

performance_graph = px.line(
            processed_df,
            x="hr_since_start",
            y=["SOC (%)", "SOF (%)", "Distance Driven", "FCStackP (kW)"],
            title=(
                f"SOC, SOF, Distance, and Fuel Cell Power vs Time"
                f" ({clean_str_date}_{veh_id})"
            ),
            labels={"hr_since_start": "time (hr)", "variable": "Parameter"},
            template=plot_color,
        )
        performance_graph.update_layout(
            font_family="Rockwell",
            hovermode="closest",
            newshape_line_color=newshape_line_color,
            legend=dict(
                traceorder="normal",
                font=dict(size=12, color="black"),
                bgcolor="White",
                bordercolor="Black",
                borderwidth=2,
                x=1.01,
                y=0.2,
                xanchor="left",
            ),
            margin=dict(
                r=250,
            ),
            annotations=[
                dict(
                    x=1.01,
                    y=0.9,
                    xref="paper",
                    yref="paper",
                    xanchor="left",
                    showarrow=False,
                    text=(
                        f"Results:<br>Total Mileage = {total_miles} miles<br>"
                        "Total Time = "
                        f"{total_time_hr} hr<br>H2 Consumed ="
                        f" {h2_consumed} kg"
                        f"<br>H2 Fueled = {h2_fueled} kg<br>Fuel Economy "
                        f"= {fuel_economy} mi/kg<br>Average Moving Speed"
                        f" = {avg_moving_speed} "
                        f"mph<br>Idle Time = {idle_time_hr} hr<br>H2"
                        " Consumed Idling "
                        f"= {h2_idling} kg"
                    ),
                    align="left",
                    bordercolor="black",
                    borderwidth=2,
                ),
            ],
       )

After continued troubleshooting, I can confirm this issue appears to be tied to the dropdown that allows the user to switch between graphs. The graph functions as expected until the user changes graphs and then returns to this graph. The graph is redrawn whenever the user selects a new graph in the dropdown so I’m not sure why this consistently causes issues with the interactivity. I included the code relevant to this particular graph and the dropdown callback.

@app.callback(
    [
        Output("performance-tooltip-container", "children"),
        Output("performance-graph-container", "children"),
    ],
    [Input("performance-graph-dropdown", "value"), Input("data-log-store", "data")],
    [State("veh-select-memory", "data")],
    prevent_initial_call=True,
)
def graph_selector(dropdown, processed_df, veh_selection_data):
    # =Update performance graph based on user selection through dropdown, click or radio=

    # Determine which input triggered the callback and its property. Triggered
    # is -1 list so most recent trigger is first in the list.
    ctx = callback_context
    input_id = ctx.triggered[0]["prop_id"].split(".")[0]
    input_id_prop = ctx.triggered[0]["prop_id"].split(".")[1]
    # =Load most recent saved data to construct
    # the perfomance graph if dropdown intializes the callback.=
    veh_id = veh_selection_data["veh_id"]
    clean_date = veh_selection_data["clean_date"]
    [performance_graph, tooltip] = update_performance_graph(
        veh_id, clean_date, dropdown, processed_df
    )

    return [
        dbc.Tooltip(
            tooltip,
            target="performance-tooltip-target",
            placement="right",
        ),
        dcc.Graph(
            id="performance-graph",
            figure=performance_graph,
            style={"height": 700},
            config={
                "toImageButtonOptions": {
                    "format": "svg",  # one of png, svg, jpeg, webp
                    "filename": "custom_graph",
                    "height": 700,
                    "width": 1200,
                    "scale": 1,  # Multiply title/legend/axis/canvas sizes by this factor
                },
                "modeBarButtonsToAdd": [
                    "drawline",
                    "drawopenpath",
                    "drawcircle",
                    "drawrect",
                    "eraseshape",
                ],
                "doubleClickDelay": 500,
            },
        ),
    ]

def update_performance_graph(veh_id, clean_date, dropdown, processed_df):
    """Show perfomance graph based on dropdown"""
    # =Graph Data Processing=
    # Select column from summary dataframe based on user selection
    row_id = [veh_id + ": " + clean_date.strftime("%Y-%m-%d")]
    selected_summary_data = summary_df.loc[summary_df["id"] == row_id[0]]
    # Strip needed date information for graph titles
    clean_str_date = clean_date.strftime("%m-%d-%Y")

    # ==Prepare summary data for graphs==
    total_miles = selected_summary_data["Mileage"].values[0]
    total_time_hr = selected_summary_data["Total Time (hr)"].values[0]
    h2_consumed = selected_summary_data["H2 Consumed (kg)"].values[0]
    h2_fueled = selected_summary_data["H2 Fueled (kg)"].values[0]
    fuel_economy = selected_summary_data["Fuel Economy (mi/kg)"].values[0]
    avg_moving_speed = selected_summary_data["Average Moving Speed (mph)"].values[0]
    idle_time_hr = selected_summary_data["Idle Time (hr)"].values[0]
    h2_idling = selected_summary_data["H2 Consumed Idling (kg)"].values[0]
    # Rename columns for all graphs
    processed_df.rename(
        columns={
            "hr_since_start": "Elapsed Time (hr)",
            "veh_spd_mph": "Speed (mph)",
            "soc": "SOC (%)",
            "sof": "SOF (%)",
            "distance_driven": "Distance Driven",
            "fc_stack_p": "FCStackP (kW)",
            "tractive_power_kw": "Tractive Power (kW)",
            "aux_power_kw": "Auxiliary Power (kW)",
            "tractive_aux_energy": "Traction and Auxiliary Loads (kWh)",
        },
        inplace=True,
    )

    # ==Speed binning on the hour==
    spd_processed_df = processed_df.copy()
    bin_cols = ["Speed (mph)", "Elapsed Time (hr)"]
    spd_processed_df[bin_cols] = spd_processed_df[bin_cols].apply(np.floor)

    # =Display Graph Based on Selection=
    if dropdown == perf_graphs[0]:
        # Create line graph with key performance parameters
        performance_graph = px.line()
        tooltip = graph2_tooltips[0]

    elif dropdown == perf_graphs[1]:
        performance_graph = px.scatter()
        tooltip = graph2_tooltips[1]
    elif dropdown == perf_graphs[2]:
        performance_graph = px.bar()
        tooltip = graph2_tooltips[2]
    elif dropdown == perf_graphs[3]:
        performance_graph = px.bar()
        tooltip = graph2_tooltips[3]

    return [performance_graph, tooltip]