2025, Dec 12 21:02

Plotly и Flask: почему графики пустые и как это исправить

Графики Plotly в Flask рендерятся пусто или криво? Узнайте, как передавать фигуру целиком в Plotly.newPlot и согласовать версии Plotly и Plotly.js. Без ошибок.

Когда графики Plotly в приложении Flask ведут себя странно и без явных причин, это раздражает. Данные корректные, код выполняется без исключений, а визуализация получается пустой, смещённой или просто неверной. Если вы передаёте фигуры из Python в JavaScript через PlotlyJSONEncoder и рисуете их с помощью Plotly.newPlot(), первопричина может оказаться удивительно простой.

Краткий контекст и нерабочая конфигурация

Приложение использует Flask на бэкенде и Plotly.js в браузере. Фигура сериализуется энкодером Plotly и подставляется в шаблон. На первый взгляд всё выглядит правильно.

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>

При валидных массивах x и y, без ошибок в консоли и с корректным подключением CDN браузер то ничего не рисует, то показывает неверные значения, то смещает трейсы.

Что на самом деле не так

Проблема в том, как сериализованная фигура передаётся в Plotly.newPlot(). Объект после сериализации уже имеет ровно ту структуру, которую ждёт Plotly.js. Когда его разбивают на cfg.data и cfg.layout, могут расходиться ожидания между схемой фигуры и используемой в браузере версией Plotly.js. Дополнительно ситуацию усугубляет несовпадение версий Plotly в Python и Plotly.js: оно нередко приводит к неправильному рендерингу без явных ошибок.

Решение

Передавайте в Plotly.newPlot() весь объект фигуры одним аргументом — ровно в том виде, в каком он был сериализован. Так структура будет соответствовать ожиданиям Plotly.js, и скрытые поломки исчезнут.

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

Кроме того, убедитесь, что версии Plotly в Python и Plotly.js согласованы. Несовпадения версий дают именно те симптомы, что описаны выше. Вот реальный пример небольшого изменения, которое у разработчика полностью решило проблему:

Спасибо! Это исправило проблему. Я заглянул в консоль браузера и увидел предупреждение о несовпадении версий. У меня стоял <script src="cdn.plot.ly/plotly-latest.min.js"></script>, который подгружает устаревшую версию (v1.58.5). Я заменил его на <script src="cdn.plot.ly/plotly-2.32.0.min.js"></script> — и теперь все графики рендерятся идеально!

Почему это важно

Фигуры Plotly содержат не только данные и разметку: в схеме закодированы значения по умолчанию, трансформации и другие детали, которые Plotly.js воспринимает как единое целое. Когда браузер получает полный объект фигуры, он воссоздаёт визуализацию именно так, как её подготовил Python. Ручная «разборка» на части повышает риск тонких несоответствий, особенно между разными версиями. Синхронизация Python- и JavaScript-сторон убирает целый класс ошибок, отнимающих время и не выдающих понятных сообщений.

Главные выводы

Если в приложении Flask графики Plotly отображаются некорректно, хотя те же фигуры с .show() в Python выглядят нормально, не делите фигуру на data и layout. Передавайте в Plotly.newPlot() полностью сериализованный объект. Также проверьте совместимость версий Plotly в Python и Plotly.js. С этими двумя шагами графики будут рисоваться стабильно: столбцы — нужной высоты, секторы — нужной пропорции, оси — как следует выровнены.