Very slow graph figure display

Hi all!

I have the following snippet. The idea is that I do give a data file as input and do some scientific processing on the backend using my Python library.

I want to interactively display two graphs on my Dash. The problem is that if I run the same code using a Jupyter Notebook, the execution and display is instantaneous (I use matplotlib as you may have noticed). With Dash though, that’s extremely slow. I recognise it’s something on my end, as when I do single-output (and not multiple) one graph is instantaneous but the plot_csd_graph is super slow.

I tried profiling it but the cProfiler says that’s the execution of the main function takes 0.5 seconds (but in reality, it takes around 20 seconds). Any ideas on how to debug or what am I doing wrong? Code follows!

Is that I need to save the output of the first class inside a hidden div or so?

Thanks for your time :slight_smile:

# Set the relative data path
MYPATH = pathlib.Path(__file__).parent
DATA_PATH = MYPATH.joinpath("data").resolve()

def plot_atd(f, my_grain, my_poly_order, my_smoothes, my_window_len):
    """ Plot the Arrival Time Distribution (ATD)

    Args:
    f (path): The f with the data (tab delim. CSV)

    Returns:
    It shows a plot. TODO: Return a matplotlib/plotly/JSON object
    """
    # Plot the ATD
    ms = MassSpectrum()
    ms.read_text_file(f, 0, my_grain, normalisationtype="bpi")
    ms.smoothingSG(my_window_len, my_smoothes, my_poly_order)
    ms.normalisation_bpi()
    # ms.select_ms_range(4200,9000)

    # fig = plt.figure(figsize=(12, 8)
    # ax = plt.subplot(311)
    fig, ax = plt.subplots()
    ms.plot_simulated_spectrum_simple(ax, color=tableau20[2])
    return fig, ms


def plot_pp_csd(my_simul_peak, msobj):
    pp = PeakPicking()
    pp.calculate_gradient(msobj.xvals, msobj.yvals)
    found_peaks = pp.find_peaks(1)

    fig, ax2 = plt.subplots()
    msobj.plot_simulated_spectrum_simple(ax2, color=tableau20[6])
    for peak in found_peaks:
        peak.plotSimulatedPeak(ax2, msobj.xvals, fwhm=my_simul_peak, color=tableau20[5])

    # plt.show()
    return fig

# Navigation bar and logo
logo = "assets/logo.png"
encoded_logo = base64.b64encode(open(logo, "rb").read())

navbar = dbc.Navbar(
    [
        html.A(
            dbc.Row(
                [
                    dbc.Col(
                        html.Img(
                            src="data:image/png;base64,{}".format(
                                encoded_logo.decode()
                            ),
                            height="20px",
                        )
                    ),
                    dbc.Col(
                        dbc.NavbarBrand(
                            "IMMS Dashboard",
                            className="navbar-brand",
                        )
                    ),
                ],
                align="center",
                justify="between",
                no_gutters=True,
            ),
            href="/",
        )
    ],
    color="light",
    dark=False,
)

# Content definitions
card_content_settings = [
    dbc.CardHeader("Choose your settings"),
    dbc.CardBody(
        [
            dcc.Upload(
                id="upload-data",
                children=dbc.Button("Upload Data", color="primary", className="mr-1"),
            ),
            html.Label("Select grain:"),
            dcc.Slider(
                id="grain-slider", min=0, max=20, value=10, marks={0: "0", 20: "20"}
            ),
            html.Label("Select the order of the poly:"),
            dcc.Slider(
                id="poly-order-slider",
                min=0,
                max=10,
                value=5,
                marks={0: "0", 5: "5", 10: "10"},
            ),
            html.Label("Select the smooth parameter:"),
            dcc.Slider(
                id="smoothes-slider", min=0, max=10, value=2, marks={0: "0", 10: "10"}
            ),
            html.Label("Select the window length:"),
            dcc.Slider(
                id="windowlen-slider",
                min=0,
                max=100,
                value=10,
                marks={0: "0", 50: "50", 100: "100"},
            ),
            html.Label("Simulated peak:"),
            dcc.Slider(
                id="simulpeak-slider",
                min=0,
                max=120,
                value=75,
                marks={0: "0", 50: "50", 100: "100"},
            ),
        ]
    ),
]

adt_content_settings = [
    dbc.CardHeader("ADT Plot"),
    dbc.CardBody([dcc.Graph(id="adt-graph")]),
]

csd_content_settings = [
    dbc.CardHeader("CSD Plot"),
    dbc.CardBody([dcc.Graph(id="csd-graph")]),
]

input_data_raw = dbc.Row(
    [
        dbc.Col(dbc.Card(card_content_settings, outline=True), md=2),
        dbc.Col(dbc.Card(adt_content_settings, outline=True), md=5),
        dbc.Col(dbc.Card(csd_content_settings, outline=True), md=5),
    ]
    # className="mb-4"
)

body = html.Div(
    [input_data_raw],
    style={"marginBottom": 50, "marginTop": 25, "text-align": "center"},
)

app.config["suppress_callback_exceptions"] = False
app.layout = html.Div([navbar, body])


@app.callback(
    [
        dash.dependencies.Output("adt-graph", "figure"),
        dash.dependencies.Output("csd-graph", "figure"),
    ],
    [
        dash.dependencies.Input("upload-data", "filename"),
        dash.dependencies.Input("grain-slider", "value"),
        dash.dependencies.Input("poly-order-slider", "value"),
        dash.dependencies.Input("smoothes-slider", "value"),
        dash.dependencies.Input("windowlen-slider", "value"),
        dash.dependencies.Input("simulpeak-slider", "value"),
    ],
)
def update_adt_graph(
    data_file,
    grain_value,
    poly_order_value,
    smoothes_value,
    windowlen_value,
    simulpeak_value,
):
    atd, msobj = plot_atd(
        DATA_PATH.joinpath(data_file),
        grain_value,
        poly_order_value,
        smoothes_value,
        windowlen_value,
    )
    return (
        tls.mpl_to_plotly(atd),
        go.Figure(tls.mpl_to_plotly(plot_pp_csd(simulpeak_value, msobj))),
    )