Blank graph in Dash

I’m hvaing some trouble getting one of my graphs to display correctly, it takes values in an array at index point pointNumber. I’ve verified that the arrays are showing the right data but I cant get the graph to plot without being completely blank. Can anyone show me where I’m going wrong?

    ms_df = pd.DataFrame({'mz':scan_mz[pointNumber], 'intensity':scan_intensities[pointNumber]})

    fig.add_trace(px.scatter(ms_df, x='mz', y='intensity').data[0], row=2, col=1)

Hi @CFOA

Welcome to the community.

Could you please paste more of your code, so I can run it on my machine? You could replace the arrays with sample data instead of the actual data. But it’s important to see the code for initialising the fig object and how you’re attempting to show it to debug the code.

2 Likes

Here is the complete code, it takes an mzML file and displays a total ion chromatogram then when a point is clicked on the line graph the components of that point are meant to be displayed below in a new subplot. I have also included some sample data printed from the array, this seems to plot fine when i replace scan_mz[pointNumber] and scan_intensities[pointNumber]. Thanks.

[array([ 41. , 42. , 43. , 43.9, 45.1, 55. , 58.8, 73.1, 74. ,
75. , 75.9, 77.1, 96. , 100.1, 102.9, 116.9, 132.9, 135.1,
145.9, 147. , 148.1, 161. , 163. , 190.9, 191.9, 193. , 207. ,
208. , 209. , 253. , 281.2, 282. , 283.1, 329. , 355. , 405. ,
429. ], dtype=float32)]
[array([ 267., 206., 292., 723., 388., 211., 236., 1635., 294.,
1084., 331., 200., 226., 165., 194., 274., 403., 250.,
271., 395., 200., 183., 157., 465., 246., 237., 3329.,
758., 561., 403., 1187., 317., 323., 173., 217., 216.,
192.], dtype=float32)]

import dash
from dash import html, dcc
import plotly.express as px
from pyteomics import mzml
import pandas as pd
from dash.dependencies import Input, Output, State
import base64
from plotly.subplots import make_subplots
#import plotly.graph_objects as go

app = dash.Dash(__name__)

upload_component = dcc.Upload(
    id="upload-data",
    children=html.Div(["Drag and drop or select a mzML file"]),
    style={
        "width": "50%",
        "height": "60px",
        "lineHeight": "60px",
        "borderWidth": "1px",
        "borderStyle": "dashed",
        "borderRadius": "5px",
        "textAlign": "center",
    },
    multiple=False  
)

graph_component = dcc.Graph(id="graph", style={"height": "400px"})

fig = make_subplots(rows=2, cols=1)

pointNumber = 0
scan_mz = []
scan_intensities = []

debug_component = html.Div(
    id="output-container"
)

app.layout = html.Div(
    [
        upload_component,
        debug_component,
        graph_component,
    ]
)

@app.callback(
    Output(component_id="graph", component_property="figure"),
    Input(component_id="upload-data", component_property="contents"),
)
def process_mzml_and_plot(uploaded_file):
    if uploaded_file is not None:
        content_type, content_string = uploaded_file.split(",")
        decoded = base64.b64decode(content_string)

        with open("temp.mzml", "wb") as f:
            f.write(decoded)

        try:
            with mzml.read("temp.mzml") as reader:
                all_scan_times = []
                all_intensities = []

                for scan in reader:
                    scan_time_minutesStr = scan["scanList"]["scan"][0]["scan start time"]
                    intensity_array = scan["intensity array"]
                    mz = scan["m/z array"]
                    scan_time_minutes = round(float(scan_time_minutesStr), 5)

                    scan_intensities.append([intensity_array])
                    scan_mz.append([mz])
                    intensity = sum(intensity_array)
                    all_scan_times.append(scan_time_minutes)
                    all_intensities.append(intensity)

                df = pd.DataFrame({"time": all_scan_times, "intensity": all_intensities})

                fig.add_trace(px.line(df, x="time", y="intensity", title="TIC").data[0], row=1, col=1)

                fig.update_xaxes(showspikes=True, spikemode="across")
                fig.update_traces(hovertemplate=None, hoverinfo="none")
                fig.update_layout(hovermode="x unified", spikedistance=-1, height=800)

                return fig

        except Exception as e:
            print(f"Failed to process mzML file: {e}")
            return px.line(title="Failed to process mzML file")

    else:
        return dash.no_update

@app.callback(
    Output("graph", "figure", allow_duplicate=True),
    [Input("graph", "clickData")],  
    [State("graph", "figure")], 
    prevent_initial_call=True,
)
def handle_graph_click(clickData, figure):
    

    if clickData is not None:
        pointNumber = clickData['points'][0]['pointNumber']

        print(scan_mz[pointNumber])
        print(scan_intensities[pointNumber])

        ms_df = pd.DataFrame({'mz':scan_mz[pointNumber], 'intensity':scan_intensities[pointNumber]})

        fig.add_trace(px.scatter(ms_df, x='mz', y='intensity').data[0], row=2, col=1)

        return fig

if __name__ == "__main__":
    app.run_server(debug=True)

I found the problem!
I have replaced this:

                    scan_intensities.append([intensity_array])
                    scan_mz.append([mz])

with this:


                    scan_intensities.append(intensity_array)
                    scan_mz.append(mz)
2 Likes