Fragment – Embedding srcdoc IFrames in Jupyter Notebooks

Whilst trying to create IFrame generating magics to embded content in Jupyter Book output, I noticed that the IPython.display.IFrame element only appears to let you refer to external src linked HTML content and not inline/embedded srcdata content. This has the downside that you need to find a way ofcopying any generated src-linked HTML page into the Jupyter Book / sphinx generated distribution directory (Sphinx/Jupyter Book doesn’t seem to copy linked local pages over (I think bookdown publishing workflow does?).

Noting that folium maps render okay in Jupyter Book without manual copyting of the map containing HTML file, I had a peek at the source code and noticed it was using embedded srcdata content.

Cribbing the mechanics, the following approach can be used to create an object with a __rep_html__ method that returns an IFrame with embedded srcdoc content that will render the content in Jupyter Book output without the need for an externally linked src file. The HTML is generated from a template page (template) populated using named template attributes passed via a Python dict ( data). Once the object is created, when used as the last item in a notebook code cell it will return the inlined-IFrame as the display object.

from html import escape
from IPython.display import IFrame

class myDisplayObject:
    def __init__(self, data, template, width="100%", height=None, ratio=1):
        self.width = width
        self.height = height
        self.ratio = ratio
        self.html = self.js_html(data, template)

    def js_html(self, data, template):
        """Generate the HTML for the js diagram."""
        return template.format(**data)

    # cribbed from branca Py package
    def _repr_html_(self, **kwargs):
        """Displays the Diagram in a Jupyter notebook."""
        html = escape(self.html)
        if self.height is None:
            iframe = (
                '<div style="width:{width};">'
                '<div style="position:relative;width:100%;height:0;padding-bottom:{ratio};">'  # noqa
                '<span style="color:#565656">Make this Notebook Trusted to load map: File -> Trust Notebook</span>'  # noqa
                '<iframe srcdoc="{html}" style="position:absolute;width:100%;height:100%;left:0;top:0;'  # noqa
                'border:none !important;" '
                'allowfullscreen webkitallowfullscreen mozallowfullscreen>'
                '</iframe>'
                '</div></div>'
            ).format(html=html, width=self.width, ratio=self.ratio)
        else:
            iframe = (
                '<iframe srcdoc="{html}" width="{width}" height="{height}"'
                'style="border:none !important;" '
                '"allowfullscreen" "webkitallowfullscreen" "mozallowfullscreen">'
                '</iframe>'
            ).format(html=html, width=self.width, height=self.height)
        return iframe

For an example of how this is used, see innovationOUtside/nb_js_diagrammers (functionality added via this commit).

Author: Tony Hirst

I'm a Senior Lecturer at The Open University, with an interest in #opendata policy and practice, as well as general web tinkering...

%d bloggers like this: