Skip to content
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

How would I capture PlotlyJS.jl figures as HTML? #126

Open
MikaelSlevinsky opened this issue Nov 25, 2020 · 11 comments
Open

How would I capture PlotlyJS.jl figures as HTML? #126

MikaelSlevinsky opened this issue Nov 25, 2020 · 11 comments

Comments

@MikaelSlevinsky
Copy link

I'm currently setup to convert a .jl script to markdown using Literate.markdown for inclusion as generated pages in Documenter. But the captured output gives the figures a random number name and thus Plots.jl defaults to saving the figure as a PNG instead of HTML. Is this avoidable?

My basic script is here https://github.com/JuliaApproximation/FastTransforms.jl/blob/master/examples/disk.jl

The docs build is here https://github.com/JuliaApproximation/FastTransforms.jl/blob/master/docs/make.jl

@fredrikekre
Copy link
Owner

Does Documenter handle this? In that case, perhaps try with execute=false here: https://github.com/JuliaApproximation/FastTransforms.jl/blob/04008f6e863c7879e03b2bf345f0b8ec4023c6c2/docs/make.jl#L20 instead?

Currently, markdown execution only handles image/png and image/jpeg, see

for (mime, ext) in [(MIME("image/png"), ".png"), (MIME("image/jpeg"), ".jpeg")]
.

@MikaelSlevinsky
Copy link
Author

Ok so this is a feature request (for the whole package chain)?

@fredrikekre
Copy link
Owner

Probably, but I thought it worked in Documenter already, but maybe I misremember. I think JuliaDocs/Documenter.jl#1247 is causing some trouble for including the necessary js library.

@MikaelSlevinsky
Copy link
Author

Thanks for the link! I thought PloylyJS's docs used HTML plots a while back, but it appears they're PNG now. Perhaps this is related.

@MikaelSlevinsky
Copy link
Author

Maybe Literate could produce a raw block for documenter?

JuliaDocs/Documenter.jl#1149

@MikaelSlevinsky
Copy link
Author

So my hack is to add commented raw html and use your post processing
JuliaApproximation/FastTransforms.jl@ecc0e59
results in
https://juliaapproximation.github.io/FastTransforms.jl/dev/generated/disk/

@fredrikekre
Copy link
Owner

Okay, using <object> is a nice idea. I developed that idea a bit further, and if you put this in docs/make.jl

import Plots
struct HTMLPlot
    p # :: Plots.Plot
end
const ROOT_DIR = joinpath(@__DIR__, "build")
const PLOT_DIR = joinpath(ROOT_DIR, "plots")
function Base.show(io::IO, ::MIME"text/html", p::HTMLPlot)
    mkpath(PLOT_DIR)
    path = joinpath(PLOT_DIR, string(hash(p) % UInt32, ".html"))
    Plots.savefig(p.p, path)
    print(io, "<object type=\"text/html\" data=\"../$(relpath(path, ROOT_DIR))\" style=\"width:100%;height:600px;\"></object>")
end

you can just return HTMLPlot(p) from your blocks, like this:

```@example test
import Plots, PlotlyJS
Plots.plotlyjs()
x = range(0, 2pi, length=100)
y = sin.(x)
p = Plots.plot(x, y)
Main.HTMLPlot(p)
```

@MikaelSlevinsky
Copy link
Author

I thought the point of using Literate was that the .jl scripts for, e.g. a repository's examples, are still standalone. Wouldn't Main.HTMLPlot(p) throw an error unless one is building the docs (or loaded docs/make.jl)?

Perhaps a more seamless solution would be if Literate.markdown supported another keyword, say plot_extension = :html / :png / :svg / ... and then execute_markdown! would depend more specifically on the extension, with the guts of the show method above for :html.

Also, in the object type, the height seems to make an appreciable difference (I switched back to default size with height 400px for better mobile support), since it's a fixed pixel size. Given a plot p, the object height could be specified by taking the plot's height as size(p.o)[2] or p.attr[:size][2].

@JakobAsslaender
Copy link

Okay, using <object> is a nice idea. I developed that idea a bit further, and if you put this in docs/make.jl

import Plots
struct HTMLPlot
    p # :: Plots.Plot
end
const ROOT_DIR = joinpath(@__DIR__, "build")
const PLOT_DIR = joinpath(ROOT_DIR, "plots")
function Base.show(io::IO, ::MIME"text/html", p::HTMLPlot)
    mkpath(PLOT_DIR)
    path = joinpath(PLOT_DIR, string(hash(p) % UInt32, ".html"))
    Plots.savefig(p.p, path)
    print(io, "<object type=\"text/html\" data=\"../$(relpath(path, ROOT_DIR))\" style=\"width:100%;height:600px;\"></object>")
end

you can just return HTMLPlot(p) from your blocks, like this:

```@example test
import Plots, PlotlyJS
Plots.plotlyjs()
x = range(0, 2pi, length=100)
y = sin.(x)
p = Plots.plot(x, y)
Main.HTMLPlot(p)

Thanks @fredrikekre! Works like a charm! Just FYI, when using prettyurl in the CI framework, I had to make the following modification:

function Base.show(io::IO, ::MIME"text/html", p::HTMLPlot)
    mkpath(PLOT_DIR)
    path = joinpath(PLOT_DIR, string(hash(p) % UInt32, ".html"))
    Plots.savefig(p.p, path)
    if get(ENV, "CI", "false") == "true" # for prettyurl
        print(io, "<object type=\"text/html\" data=\"../../$(relpath(path, ROOT_DIR))\" style=\"width:100%;height:425px;\"></object>")
    else
        print(io, "<object type=\"text/html\" data=\"../$(relpath(path, ROOT_DIR))\" style=\"width:100%;height:425px;\"></object>")
    end
end

@JakobAsslaender
Copy link

I have another question regarding PlotlyJS though. Does anyone have an idea how to get them working in Jupyter notebooks?

On my own computer I got them to work with this extension, i.e. by executing this command

jupyter labextension install jupyterlab-plotly

But I am puzzled how to incorporate that in the make.jl or somewhere so that a) the precomputed notebooks (executed by the GitHub action) display the figures and b) binder knows how to handle these plots. Neither is working right now.

@fredrikekre, do you have yet another trick up your sleeve? Thank a ton for your help in advance!

@fredrikekre
Copy link
Owner

No idea, sorry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants