Display svg

In a Jupyter notebook I have the following code that worked with Julia 1.0

f = open(“Output.svg”, “r”)
s = read(f,String)
display(“image/svg+xml”,s)

Now in Julia 1.5.3 it did not work anymore. I looked up the documentation but could not find why.

Thanks Tony

Ah neat! I didn’t know you could directly request Julia to draw an image like this! I thought you had to request it to display your object (ex: display(myObject)), and wait for a “display object” on the “display stack” to call the appropriate show() function.

New way to write your code

f = open("images/animage.svg", "r")
s = read(f) #Don't force Julia to read a "String"
close(f) #Don't forget to close your file!
@show typeof(s); flush(stdout) #FYI: So you can understand what type is read back
display(MIME("image/svg+xml"), s)

Explanation

So it appears the main problem is that display() no longer has access to show() functions that accept image data stored in String types.

The good news is that if instead, you call read(f) without specifying a type, Julia returns a Vector{UInt8} - which is probably a more appropriate data structure anyways.

If you now call your display() function with this Vector{UInt8}, everything should work!

Supplemental information

Notice how my version calls display() using MIME("image/svg+xml"). I suggest writing it this way, as it explicitly wraps the MIME information in an appropriate type. As a consequence, there should be less ambiguity with the call to display() (i.e.: Is this String parameter the MIME information, or is it the data I want to display?).

1 Like

Does this still work? I’m getting errors:


julia> display("image/svg+xml",s)
ERROR: MethodError: no method matching show(::Base.TTY, ::MIME{Symbol("image/svg+xml")}, ::Vector{UInt8})
Closest candidates are:
  show(::IO, ::AbstractString, ::Any) at /usr/share/julia/base/multimedia.jl:111
  show(::IO, ::MIME{Symbol("text/tab-separated-values")}, ::Any) at /usr/share/julia/stdlib/v1.7/DelimitedFiles/src/DelimitedFiles.jl:830
  show(::IO, ::MIME{Symbol("text/csv")}, ::Any) at /usr/share/julia/stdlib/v1.7/DelimitedFiles/src/DelimitedFiles.jl:829
  ...
Stacktrace:
 [1] display(d::TextDisplay, M::MIME{Symbol("image/svg+xml")}, x::Any)
   @ Base.Multimedia ./multimedia.jl:249
 [2] display(m::MIME{Symbol("image/svg+xml")}, x::Any)
   @ Base.Multimedia ./multimedia.jl:342
 [3] display(mime::String, x::Any)
   @ Base.Multimedia ./multimedia.jl:217
 [4] top-level scope
   @ REPL[6]:1

@lazycoder:
This will only work if your “display” object supports rendering SVGs.

  • Note how the original question was for displaying within Jupyter Notebooks.
  • It appears from your error messages that you are using the base Julia command line (aka “REPL”).

So it is quite expected that your particular call to display() failed.

Easiest way to “display” SVG with the REPL?

If that’s what you want, I suggest constructing/displaying an external window that can display .svg images (like a GTK window).

Here is a straw man of how you could go about implementing this:

using Gtk #Need gtk loaded

#Viewer object to add to Julia's display stack:
struct GTKImgView <: AbstractDisplay
end

function display(d::GTKImgView, M::MIME{Symbol("image/svg+xml")}, x::Vector{UInt8})
   # Insert code here:
   # Construct a new GTK window
   # Render SVG on window
   # Show GTK window
end

#Create a GTKImgView object & add it to Julia's display stack:
#(It will get "asked" to display first when an SVG image is to be displayed)
pushdisplay(GTKImgView())
2 Likes

FWIW: I came across this issue in trying to plot an SVG in Pluto. There the solution was simply to type HTML(s). I was inspired by using typeof to look at the type of the html_str example of SVG cells in Pluto.