Interactive plotly charts on jinja2 + flask

Tags:

It’s difficult to find explanation on how we can render plotly chart on flask + jinja, so I’m sharing my code snippets.

First, in python, given a figure, turn that into json response of flask.

import plotly
from flask import Response, jsonify
import json  # It's never "from flask import json"

def func(chart_name):
  ... generate necessary chart and save it to fig ...
  return jsonify(json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder))

The chart data will be served via /get_chart/<chart_name>

    @app.route("/get_chart/<string:chart_name>")
    def get_chart(chart_name: str):
        return <here, return the json from the func>

Prepare js code that can render the given json. Following code inserts a div to be filled with a chart. Chart data comes from /get_chart/<name>.

function fetchAndRenderChart(name) {
    const parentTag = document.currentScript.parentElement;
    const chartDiv = document.createElement("div");
    chartDiv.alt = name;
    const uniqueId =
        "plotly-chart-" + Math.random().toString(36).substring(2, 9);  # unique id for the div
    chartDiv.id = uniqueId;
    parentTag.appendChild(chartDiv);
    fetch(`/get_chart/${name}`)
        .then((response) => response.json())
        .then((data) => {
            let plotData = JSON.parse(data);
            Plotly.newPlot(uniqueId, plotData.data, plotData.layout, {
                responsive: true,  # responsive to the browser width
            });
        });
}

Now in your html, load relevant scripts:

<head>
  ...
  <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
  <script src="....<path to fetchAndRenderChart of the above>..."></script>
</head>

Now, whenever you need a chart, render it as below. Note that js code looks for a parent to insert a child div. I’m using <p>…</p>. You will need one.

    <p>
        <script>fetchAndRenderChart("{{ CHART_KEYS.BITCOIN_PROCESSED }}");</script>
    </p>

For better speed, I’m storing response of /get_chart/<chart_name> output in the redis using https://flask-caching.readthedocs.io/en/latest/ which is reloaded whenever I update dataset of my website.