JuliaInterop / RCall.jl

Call R from Julia
Other
319 stars 59 forks source link

Showing R plots in Juno plot pane #333

Open greimel opened 4 years ago

greimel commented 4 years ago

Is it possible to show ggplot2 plots in the Juno plot pane?

using RCall, DataFrames
@rlibrary ggplot2

df = DataFrame(x=rand(10), y=rand(10))
ggplot(df) + geom_point(aes(x=:x, y=:y))

This plot is shown in a Jupyter notebook, but when run in Juno, it is shown in an R plot window.

Instead of cross-posting in the Juno repo, I am pinging @pfitzseb. If you give me hints where to start this, I would try to tackle this myself.

pfitzseb commented 4 years ago

You need overloads for the correct Base.show method (see here for some docs on that). I didn't see any Base.show overloads in this package, so I have no idea how displaying stuff in Jupyter notebooks works.

greimel commented 4 years ago

thanks for the hint. I'll see how far I get.

As far as Juno is concerned, probably this: https://github.com/JuliaInterop/RCall.jl/blob/master/src/ijulia.jl

greimel commented 4 years ago

I think I got it to work.

using RCall, DataFrames
@rlibrary ggplot2

df_string = DataFrame(x = randn(100), y=randn(100), z1=rand(["a"; "b"], 100), z2=rand(["darkorange"; "lightblue"], 100))

plt = ggplot(df_string) + geom_point(aes(x=:x, y=:y, color=:z2)) # works with standard colors

using ImageShow
using FileIO
rdevicefun(m::MIME"image/png") = @rget png
#rdevicefun(m::MIME"image/svg+xml", f) = R"svg($f)"
ext(::MIME"image/png") = ".png"
#ext(::MIME"image/svg+xml") = ".svg"

function Base.show(io::IO, m::MIME"image/png", plt::RObject)
  f = tempname() * ext(m)
  width, height = get(io, :juno_plotsize, [100, 100])
  R"""
    png($f, width=$width, height=$height, units="px", pointsize=20)
    show($plt) # plot(rnorm(10), rnorm(10))
    dev.off()
   """
   show(io, m, load(f))
end

plt

Before I put this into a PR I need some advice

pfitzseb commented 4 years ago

Is it a good idea to use use width, height = get(io, :juno_plotsize, [100, 100]) because the function might be useful outside Juno. Do you have suggestion for improvement?

Would probably make sense to use the defaults that are already in place instead of [100, 100].

Do you think the tmp-file is a good solution?

Not really, but it might be the easiest solution for now (and is already what is used for IJulia display, so whatever).

Since R plots are pointers, I couldn't figure out which type they actually are. Could someone tell be what I can use instead of ::RObject?

You probably can't do any better, but for correctness you'll need to figure out a runtime check for whether you have a R-plot, and put that into

Base.showable(m::MIME"image/png", plt::RObject) = is_a_plot(plt)

so the display system does the right thing.

greimel commented 4 years ago

Thank you for your help!

Regarding

You probably can't do any better, but for correctness you'll need to figure out a runtime check for whether you have a R-plot, and put that into

Base.showable(m::MIME"image/png", plt::RObject) = is_a_plot(plt)

so the display system does the right thing.

probably some of the RCall contributors can help me out with this?

EDIT:

I found the is.ggplot() function in R. And it seems, that one cannot actually save a base plot and show it again.

So the code above actually doesn't work for base plots.

greimel commented 4 years ago

Now that I understand that R-base plots cannot be captured ex-post, I start to understand what the code in ijulia.jl does.

  1. It resets the default device so that plots are automatically saved to file
  2. At the end of each cell it checks if there is a plot open (post-execute hook)
  3. If there is a plot, show it, close the device and remove the file

Are there such things like post-execute hooks in Juno as well?

The two options I see are

  1. Use the current implementation for ggplot2 only
    Base.showable(m::MIME"image/png", plt::RObject) = R"is.ggplot($plt)"
  2. Follow the IJulia strategy and implement post-execute hooks
xgdgsc commented 2 years ago

What could be done to show rcall plots in julia-vscode?