Interact.jl custom layout to @manipulate macro

based on this example from the Interact.jl docs

function mycolorpicker()
    r = slider(0:255, label = "red")
    g = slider(0:255, label = "green")
    b = slider(0:255, label = "blue")
    output = Interact.@map Colors.RGB(&r/255, &g/255, &b/255)
    plt = Interact.@map plot(sin, color = &output)
    wdg = Widget(["r" => r, "g" => g, "b" => b], output = output)
    @layout! wdg hbox(plt, vbox(:r, :g, :b)) ## custom layout: by default things are stacked vertically
end

i wanted to change the layout of my interaction to have sliders in three columns in a hbox. I’m having trouble generating the plot though because I dont understand how the &-updated objects are behaving. to make my plot i need to put the values from the sliders into a dict, then give that dict to a function which evaluates a model, then the output of this is used to make a plot.

here is what works for me:

	p = Param()
	gammas = 1.0:0.1:3.0
	betas  = 0.5:0.05:1.0
	Rs  = 1.0:0.05:1.5
	alphas = [0.0,0.35,0.5]
	sigmas = 0.0:0.05:0.35
	lambdas = 0.0000002:0.05:1
	rhos = 0.1:0.05:1
	deltas = 0.0:0.05:0.5
	pensions = 0.0:0.1:1.0

	mp = @manipulate for dosim = Dict("sim" => true, "sol" => false),
						 id = Dict("id=$id" => id for id in 1:2),
						 nsims = spinbox(label="nsims"; value=p.nsims),
						 # γ in slider(gammas, label = "γ", value =p.gamma ),
						 β in slider(betas, label = "β", value =p.beta) ,
						 R in slider(Rs, label = "R", value =p.R) ,
						 α in slider(alphas, label = "α", value =p.alpha) ,
						 σ in slider(sigmas, label = "σ", value =p.sigma) ,
						 λ in slider(lambdas, label = "λ", value =p.lambda),
						 δ in slider(deltas, label= "δ",value = p.delta),
						 pens in slider(pensions, label= "pension",value = p.pension)
	
		 m,p = runf(par = Dict(:nsims => nsims, :beta => β, :alpha => α, :sigma => σ, :lambda => λ, :R => R, :delta => δ, :pension => pens))
		 if dosim
			 s = sim(m,p)
			 plot_s(s)
		 else
			 plot(m,p,id = id)
		 end
	end

and here is what does not:

	p0 = Interact.@map Dict(:nsims => &nsims, :beta => &β, :alpha => &α, :sigma => &σ, :lambda => &λ, :R => &R, :delta => &δ, :pension => &pens)
	m = Interact.@map runf(par = p0[])  # runf returns a tuple

		s = Interact.@map sim(m[1][1], m[1][2])
		pl = Interact.@map plot_s(s[1])


	# build output
	vbox(
		hbox(dosim, id, nsims),
		hbox(β, R, σ),
		hbox(α, λ, δ, pens),
		# pl[1]
		# Interact.@map plot(10)
		Interact.@map plot_s(s[])

	)

I’m confused by the type of some of those objects Lazy.List. whats the difference of usign & and [] on an object return by the Interact.@map macro? thanks

So, [] means “take current value”, whereas & means “take current value and update on change”.

In practice, I guess just doing a unique @map where all the widgets participate with & should be equivalent to @manipulate.

That being said, @manipulate is also a widget, so you can call the @layout! macro on mp. I confess I don’t remember how exactly things are stored there, but I think each slider should be a child whose key is the symbol corresponding to the variable name.

Great! I was hoping there is a way to do a @layout on a straight manipulate ! Will try!

almost there. but i can’t show the plot.

using Plots

x = y = 0:0.1:30

freqs = OrderedDict(zip(["pi/4", "π/2", "3π/4", "π"], [π/4, π/2, 3π/4, π]))

julia> mp = @manipulate for freq1 in freqs, freq2 in slider(0.01:0.1:4π; label="freq2")
           y = @. sin(freq1*x) * sin(freq2*x)
           plot(x, y)
       end

julia> @layout! mp vbox(hbox(:freq1, :freq2), :output)

shows this

(same result with julia> @layout! mp vbox(hbox(:freq1, :freq2),hbox(:output)))

julia> fieldnames(typeof(mp))
(:components, :output, :scope, :layout)

julia> mp.output
Observable{Any} with 1 listeners. Value:
Plot{Plots.GRBackend() n=1}

how can i refer to the plot such that it reprints it so screen?

I think getproperty is overload to only look in the children list. You can access the output with observe, see the @manipulate docs. So the following should work:

@layout! mp vbox(hbox(:freq1, :freq2), observe(_))
1 Like

oh man, I love it. thanks so much!

1 Like

Assuming that you defined a dictionary containing keys (say, from 1 to 90) and values incorporating plots (p[1], p[2], …, p[90]), you can create a dynamic plot using manipulate macro with the following codes:

using Interact, Plots
t=widget(0:1:90, label=“t”)
ui = @manipulate for t in 1:90
vbox(
hbox(t),
plot(p[t], title = “t=$t”)
)
end
using Blink
w = Window()
body!(w, ui)

2 Likes

very nice, it worked for me.