Web Visualization with Plotly and Flask.
By: Alan Jones
Tags: Data Visualization, Flask, Web App Development, Dash, Plotly

Data Visualization

Web Visualization with Plotly and Flask.

A multi-page web app using Plotly and Flask — image by author

Why would you want to write HTML in Python? It baffles me. But that is what you need to do if you want to write a Dash app.

While I understand that there is a certain amount of satisfaction in having all your code in a single file, it seems to me that if you know enough about HTML to code it in a different language then you certainly know enough to write it in HTML!

I’d love for Dash to be the solution to writing web visualization apps but I’m not convinced.

Consider the following:

A Dash app is fundamentally a Flask app that incorporates Plotly. Writing an actual Flask app that uses Ploty is not difficult. Writing a Flask app gives you more control over what you write and is more flexible.

So, while acknowledging that Dash is a well constructed and well-intentioned tool with which you can create sophisticated and impressive web apps, I’d like to present what I think is a simpler solution — at least for simple web apps.

We are going to see just how straightforward it is to build a multi-page web app with Flask that contains Plotly charts (a task that is not straightforward with the open source version of Dash).

But first let’s do a quick comparison of a simple Dash app and it’s Flask equivalent.

A Simple Dash App

Below is a listing of a slightly modified version of a Dash tutorial — the original tutorial is here and you can download the source code from github.

There are a number of parts to it. First, we import the appropriate libraries, then on the next line, we fire up a Dash app. Next we define a Pandas dataframe and then draw a bar graph putting it in the variable fig.

The last section creates a layout for the app. Creating a layout is basically defining a web page as a document object model in Python. The page that is defined consists of a header “Hello Dash”, some text, “Dash: A web application framework for Python.” and, finally, the graph.

import dash

import dash_core_components as dcc

import dash_html_components as html

import plotly.express as px

import pandas as pd app = dash.Dash(__name__) df = pd.DataFrame({

“Fruit”: [“Apples”, “Oranges”, “Bananas”, “Apples”, “Oranges”, “Bananas”],

“Amount”: [4, 1, 2, 2, 4, 5],

“City”: [“SF”, “SF”, “SF”, “Montreal”, “Montreal”, “Montreal”]

}) fig = px.bar(df, x=”Fruit”, y=”Amount”, color=”City”,

barmode=”group”) app.layout = html.Div(children=[

html.H1(children=’Hello Dash’),

html.Div(children=’’’

Dash: A web application framework for Python.

‘’’),

dcc.Graph(

id=’example-graph’,

figure=fig

)

]) if __name__ == ‘__main__’:

app.run_server(debug=True)

Code reproduced courtesy of Plotly — Copyright © 2019 Plotly, MIT License

It’s not terrifically difficult to follow and it produces a web page that looks like this:

A single page web app using Dash — image by author

Now let’s look at the Flask equivalent.

A simple Flask + Plotly app

A Flask app that uses Plotly is a little different. Firstly, there are two parts: the Flask app itself and one or more HTML templates. The Flask app does a similar job to the Dash app but without building the actual web page. The web page is an HTML template and we pass the Plotly data to it from the Flask app so it can display the charts.

The Flask part has a similar structure to Dash: first the (slightly different) imports, then the Flask app, but now a difference. The next part of the code is inside a function definition called notdash() and this has an app.route decorator.

from flask import Flask, render_template

import pandas as pd

import json

import plotly

import plotly.express as px app = Flask(__name__) @app.route(‘/’)

def notdash():

df = pd.DataFrame({

“Fruit”: [“Apples”, “Oranges”, “Bananas”, “Apples”, “Oranges”, “Bananas”],

“Amount”: [4, 1, 2, 2, 4, 5],

“City”: [“SF”, “SF”, “SF”, “Montreal”, “Montreal”, “Montreal”]

}) fig = px.bar(df, x=”Fruit”, y=”Amount”, color=”City”, barmode=”group”) graphJSON = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) return render_template(‘notdash.html’, graphJSON=graphJSON)

