2025, Nov 28 23:00

Troubleshooting Plotly in Flask: fix blank or misaligned charts by passing the full figure and syncing versions

Plotly charts rendering blank or wrong in a Flask app? Send the full serialized figure to Plotly.newPlot and match Plotly.py with Plotly.js versions to fix it.

When Plotly charts quietly misbehave in a Flask app, it’s frustrating. The data is valid, the code executes without exceptions, and yet visuals appear blank, misaligned, or simply wrong. If you’re passing figures from Python to JavaScript via PlotlyJSONEncoder and rendering with Plotly.newPlot(), the root cause can be deceptively simple.

Minimal context and the failing setup

The application uses Flask on the backend and Plotly.js in the browser. A figure is serialized with Plotly’s encoder and injected into the template. Everything looks correct on paper.

import json
import plotly
import plotly.graph_objs as gfx
from flask import render_template
@app.route("/meteo")
def report_view():
    chart = gfx.Figure(data=gfx.Bar(x=["Mon", "Tue", "Wed"], y=[2, 5, 3]))
    json_payload = json.dumps(chart, cls=plotly.utils.PlotlyJSONEncoder)
    return render_template("weather.html", chart_json=json_payload)
<div id="chartBox"></div>
<script>
    var cfg = {{ chart_json | safe }};
    Plotly.newPlot("chartBox", cfg.data, cfg.layout);
</script>

Despite valid x and y arrays, no console errors, and a correct CDN include, the browser either renders nothing, shows incorrect values, or misaligns traces.

What’s actually going wrong

The issue stems from how the serialized figure is passed to Plotly.newPlot(). The object coming from fig serialization already contains the exact structure Plotly.js expects. Splitting it up into cfg.data and cfg.layout can desynchronize expectations between the figure schema and the Plotly.js version in the browser. Another contributing factor can be a version mismatch between Plotly Python and Plotly.js, which often manifests as charts that render incorrectly without explicit errors.

The fix

Send the entire figure object to Plotly.newPlot() as a single argument, exactly as it was serialized. This aligns the structure with what Plotly.js expects and avoids silent breakage.

<div id="chartBox"></div>
<script>
    var cfg = {{ chart_json | safe }};
    Plotly.newPlot("chartBox", cfg);
</script>

In addition, make sure the Plotly Python and Plotly.js versions are aligned. Version mismatches can produce the exact symptoms described above. One real-world adjustment that resolved the problem for a developer looked like this:

Thanks! That fixed the issue. I checked my browser console and saw a version mismatch warning. I was using <script src="cdn.plot.ly/plotly-latest.min.js"></script>, which loads an outdated version (v1.58.5). I replaced it with <script src="cdn.plot.ly/plotly-2.32.0.min.js"></script>, and now all my charts render perfectly!

Why this matters

Plotly figures carry more than just data and layout; the schema encodes defaults, transforms, and details that Plotly.js consumes as a whole. When the browser receives the full figure payload, it can reconcile the visualization exactly as Python produced it. Hand-picking pieces increases the odds of subtle mismatches, especially across versions. Keeping Python and JavaScript sides in sync removes a class of bugs that waste time without producing clear errors.

Takeaways

If Plotly charts render incorrectly in a Flask app while the same figures look fine with .show() in Python, avoid splitting the figure into data and layout. Pass the complete serialized figure object directly to Plotly.newPlot(). Also verify that Plotly Python and Plotly.js are on compatible versions. With these two adjustments, charts should render consistently, with bars at the right heights, slices at the right proportions, and axes lined up as expected.