I am experimenting with Interact.jl for teaching (interactively exploring implications of a macroeconomic model). I also have no clue about web technologies.
The idea is to have model parameters as sliders, solve and simulate the model (\approx 0.1s), and then make plots, about 6–10 simple ones.
I am wondering what the best backend is for this. I experimented with gr(), but perhaps making SVG would be something that would be easier on the browser?
MWE:
using Interact, Mux, Plots
gr()
xgrid = (1:100)/100
ui = @manipulate for α in range(0, 2; step = 0.1)
plot(xgrid, xgrid.^α)
end
WebIO.webio_serve(page("/", req -> ui), 8001)
Fortunately your rarely have to touch any html or css with Interact.
I use plotly() for its zoom functionality as I often need it. But I find it runs fast enough and outputs pretty well optimised svgs. I normally plot multiple plots into one plot window instead of as separate plots. I’m not actually sure that its faster now that I think about it, but you would think that it is…
If your model takes 0.1s to run you will want to throttle the sliders so it doesn’t get run too often. Its usually something like throttle(0.1, observe(sli)) but I’m not sure of the syntax for @manipulate as I don’t use the macro. At a certain level of complexity its just easier to use the observables directly.
If you have the time, I would greatly appreciate if you could provide an example with observables, two slides a and b, throttled, and two plots. Eg plots
xgrid = (1:100)/100
plot(xgrid, xgrid.^(a + b))
plot(xgrid, a .+ xgrid .* b)
I am very new to this and I have a hard time piecing this together.
I agree that while @manipulate is good for simple cases, it could be better to do things by hand in more complex scenario. An in-between things is widget(x::T) that creates the default widget for an element of type T (for ranges it is a slider) and also the macro Widgets.@auto that allows to create the “default widget” for a variable with as label the name of the variable.
For example:
using Plots, Interact, Mux
dt = 0.2
# Create default widgets with default label
Widgets.@auto params1 = 1:100
Widgets.@auto params2 = 1:100
# Throttled widgets
throttled1 = throttle(dt, params1)
throttled2 = throttle(dt, params2)
# use map to have plots that updates as soon as throttled value updates
plot1 = map(throttled1) do val
plot(rand(val), rand(val))
end
plot2 = map(throttled2) do val
plot(rand(val), rand(val))
end
# create layout
ui = vbox(params1, params2, hbox(plot1, plot2))
# serve webapp
WebIO.webio_serve(page("/", req -> ui), 8000)
EDIT: If you want to serve this from a server from multiple users @Raf approach of putting the app in a function is better as otherwise different users from different computers would get the same synced sliders, but if it’s to serve the app locally I think it doesn’t matter
Thanks. If I just want to stack (and not necessarily align) many plots vertically, ie just have one plot below another in the order they come in, should I just use vbox?
There is also Widgets.div(a, b, c...) which stacks vertically without aligning. See which works better for your use case (for more sophisticated options I’m afraid one would need to write some CSS)
You might be interested at looking at the examples using the InspectDR.jl backend, that use Interact.jl + Blink.jl (Web GUIs using Chrome engine, if I am not mistaken):
The files under blink/ are mostly just interact/GUI code; the code that generates the plots themselves are placed in a separate file found under ../notebook/ to make things cleaner.
You must explicitly add packages Interact, Blink, NumericIO, Colors (and optionally DSP & FFTW) for the examples to work, as described in README.md.
I am not just using Mux (I use Blink instead), but I am sure the examples can be displayed in Mux directly with little change in code (since Interact is the main component here).
I suggest checking out example 3_pllstab.jl. It is a relatively complex example, and I think it is somewhat inline with what you might want. Here is a snapshot: