Skip to content

macro to plot in Pluto #409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ authors = ["Douglas Bates <[email protected]>", "Randy Lai <[email protected]
version = "0.14.2"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597"
Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Expand Down
3 changes: 2 additions & 1 deletion src/RCall.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export RObject,
globalEnv,
isnull, isna, anyna,
robject, rcopy, rparse, rprint, reval, rcall, rlang,
rimport, @rimport, @rlibrary, @rput, @rget, @var_str, @R_str
rimport, @rimport, @rlibrary, @rput, @rget, @var_str, @R_str, @html_plot

# These two preference get marked as compile-time preferences by being accessed
# here
Expand Down Expand Up @@ -80,6 +80,7 @@ include("macros.jl")
include("operators.jl")
include("RPrompt.jl")
include("ijulia.jl")
include("html_plot.jl")
include("setup.jl")
include("deprecated.jl")

Expand Down
84 changes: 84 additions & 0 deletions src/html_plot.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Base64

_open_device(format::Symbol, plot_file; kargs...) = rcall(format, plot_file; kargs...)

_close_device() = rcall(Symbol("dev.off"))

_DEFAULT_FORMAT = :png

function _open_temp_plot(format)
temp_plot_file = tempname()
if format == :svg
_open_device(format, temp_plot_file)
elseif format == :png
_open_device(format, temp_plot_file, width=672, height=672, units="px", res=100)
else
throw(ErrorException(
"`$format` is not supported, try with `png` or `svg`"
))
end
temp_plot_file
end

_open_temp_plot() = _open_temp_plot(_DEFAULT_FORMAT)

function _close_and_show_temp_plot(temp_plot_file, format)
_close_device()
if isfile(temp_plot_file)
if format == :png
plot_base64 = Base64.base64encode(read(temp_plot_file))
HTML("<img src='data:image/png;base64, $plot_base64'/>")
elseif format == :svg
svg_str = read(temp_plot_file, String)
HTML(_fix_svg_ids(svg_str))
end
end
end

function _close_and_show_temp_plot(temp_plot_file)
_close_and_show_temp_plot(temp_plot_file, _DEFAULT_FORMAT)
end


"""
It executes the R code and returns an `HTML` object containing the plot.
This macro is handy to inline R plots inside Pluto notebooks.

`@html_plot` can take two arguments; the first is the code block to evaluate
to produce the R plot. The second argument is the plot format (optional);
it could be `png` (the default) or `svg`. For example:

```julia
@html_plot R"plot(c(1,2,5,3,4), type='o', col='blue')"
```

To use the `svg` format:

```julia
@html_plot R"plot(c(1,2,5,3,4), type='o', col='blue')" svg
```

**NOTE:** To see a *ggplot2* plot, it is necessary to `print` it explicitly:

```julia
@html_plot R\"""
library(ggplot2)

plt <- ggplot(data = diamonds) +
geom_bar(
mapping = aes(x = cut, fill = clarity),
position = "fill"
)

print(plt)
\"""
```

"""
macro html_plot(r_code, format...)
quote
temp_plot_file = _open_temp_plot($format...)
$r_code
_close_and_show_temp_plot(temp_plot_file, $format...)
end
end
16 changes: 10 additions & 6 deletions src/ijulia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,20 @@
display(m,d)
end
end
function ijulia_displayfile(m::MIME"image/svg+xml", f)

function _fix_svg_ids(svg_str::String)
# R svg images use named defs, which cause problem when used inline, see
# https://github.com/jupyter/notebook/issues/333
# we get around this by renaming the elements.
rand_id = randstring()
svg_str = replace(svg_str, "id=\"glyph" => "id=\"glyph"*rand_id)
replace(svg_str, "href=\"#glyph" => "href=\"#glyph"*rand_id)
end

function ijulia_displayfile(m::MIME"image/svg+xml", f)

Check warning on line 47 in src/ijulia.jl

View check run for this annotation

Codecov / codecov/patch

src/ijulia.jl#L47

Added line #L47 was not covered by tests
open(f) do f
r = randstring()
d = read(f, String)
d = replace(d, "id=\"glyph" => "id=\"glyph"*r)
d = replace(d, "href=\"#glyph" => "href=\"#glyph"*r)
display(m,d)
svg_str = read(f, String)
display(m, _fix_svg_ids(svg_str))
end
end

Expand Down
21 changes: 21 additions & 0 deletions test/html_plot.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@test RCall._fix_svg_ids("id=\"glyph") != "id=\"glyph"
@test RCall._fix_svg_ids("href=\"#glyph") != "href=\"#glyph"

@test RCall._DEFAULT_FORMAT == :png

@test_throws ErrorException @html_plot R"plot(1, 2)" :png # : is not needed as the macro is already taking a Symbol
@test_throws ErrorException @html_plot R"plot(1, 2)" pdf # only svg and png are supported

@test @html_plot(R"plot(1, 2)") == @html_plot(R"plot(1, 2)", png) # png is the default format

let png_plot = @html_plot R"plot(1, 2)" png
@test isa(png_plot, HTML)
@test startswith(png_plot.content, "<img src='data:image/png;base64,")
@test endswith(png_plot.content, "/>")
end

let svg_plot = @html_plot R"plot(1, 2)" svg
@test isa(svg_plot, HTML)
@test occursin("<svg ", svg_plot.content)
@test occursin("</svg>", svg_plot.content)
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ println(R"l10n_info()")
"macros",
"namespaces",
"repl",
"html_plot",
]

for t in tests
Expand Down
Loading