I have an ipython notebook with an embedded image from my local drive. I was expecting it to be embedded in the JSON along with the output of code cells, but when I distributed the notebook, the image did not appear to users. What is the recommended way (or ways) to embed an image in a Notebook, so that it doesn't disappear if users rerun code cells, clear cell output, etc.?
The notebook system caches images included with ![label](image.png)
, but they last only until the python "kernel" serving the notebook is restarted. If I rename the image file on disk, I can close and reopen the notebook and it still shows the image; but it disappears when I restart the kernel.
Edit: If I generate an image as code cell output and then export the notebook to html, the image is embedded in the html as encoded data. Surely there must be a way to hook into this functionality and load the output into a markdown (or better yet "raw nbconvert") cell?
from IPython.display import Image
Image(filename='imagename.png')
will be exported (with ipython nbconvert
) to html that contains the following:
<div class="output_png output_subarea output_execute_result">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnAAAAFgCAYAAAA...
</div>
However, even when I manually embedded this snippet into a markdown cell, I couldn't get the image to display. What am I doing wrong?
Apparently, the problem has (finally!) been addressed in the newer notebook / Jupyter versions: as of 2018 (thanks for the link @Wayne), the html sanitizer will accept an embedded html image, as in <img src="data:image/png;base64,iV...>
. Markdown image syntax also accepts images as embedded data, so there are two ways to do this. Details in these helpful answers:
Method 1: Direct insertion using the edit menu first, change the type of the cell to -> markdown. Step 2: After that click edit in the jupyter notebook menu. after that click 'insert image'. Edit -> insert image.
IPython/Jupyter now has support for an extension modules that can insert images via copy and paste or drag & drop.
Are you happy to use an extra code cell to display the image? If so, use this:
from IPython.display import Image
Image(filename="example.png")
The output cell will have the raw image data embedded in the .ipynb
file so you can share it and the image will be retained.
Note that the Image
class also has a url
keyword, but this will only link to the image unless you also specify embed=True
(see the documentation for details). So it's safer to use the filename
keyword unless you are referring to an image on a remote server.
I'm not sure if there is an easy solution if you require the image to be included in a Markdown cell, i.e. without a separate code cell to generate the embedded image data. You may be able to use the python markdown extension which allows dynamically displaying the contents of Python variables in markdown cells. However, the extension generates the markdown cells dynamically, so in order to retain the output when sharing the notebook you will need to run ipython nbconvert --to notebook original_notebook.ipynb --output preprocessed_notebook
using the preprocessor pymdpreprocessor.py
as mentioned in the section "Installation". The generated notebook then has the data embedded in the markdown cell as an HTML tag of the form <img src="data:image/png;base64,...">
so you can delete the corresponding code cell from preprocessed_notebook.ipynb
. Unfortunately, when I tried this the contents of the <img>
tag weren't actually displayed in the browser, so not sure if this is a viable solution. :-/
A different option would be to use the Image
class in a code cell to generate the image as above, and then use nbconvert
with a custom template to remove code input cells from the notebook. See this thread for details. However, this will strip all code cells from the converted notebook, so it may not be what you want.
The reason why the
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnAAAAFgCAYAAAA...
tag doesn't do anything when you put it in a markdown cell is because IPython uses an HTML sanitizer (something called Google Caja) that screens out this type of tag (and many others) before it can be rendered.
The HTML sanitizer in IPython can be completely disabled by adding the following line to your custom.js
file (usually located at ~/.ipython/profile_default/static/custom/custom.js
):
iPython.security.sanitize_html = function (html) { return html; };
It's not a great solution though, as it does create a security risk, and it doesn't really help that much with distribution.
Postscript:
The ability to render base64 encoded strings as images != obvious security concern, so there should be a way for the Caja people to eventually allow this sort of thing through (although the related feature request ticket was first opened back in 2012, so don't hold your breath).
I figured out that replacing the image URL in the ![name](image)
with a base64 URL, similar to the ones found above, can embed an image in a markdown container.
Example markdown:
![smile](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAD9JREFUGJW1jzEOADAIAqHx/1+mE4ltNXEpI3eJQknCIGsiHSLJB+aO/06PxOo/x2wBgKR2jCeEy0rOO6MDdzYQJRcVkl1NggAAAABJRU5ErkJggg==)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With