Automated saving of vector images in a notebook for download¶
Problem description¶
- You are making plots in a jupyter notebook
- You are using some package to automatically generate web-first documentation/reports from notebooks
- People reading the documentation/reports want to download a specific figure in an editable format, so that they can modify colors, etc.
What doesn't work¶
Saving the figure from the artifact built by the notebook¶
This doesn't work because jupyter doesn't save vector images (when using matplotlib). Only rasterized images are saved.
Saving the figure you want, and then...?¶
I'm going to stop you there. Doing this manually is not only a pain, but is also a nightmare. What happens if the plot changes? Will you remember to update the saved figure? How do you guarantee that the plot showed in the notebook/documentation is the same as the plot that is saved in an editable format?
Example¶
%load_ext autoreload
%autoreload 2
import matplotlib.pyplot as plt
import numpy as np
from pycore.jupyter_utils import offer_editable_mpl_figure
First we define a silly plot function that operates on some np.arrays. All we need to do is wrap it in a decorator as such:
@offer_editable_mpl_figure
def plot_something(a: np.array, b: np.array, c: int):
fig, ax = plt.subplots()
plt.plot(a,b)
return fig
a = np.arange(1000)
b = np.sin(a/20)
plot_something(a=a,b=b, c= 1)
We see that in addition to making the plot we wanted, there is now a download link that will allow you to download an editable version of this figure (a PDF). Note also that the link contains a hash. If we use the same plot function with different arguments, we get a differnet hash (and therefore a different file saved and available to download)
a = np.arange(1000)
b = np.sin(a/19)
plot_something(a=a,b=b, c= 1)
Gotchas¶
Because of the way arguments are hashed, you will get different hashes if you switch from calling your function using key-word arguments to positional arguments. However, this doesn't matter too much, as you will still get unique file names. The worst-case scenario is that you may get duplicated files.
a = np.arange(1000)
b = np.sin(a/19)
plot_something(a,b, 1)
A note about keyword arguments
If you have a function that you can call with all positional arguments, and then choose to call it with keyword arguments, the artifact will be saved with a different name. That is because of the way hashing of function arguments is done -- first positional arguments are hashed, then keyword arguments.