# Exporting figures to static HTML

**URL:** <https://discourse.julialang.org/t/exporting-figures-to-static-html/125896>\
**Category:** Visualization\
**Tags:** makie, wglmakie\
**Created:** [February 14, 2025, 9:10am UTC](https://discourse.julialang.org/t/exporting-figures-to-static-html/125896 "2025-02-14T09:10:59Z")\
**Posts on this page:** 1\
**Showing post:** 16

<div class="post-metadata">

**Author:** ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)\
**Post date:** [February 15, 2025, 12:57pm UTC](https://discourse.julialang.org/t/exporting-figures-to-static-html/125896/16 "2025-02-15T12:57:30Z")

</div>

There are some good ideas here in the thread, but I think the best way of doing this goes like this:

```julia
using WGLMakie, Bonito
# Maybe should be in bonito?
function as_html(io, session, app)
    dom = Bonito.session_dom(session, app)
    show(io, MIME"text/html"(), Bonito.Pretty(dom))
end

# For a single plot, we can just do this:
open("test.html", "w") do io
    # Do you own header etc
    println(io, "<!doctype html>")
    app = App(contour(rand(10, 10, 10))) 
    # Page(exportable=true, offline=true) creates pretty much just the below Session 
    session = Session(NoConnection(); asset_server=NoServer())
    # This should only create a `div` with all imports and the plot:
    as_html(io, session, app)
end

```

For multiple plots, we need to use a Subsession, which skips uploading similar assets/data and setup.  
This is pretty much what `Page` does, but for direct export, Page is a bit cumbersome to work with, so I recommend just creating the subsession manually:

```julia
open("test.html", "w") do io
    println(io, "<!doctype html>")
    app = App(contour(rand(10, 10, 10)))
    # Page(exportable=true, offline=true) creates pretty much just the below Session 
    session = Session(NoConnection(); asset_server=NoServer())
    println(io, "<h2>First plot</h2>")
    as_html(io, session, app)
    app2 = App(volume(rand(10, 10, 10)))
    # Create a new session with the same connection, but skip uploading assets/data
    println(io, "<h2>Second plot</h2>")
    sub = Session(session)
    as_html(io, sub, app2)
end

```

If you use a static site, which supports serving files (like [github.io](http://github.io)), you can also use `Bonito.AssetFolder`, instead of `NoServer()`.  
NoServer uses Base64 encoded urls for all assets, which is slower and leads to worse stack traces, while AssetFolder writes out all dependencies and uses relative urls to include them:

```julia

root = "root-of-server"
mkdir(root)
# First argument is the root of the server
# Second argument is the location of the current html file that gets exported
# Which is required for generating urls for assets correctly 
# e.g. you could want to generate `/root/plots/plot.html`, then the second argument would need to be 
# "root-of-server/plots"
asset_server = Bonito.AssetFolder(root, root)
open(joinpath(root, "index.html"), "w") do io
    println(io, "<!doctype html>")
    app = App(contour(rand(10, 10, 10)))
    # Page(exportable=true, offline=true) creates pretty much just the below Session 
    session = Session(NoConnection(); asset_server=asset_server)
    println(io, "<h2>First plot</h2>")
    as_html(io, session, app)
    app2 = App(volume(rand(10, 10, 10)))
    # Create a new session with the same connection, but skip uploading assets/data
    println(io, "<h2>Second plot</h2>")
    sub = Session(session)
    as_html(io, sub, app2)
end

```

You will see that a few files and folders are created in the root folder, which contain the assets used by `index.html`. The `index.html` then uses something like `./bonito/someasset.js` to include those.

You will need e.g. `LiveServer`, to look at `index.html` now, since it needs a full file server to display things:

```julia
using LiveServer
LiveServer.serve(dir=root)

```

This is actually how [makie.org](https://www.makie.org) is created - if you don’t already use e.g. Jekyll, Bonito has some tools to create the whole site, avoiding the whole manual export above:

> **[GitHub - MakieOrg/Website: Makie Org Website](https://github.com/MakieOrg/Website)**
>
> Makie Org Website

And the [make.jl](https://github.com/MakieOrg/Website/blob/main/docs/make.jl).

Would be nice to update the Bonito docs with all of this.

Btw, `record_states` is not completely deprecated, but it’s quite buggy, and I’m not sure if I’d recommend it anymore.  
Maybe for very simple stuff, but the size also balloons pretty quickly, and the last refactor of it, made it even worse sadly (I tried to improve correctness, but mainly just increased size) ☹  
But I guess if it works for you and doesn’t become too big, there’s no reason against using it. Not sure, if it’s worth putting more time into it, but maybe I’ll find some low hanging fruits to decrease size and make it work better.

Currently, I’m thinking it’s better to just improve the javascript interface, making it easier to update plots via sliders in javascript, and then maybe make it easier to hook those up with precalculated data from Julia.

---

_[View the full topic](https://discourse.julialang.org/t/exporting-figures-to-static-html/125896)._
