RCall.jl icon indicating copy to clipboard operation
RCall.jl copied to clipboard

Showing R plots in Juno plot pane

Open greimel opened this issue 6 years ago • 7 comments

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.

greimel avatar Aug 24 '19 16:08 greimel

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.

pfitzseb avatar Aug 24 '19 17:08 pfitzseb

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 avatar Aug 24 '19 17:08 greimel

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

  • 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?
  • Do you think the tmp-file is a good solution?
  • 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?

greimel avatar Aug 24 '19 18:08 greimel

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.

pfitzseb avatar Aug 24 '19 19:08 pfitzseb

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 avatar Aug 24 '19 19:08 greimel

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)"
  1. Follow the IJulia strategy and implement post-execute hooks

greimel avatar Aug 24 '19 20:08 greimel

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

xgdgsc avatar May 11 '22 08:05 xgdgsc