In Flask URLs are mapped onto functions and the decorator tells us which function corresponds to a particular url, or route. In our case we have a function called notdash() and this is called for the url “/” (i.e. the root url for the web site). We’ll see shortly that using Flask we can specify other pages with different urls.

(If you need a quick get-up-to-speed on building and running Flask apps, see How to Create and Run a Flask App for 5 minute intro)

Within notdash() we create the dataframe and, as in the previous version, create a plot in the variable fig. Now we change things a little. Our next step is to convert the plot to JSON using json.dumps() and the JSON encoder that comes with Plotly. The reason for doing this is that the web page will use the Plotly Javascript library to render the plot and this requires the Plotly chart encoded as JSON.

The next line of code tells Flask to use an HTML template called notdash.html and pass to it the JSON code.

The template is the web page that will be displayed. It is the equivalent of the layout from the Dash app but we write actual HTML in an HTML file: the body of the HTML contains a header (that displays a message) and a <div> element that will contain the Plotly chart (for Plotly to work we need to give this <div> an id and set its class attribute to chart).

The remainder of the file is a few lines of Javascript boilerplate code that will be common to any Flask/Plotly app. First, we import the Plotly Javascript library. Then we create our own script which sets a variable to the imported JSON code and then calls the plot method from the Plotly library to display the chart.

Note that the way that we tell Python to put the JSON data into the HTML is to use the notation {{name}}, where name is the parameter passed to the template from Python and the curly braces denote that it is a placeholder for a parameter.

<!doctype html>

<html>

<body>

<h1>Hello Plotly (but not Dash)</h1>

<div id=”chart” class=”chart”></div>

</body> <script src=”https://cdn.plot.ly/plotly-latest.min.js"></script>

<script type=”text/javascript”>

var graphs = {{graphJSON | safe}};

Plotly.plot(‘chart’,graphs,{});

</script> </html>

Here is what it looks like:

A single page web app using Plotly and Flask — image by author

Pretty similar to the Dash version, right?.

I have to admit that my non-Dash version is marginally longer but, from my point of view it is more logical to write your web page as an HTML file and your web app in Python.

More importantly, it allows you the flexibility to write multi-page apps.

Multi-page app

In this section we are going to produce an app that consists of three pages: two pages that contain different charts and an index page that contains links to the other two pages. This is something that you often might want to do when you have a number of different charts or dashboards to include on a single web site but is not straightforward when using Dash.

The image below shows the three pages of the app.

A multi-page web app using Plotly and Flask — image by author

It’s marginally more sophisticated than the previous one in that the charts pages (notdash2.html) now have three parameters, the chart (as before) plus a header and a description — the placeholders in the HTML code are {{graphJSON}},{{header}} and {{description}}.

The Flask code now has three routes for the three pages. The first is the root of the web app and the other two are for the two chart pages. Notice that the charts have the same template as they use the same layout but different headers, descriptions and charts are passed to those templates.

So that’s not too difficult, I think, a multi-page web app that uses Plotly to display charts from Pandas dataframes in a Flask app.

Callbacks

But, I hear you died-in-the-wool Dash aficionados say, what about callbacks? Callbacks are a Dash mechanism that allows a web page to be updated in response to a change in input. Well, we can do that using HTML and Flask, too. But not here. I will follow this article up with another covering this, if there is enough interest. If you want to be informed when this and other articles are published please consider subscribing to my free, occasional, newsletter, here.

Update: the followup article is here: An Interactive Web Dashboard with Plotly and Flask

Code

If you copy the code from the Gist above, don’t forget that the HTML templates need to go in a folder, templates, Alternatively, you can find all of the source code in my Github repository — see the Github page here.

So, Dash or Flask?

I’m sure there may be very good reasons for using Dash for web visualizations and I’m not entirely against it. My aim here has been to show that there is an alternative that, to my mind, is at least as good as Dash, at least for simple apps. I hope it has been useful — thanks for reading.