Base.show method for showing a widget in Jupyter

jupyter
#1

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
#2

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

#3

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
#4

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
#5

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!

#6

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)?

#7

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
#8

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?

#9

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
#10

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: