Friday, January 1, 2016

Serving a matplotlib plot that follows good design practices using Flask

It can be useful at times to serve images that are generated using matplotlib within a Flask application context. This enables some lightweight, non-dynamic visualization generation.

Unfortunately, the defaults for matplotlib are terrible. Ugh!


Enter prettyplotlib -- this library applies some of the work of several key influencers in the visual design space (Tufte, Brewer) to matplotlib. We eliminate chartjunk, add some better fonts, remove some redundant axes, add some better colours, and get the following:



Much better! Now how do we go about serving this type of a plot via Flask? We will have to have two views, one that creates the image, and another one that serves the template that will contain the image. Our template, contained at templates/image.html should be as follows:


<html>
  <head>
    <title>{{ title }} - image</title>
  </head>
  <body>
    <img src="/fig/" alt="Image Placeholder">
  </body>
</html>

and our main application file, titled run.py, should contain the following:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from io import BytesIO
from flask import Flask, render_template, send_file, make_response
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
import numpy as np
import prettyplotlib as ppl
import matplotlib.pyplot as plt


app = Flask(__name__)

@app.route('/fig/')
def fig():
    fig, ax = plt.subplots(1)
    ppl.bar(ax, np.arange(10), np.abs(np.random.randn(10)))
    canvas = FigureCanvas(fig)
    img = BytesIO()
    fig.savefig(img)
    img.seek(0)
    return send_file(img, mimetype='image/png')


@app.route('/image/')
def images():
    return render_template("image.html")


if __name__ == '__main__':
    app.run(debug=True)

The key is line 14 -- rather than calling matplotlib's plt.bar, we call prettyplotlib's plt.bar . Just like that, our output is much more visually appealing and easier to read!

For further reading, check out the following Stack Overflow thread about serving matplotlib files via Flask, this Gist about plotting a PNG using matplotlib (uses Python 2 -- you'll have to adapt it to use the io library if you'd like to try something similar in Python 3) and the official prettyplotlib documentation.

3 comments:

  1. Unfortunately, prettyplotlib is dead at this point. The author recommends using seaborn instead. Simply importing seaborn `import seaborn as sns` will automatically change the styling.

    Alternatively, the newer matplotlib provides styling with `matplotlib.style.use`. There is not currently an exact duplicate of prettyplotlib's style that I can see, but some are similar. You could also create your own style, post it in a gist and use the URL.

    ReplyDelete
  2. The article presents a practical use case for serving Matplotlib-generated images through a Flask application when lightweight, non-dynamic visualization generation is sufficient. The discussion also highlights an important design consideration: simply generating a chart is not enough when the default visualization contains unnecessary elements that reduce clarity.

    The introduction of prettyplotlib is interesting because the article connects visualization design principles with the technical process of generating charts in Python. Applying ideas such as reducing chartjunk, improving typography, simplifying redundant axes, and refining colors provides useful context for learners exploring a Matplotlib Course.

    ReplyDelete
  3. The combination of Flask for serving generated images and Matplotlib for visualization also demonstrates how visualization can be integrated into a Python web application. This makes the example relevant to a Flask Course only if a Flask-specific course URL is available; otherwise, the supplied Flask tag should not be substituted with an unrelated framework URL.

    ReplyDelete

Sign up to receive data viz talk tips and updates via email. We're low traffic and take privacy very seriously.