How to embed HTML into IPython output?
Asked Answered
V

6

253

Is it possible to embed rendered HTML output into IPython output?

One way is to use

from IPython.core.display import HTML
HTML('<a href="http://example.com">link</a>')

or (IPython multiline cell alias)

%%html
<a href="http://example.com">link</a>

Which return a formatted link, but

  1. This link doesn't open a browser with the webpage itself from the console. IPython notebooks support honest rendering, though.
  2. I'm unaware of how to render HTML() object within, say, a list or pandas printed table. You can do df.to_html(), but without making links inside cells.
  3. This output isn't interactive in the PyCharm Python console (because it's not QT).

How can I overcome these shortcomings and make IPython output a bit more interactive?

Venule answered 6/9, 2014 at 8:36 Comment(5)
Is this what you want to do? ipython.org/ipython-doc/dev/config/integrating.htmlStrict
@Strict It formats html output just like HTML() does, but I still couldn't solve items 1 and 2.Venule
I'm not an expert, so this could be wrong, but I feel that injecting arbitrary html code into the representation of other objects won't work. This would couple logic and representation of an object and is probably not desirable. But you sure could write wrapper objects, that contain the original object and use the repr_html method to provide a custom html representation.Strict
Actually, I just ran your code and it worked as soon as a moved on to a different cell...Decollate
Adding JavaScript: #16853385Venule
B
372

This seems to work for me:

from IPython.core.display import display, HTML
display(HTML('<h1>Hello, world!</h1>'))

The trick is to wrap it in display as well.

Source: http://python.6.x6.nabble.com/Printing-HTML-within-IPython-Notebook-IPython-specific-prettyprint-tp5016624p5016631.html

Edit:

from IPython.display import display, HTML

In order to avoid:

DeprecationWarning: Importing display from IPython.core.display is 
deprecated since IPython 7.14, please import from IPython display
Breakage answered 3/3, 2016 at 0:31 Comment(9)
Can this version exeucte javascirpt?Derisive
Here is a link to an example notebook showing the display possibilities: Rich OutputAllegiance
The display part allowed me to embed JavaScript in a notebookRevisory
Is this a feasible method for producing a website if I need to make it with Dash and all my python code is in Jupyter .ipynb file?Elfrieda
What I meant is if I need to make a website containing a dashboard made from Dash and Flask and all my code is in jupyter .ipynb files, can I just use a seperate html and css files in Atom to do that part and link it to the code in Jupyter files or does all my code need to be in .Ipynb file. Would appreciate any help on this point as I'm new to this.Elfrieda
Consider adding target="_blank" in links in notebooks (except in Markdown cells to other .ipynb files).Tinnitus
Any ideas for a display alternative that works with Voila?Robet
This "Rich Output" notebook link works: github.com/ipython/ipython/blob/main/examples/IPython%20Kernel/…Orebro
I got a deprecation warning. The new import statement us from IPython.display import display, HTML.Claudieclaudina
C
60

