Base.show method for showing a widget in Jupyter

Is there a way to have different methods for Base.show, one for the REPL and another one only for showing a Widgets.Widget in Jupyter? For example:

module Foos

using Interact

export Foo, foo

struct Foo end

# This method is only for the REPL, that's good
Base.show(io::IO, ::Foo) = print(io, "This is a Foo")

function foo(::Foo)
    @manipulate for x in 1:10
        sin(x)
    end
end

# How can i define this method in order
# use it only in Jypter notebooks?
function Base.show(io::IO, ???, x::Foo)
    show(io, ???, foo(x))
end

end

For the REPL I can define Base.show(::IO, ::Foo), or also Base.show(::IO, MIME"text/plain", ::Foo) if necessary, but how can I show the foo function, which is a Widgets.Widget, in Jupyter? Is there a particular MIME that I have to use?

1 Like

Bump :slightly_smiling_face: I think I already read something like this some time ago here on discourse, but couldn’t find it.

Hi, I recently also tried to do this but couldn’t find a working solution for jupyter notebooks. So I would like to bump this again.

1 Like

The question is, what is different about the display that you want to do in Jupyter compared to the text/plain output in the REPL? In the case of a Widget, I’m guessing that you want to use its text/html output method, so you would do:

Base.show(io::IO, m::MIME"text/html", x::Foo) = show(io, m, foo(x))

(In Jupyter, if both text/plain and text/html output are available, it shows the “richer” html output.)

2 Likes

This is for an image-like object. In the REPL I don’t have a way to display anything, but in a notebook I can display it and with a Widget I’d like to tweak brightness/contrast. This is for astronomical images which are usually unviewable without manually adjusting brightness/contrast

Yes, text/html did the trick, thanks!

Thanks for your answer. I have a follow-up question on this:

I would like to “overload” the print function for a custom datatype.
There should be different outputs, depending on the available MIME, so plain text for REPL and HTML for jupyter notebook. Using display() I get the desired result. But calling print or show on my datatype, I just get the default output (here: Foo(“ABC”)).
So in a jupyter notebook it would look like this:

struct Foo
   x::String 
end

function Base.show(io::IO, m::MIME"text/plain", f::Foo)
    print(io, "plain:  $(f.x)")
end

function Base.show(io::IO, m::MIME"text/html", f::Foo)
    print(io, "<p><strong>html: $(f.x)</strong></p>")
end
f = Foo("ABC")

html: ABC

print(f)

Foo(“ABC”)

show(f)

Foo(“ABC”)

display(f)

html: ABC

How do I get the formatted output when calling print(f)?

The print(x) function is always plain text. If you want formatted display, you either call display explicitly or you define an object that has a show method for a formatted type like HTML (which will be called when the object is evaluated in the REPL or Jupyter etc.)

For example, if you want the text/html version of f::Foo embedded in some other text/html output, you call show(io, "text/html", f) or repr("text/plain", f) as part of that output.

You can use the built-in HTML type to wrap an arbitrary HTML string in an object that will be displayed as formatted text in the browser (because the HTML object has a text/html method for show):

HTML("""
<h1>A header</h1>
A <code>Foo</code> object: $(repr("text/html", f))
<p>Some <b>bold</b> text.</p>
""")

or

HTML() do io
    println(io, "<h1>A header</h1>\nA <code>Foo</code> object:")
    show(io, "text/html", f)
    println(io, "<p>Some <b>bold</b> text.</p>")
end

You can also call display explicitly on an HTML string:

display("text/html", """
<h1>A header</h1>
A <code>Foo</code> object: $(repr("text/html", f))
<p>Some <b>bold</b> text.</p>
""")
1 Like

Thank you for your answer! But I’m afraid it did not yet solve my problem completely.

Below I have a MWE of what I’m trying to do:

struct MyType1
   value::String
end

function Base.show(io::IO, m::MIME"text/html", f::MyType1)
    print(io, """This is <strong>MyType1</strong> with value: <strong> $(f.value) </strong>""")
end


struct MyType2
    value::MyType1
end

function Base.show(io::IO, m::MIME"text/html", f::MyType2)
    print(io, """This is <strong>MyType2</strong> with value: """)
    print(io, f.value)
end


m1 = MyType1("A")
m2 = MyType2(m1)


display(m1)
display(m2)

This results in:

This is MyType1 with value: A
This is MyType2 with value: MyType1(“A”)

But the result I would like to have is:

This is MyType1 with value: A
This is MyType2 with value: This is MyType1 with value: A


If I remove m::MIME"text/html" in Base.show of MyType1 :

function Base.show(io::IO, f::MyType1)
    print(io, """This is MyType1 with value: <strong> $(f.value) </strong>""")
end

then I get the desired output. But then I couldn’t have a html and also a plain text version of show for MyType1. It seems I somehow need to to pass the MIME-type?

How do I get the desired results?

print always uses a text/plain representation. Instead, call show(io, m, f.value) at the point where you want to use the m::MIME representation f.value:

print(io, "This is <strong>MyType1</strong> with value: <strong> ")
show(io, m, f.value)
print(io, " </strong>")
1 Like

Ah, thanks a lot!
The trick is to split and use both print and show.
Should have already seen this from your last post. :see_no_evil: