Hi. I am trying to create an interactive boxplot where the use selects the variable and the boxplot is updated accordingly. The code is like below:
xs = @lift($dfbox[: , 1])
ys = @lift($dfbox[:, 2])
ax = Axis(fig[1,1])
boxplot!(ax, xs, ys)
Here, dfbox
is an observable dataframe which is created as:
dfbox = @lift(data |>
df -> select(df, :country, $xvar) |>
dropmissing |>
df -> transform(df, :country => labelencode => :cntlabel))
When I change the variable, I get errors due to shape mismatch. I have checked the title “Problems With Synchronous Updates” in the Makie documentation but still I couldn’t solve the problem. Any idea about how can I workaround this?
A good Minimal Working Example would help a lot here (maybe some code generating mock data and the plot that we can copy and paste!).
using DataFrames, GLMakie
df = DataFrame(:a => rand(50), :b => rand(50))
l = Observable(10)
xs = Observable(df[1:10,1])
ys = Observable(df[1:10,2])
fig = Figure()
ax = Axis(fig[1,1])
bp = boxplot!(ax, xs,ys)
on(l) do val
xs.val = df[1:val,1]
ys.val = df[1:val,2]
notify(xs)
notify(ys)
end
l[] = 20
I think this should work, but it does not. It seems like one value inside the boxplot is not being updated (maybe it is not observable when it should be?). I think this is worth opening an issue at Makie’s repo
Edit: I opened the issue here
airpmb
April 18, 2023, 7:16pm
4
I actually get an error:
ulia> l[] = 20
ERROR: BoundsError: attempt to access 10-element Vector{Float64} at index [[13]]
Stacktrace:
[1] throw_boundserror(A::Vector{Float64}, I::Tuple{Vector{Int64}})
@ Base ./abstractarray.jl:744
[2] checkbounds
@ ./abstractarray.jl:709 [inlined]
[3] view
@ ./subarray.jl:177 [inlined]
[4] (::Makie.var"#883#897")(x::Vector{Float64}, y::Vector{Float64}, color::ColorTypes.RGBA{Float32}, weights::MakieCore.Automatic, width::MakieCore.Automatic, range::Float64, show_outliers::Bool, whiskerwidth::Float64, show_notch::Bool, orientation::Symbol, gap::Float64, dodge::MakieCore.Automatic, n_dodge::MakieCore.Automatic, dodge_gap::Float64)
@ Makie ~/.julia/packages/Makie/Iqcri/src/stats/boxplot.jl:108
[5] invokelatest(::Any, ::Any, ::Vararg{Any}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ Base ./essentials.jl:816
[6] invokelatest(::Any, ::Any, ::Vararg{Any})
@ Base ./essentials.jl:813
[7] (::Observables.MapCallback)(value::Any)
@ Observables ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:431
[8] #invokelatest#2
@ ./essentials.jl:816 [inlined]
[9] invokelatest
@ ./essentials.jl:813 [inlined]
[10] notify
@ ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:169 [inlined]
[11] setindex!(observable::Observable, val::Any)
@ Observables ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:86
[12] (::Observables.MapCallback)(value::Any)
@ Observables ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:431
[13] #invokelatest#2
@ ./essentials.jl:816 [inlined]
[14] invokelatest
@ ./essentials.jl:813 [inlined]
[15] notify
@ ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:169 [inlined]
[16] setindex!(observable::Observable, val::Any)
@ Observables ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:86
[17] (::Makie.var"#171#173"{Attributes, Observable{Tuple{Vector{Float64}, Vector{Float64}}}, DataType})(::Tuple{}, ::Vector{Float64}, ::Vararg{Vector{Float64}})
@ Makie ~/.julia/packages/Makie/Iqcri/src/interfaces.jl:342
[18] invokelatest(::Any, ::Any, ::Vararg{Any}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ Base ./essentials.jl:816
[19] invokelatest(::Any, ::Any, ::Vararg{Any})
@ Base ./essentials.jl:813
[20] (::Observables.OnAny)(value::Any)
@ Observables ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:415
[21] #invokelatest#2
@ ./essentials.jl:816 [inlined]
[22] invokelatest
@ ./essentials.jl:813 [inlined]
[23] notify(observable::Observables.AbstractObservable)
@ Observables ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:169
[24] (::var"#8#9")(val::Int64)
@ Main ./REPL[9]:4
[25] #invokelatest#2
@ ./essentials.jl:816 [inlined]
[26] invokelatest
@ ./essentials.jl:813 [inlined]
[27] notify
@ ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:169 [inlined]
[28] setindex!(observable::Observable, val::Any)
@ Observables ~/.julia/packages/Observables/PHGQ8/src/Observables.jl:86
[29] top-level scope
@ REPL[10]:1
julia> versioninfo()
Julia Version 1.9.0-rc2
Commit 72aec423c2a (2023-04-01 10:41 UTC)
Platform Info:
OS: macOS (arm64-apple-darwin21.3.0)
CPU: 12 × Apple M2 Max
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-14.0.6 (ORCJIT, apple-m1)
Threads: 8 on 8 virtual cores
Environment:
JULIA_EDITOR = code
Yes, that is why I suggested opening an issue :). So this error does not suggest a mismatch between x and y lengths but between another vector of length 10 and the new boxes. This makes me suspect it is a bug instead of an error on the code.
I wrote a minimal example. The following is my version which doesn’t work.
using DataFrames, GLMakie
data = DataFrame(
country = [fill(1, 20); fill(2, 20); fill(3, 20)],
population = [(rand() > 0.2) ? rand() : missing for i in 1:60],
pop_growth = [(rand() > 0.2) ? rand() : missing for i in 1:60],
gdp = [(rand() > 0.2) ? rand() : missing for i in 1:60],
gdp_growth = [(rand() > 0.2) ? rand() : missing for i in 1:60]
)
macrovars = ["population", "pop_growth", "gdp", "gdp_growth"]
var = Observable("population")
df = @lift(data[:, Cols(:country, $var)] |> dropmissing)
xs = @lift($df[:, 1])
ys = @lift($df[:, 2])
fig = Figure();
ax = Axis(fig[1,1])
menu = Menu(fig, options=macrovars, default="gdp_growth");
fig[1:end, 0] = vgrid!(
Label(fig, "Variable:", width=200, font=:bold),
menuxvar;
tellheight=false, width=200)
boxplot!(ax, xs, ys)
on(menu.selection) do v
var[] = v
autolimits!(ax)
end
notify(menu. Selection)
fig
airpmb
April 18, 2023, 7:49pm
7
Right, just adding the traceback. And I think you’re right, it’s a bug, and maybe in boxplot
(which I think is what you mean @aramirezreyes ) , because the equivalent with scatter!
works:
using DataFrames, GLMakie
df = DataFrame(:a => rand(50), :b => rand(50))
l = Observable(10)
xs = Observable(df[1:10,1])
ys = Observable(df[1:10,2])
fig = Figure()
ax = Axis(fig[1,1])
# bp = boxplot!(ax, xs,ys)
scatter!(ax, xs, ys)
on(l) do val
xs.val = df[1:val,1]
ys.val = df[1:val,2]
notify(xs)
notify(ys)
end
l[] = 20