🌻 Plotly.py End of Summer Updates 🌻

Static Image Export and a New Lead Maintainer

plotly.py is a free, open source Python graphing library written and maintained by the company Plotly. Under the hood, it’s an interface to the open source plotly.js JavaScript graphing library. Get started or view the source on GitHub.

Just two months ago we announced plotly.py 3.0.0, our biggest release yet. It included first-class Jupyter widget integration, deep validation and typeahead support, and several performance improvements (read more).

Today we’re excited to announce two new developments in the plotly.py library:
Announcement 1. Jon Mease, the open source contributor behind 3.0.0, is stepping up as the lead maintainer of plotly.py. Jon has been working in technical computing and data science for many years. He started working on plotly.py because he wants it all: a library with high quality SVG graphics, GPU acceleration for large datasets, two-way interactivity in Jupyter, standalone dashboard support, and an extensive range of chart types. With Jon at the helm, plotly.py has never been in a better place. Welcome Jon!

Announcement 2. Programmatic static image export is now widely available in plotly.py 3.2.0. Here “programmatic” means the ability to save figures as images from code, without requiring any manual interaction with a web browser (e.g. no save dialog). This has been the most requested feature by the community and seriously broadens the applicability of the library. Thanks to Jon, our community no longer has to choose between interactive graphing and high quality static image exports; with plotly.py you can have it both ways.

Quickstart

Converting a figure to an image is simple and it’s very similar to matplotlib’s savefig:

plotly.io.write_image(fig, file, format=None,
scale=None, width=None, height=None)
  • fig is a Figure or a compatible dict. This is the central declarative object that describes every aspect of a plotly graph.
  • file may be a string referring to a local filesystem path, or a file-like object to be written to. If file is a string, then the file extension is used to infer the image format if possible.
  • The format may be used to explicitly specify the format, and it is required if file is not a string with a common extension. Supported formats are png, jpeg (jpg extension supported as well), webp, svg, pdf, and eps (with poppler installed).
  • scale, width, and height all work as you would expect.
plotly.io.to_image(fig, format=None,
scale=None, width=None, height=None)

This function may be used to return the binary representation of the image directly (no temp files or messing with io.BytesIO!). This can be used in conjunction with IPython.display.Image to display static images directly in the notebook or QtConsole.

Installation

The main plotly.py library can be installed either through pip or through conda:

  1. $ pip install plotly --upgrade
  2. $ conda install -c plotly plotly

Image export requires two additional dependencies: orca and psutil. psutil may be installed using pip or conda from the standard repositories, and there are three ways to install orca:

  1. $ conda install -c plotly plotly-orca
  2. $ npm install -g electron@1.8.4 orca
  3. Download and install the prebuilt binary

Performance

One of the really exciting aspects of our image export functionality is that generating images is really fast. It takes about 2 seconds for the image generating subprocess to start but once it’s started, generating images can be about as fast as matplotlib and somewhat faster than the selenium-based approach used by other JavaScript visualization libraries like bokeh and altair.

Here are the results of some timing comparisons between plotly.py, matplotlib, bokeh, and altair for saving a 1000 point scatter plot to a PNG and SVG image (get the full notebook here).

Update 09/08/2018: The original version of the chart below showed significantly slower bokeh export times. Thanks to Bryan Van de Ven for pointing out that it is possible to substantially improve the export time by reusing a single selenium webdriver instance across multiple export operations. As far as we know, this approach is not currently available in altair (as of version 2.2.2).

plotly.py image export is fast 🏇
The benchmark image.

Architecture

plotly.py is a graphing library that renders graphs using JavaScript, SVG, and WebGL. It’s a pythonic interface to the plotly.js javascript library.

The fact that plotly graphs are traditionally rendered in a web browser is important: it means that in order to generate static images of plotly graphs, we need an environment that is programatically accessible, cross-platform, and capable of running JavaScript and rendering SVG and WebGL. This environment is Electron.

Electron is a cross-platform desktop application technology that is built on top of Chromium, the core of the Chrome browser. With Electron, we wrote and published orca, a self-contained CLI for rendering static images of plotly graphs. You can either install it with conda or npm, or you can download our prebuilt binaries for Windows, Mac, and Linux. We create these builds using the CI platforms AppVeyor, Travis, and CircleCI.

Since most plotly.js graphs are rendered in SVG, the resulting images will be publication-quality: The fonts and shapes are crisp, and they’ll stay crisp and unpixelated when you enlarge them in your PowerPoint presentation, or when you’re post-processing in Illustrator.

High-quality image export with plotly.py and orca

To create an image, plotly.py will invoke the orca command, running it as a background server. Plotly plots are completely described in declarative JSON, so that data is easily transferred from Python to orca over a local HTTP request, and orca will draw the graph using plotly.js and render the image. orca is run in a subprocess and without a window: it’s completely out of the way. We keep the orca subprocess running until the main Python process exits so that your code can generate multiple images in a row without waiting for orca to start each time (orca takes about 2 seconds to start).

For more on the design, see the original pull request.

More Resources