Some time ago Jupyter Notebooks started stripping JavaScript from HTML content [#3118]. Here are two solutions:

Serving Local HTML

If you want to embed an HTML page with JavaScript on your page now, the easiest thing to do is to save your HTML file to the directory with your notebook and then load the HTML as follows:

from IPython.display import IFrame

IFrame(src='./nice.html', width=700, height=600)

Serving Remote HTML

If you prefer a hosted solution, you can upload your HTML page to an Amazon Web Services "bucket" in S3, change the settings on that bucket so as to make the bucket host a static website, then use an Iframe component in your notebook:

from IPython.display import IFrame

IFrame(src='https://s3.amazonaws.com/duhaime/blog/visualizations/isolation-forests.html', width=700, height=600)

This will render your HTML content and JavaScript in an iframe, just like you can on any other web page:

<iframe src='https://s3.amazonaws.com/duhaime/blog/visualizations/isolation-forests.html', width=700, height=600></iframe>
Cathodoluminescence answered 14/9, 2018 at 19:28 Comment(7)
Thanks a lot. That's what I was looking for. I use this to render plotly charts interactively in my static blog sitePriming
Wouldn't a local file be easier than throwing something on AWS?Polypropylene
This is perfect! Exactly what I needed - because I want to host an entire web application on a Jupyter Notebook from Amazon SageMaker. Thanks!Hipolitohipp
For extra marks, run an interactive web server asynchronously from a cell and interact with the pages it creates inside an iFrame in other cells!Pyxie
@Pyxie you just found a secret levelCathodoluminescence
@Pyxie can you give a code example for how to do this? This sounds like a very cool idea.Responsible
Simple proof of concept at gist.github.com/holdenweb/fb8de56e33cdfaef9218673915cc7f1cPyxie
Q
25

Related: While constructing a class, def _repr_html_(self): ... can be used to create a custom HTML representation of its instances:

class Foo:
    def _repr_html_(self):
        return "Hello <b>World</b>!"

o = Foo()
o

will render as:

Hello World!

For more info refer to IPython's docs.

An advanced example:

from html import escape # Python 3 only :-)

class Todo:
    def __init__(self):
        self.items = []

    def add(self, text, completed):
        self.items.append({'text': text, 'completed': completed})

    def _repr_html_(self):
        return "<ol>{}</ol>".format("".join("<li>{} {}</li>".format(
            "☑" if item['completed'] else "☐",
            escape(item['text'])
        ) for item in self.items))

my_todo = Todo()
my_todo.add("Buy milk", False)
my_todo.add("Do homework", False)
my_todo.add("Play video games", True)

my_todo

Will render:

  1. ☐ Buy milk
  2. ☐ Do homework
  3. ☑ Play video games
Quadrennial answered 29/7, 2018 at 18:5 Comment(0)
A
9

Expanding on @Harmon above, looks like you can combine the display and print statements together ... if you need. Or, maybe it's easier to just format your entire HTML as one string and then use display. Either way, nice feature.

display(HTML('<h1>Hello, world!</h1>'))
print("Here's a link:")
display(HTML("<a href='http://www.google.com' target='_blank'>www.google.com</a>"))
print("some more printed text ...")
display(HTML('<p>Paragraph text here ...</p>'))

Outputs something like this:


Hello, world!

Here's a link:

www.google.com

some more printed text ...

Paragraph text here ...


Accentor answered 10/7, 2017 at 18:59 Comment(0)
A
4

First, the code:

from random import choices

def random_name(length=6):
    return "".join(choices("abcdefghijklmnopqrstuvwxyz", k=length))
# ---

from IPython.display import IFrame, display, HTML
import tempfile
from os import unlink

def display_html_to_frame(html, width=600, height=600):
    name = f"temp_{random_name()}.html"
    with open(name, "w") as f:
        print(html, file=f)
    display(IFrame(name, width, height), metadata=dict(isolated=True))
    # unlink(name)
    
def display_html_inline(html):
    display(HTML(html, metadata=dict(isolated=True)))

h="<html><b>Hello</b></html>"    
display_html_to_iframe(h)
display_html_inline(h)

Some quick notes:

  • You can generally just use inline HTML for simple items. If you are rendering a framework, like a large JavaScript visualization framework, you may need to use an IFrame. Its hard enough for Jupyter to run in a browser without random HTML embedded.
  • The strange parameter, metadata=dict(isolated=True) does not isolate the result in an IFrame, as older documentation suggests. It appears to prevent clear-fix from resetting everything. The flag is no longer documented: I just found using it allowed certain display: grid styles to correctly render.
  • This IFrame solution writes to a temporary file. You could use a data uri as described here but it makes debugging your output difficult. The Jupyter IFrame function does not take a data or srcdoc attribute.
  • The tempfile module creations are not sharable to another process, hence the random_name().
  • If you use the HTML class with an IFrame in it, you get a warning. This may be only once per session.
  • You can use HTML('Hello, <b>world</b>') at top level of cell and its return value will render. Within a function, use display(HTML(...)) as is done above. This also allows you to mix display and print calls freely.
  • Oddly, IFrames are indented slightly more than inline HTML.
Apperception answered 21/8, 2020 at 8:55 Comment(0)
I
3

to do this in a loop, you can do:

display(HTML("".join([f"<a href='{url}'>{url}</a></br>" for url in urls])))

This essentially creates the html text in a loop, and then uses the display(HTML()) construct to display the whole string as HTML

Inaccurate answered 27/1, 2021 at 0:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.