GLMakie beginners help: Multiple sliders and an arrow

Hi,

I am learning sliders from this tutorial line 18 to 87 [tutorials/Tutorial02x10.jl at master · julia4ta/tutorials · GitHub] and trying to edit such that it includes multiple sliders and an arrow from a reference point pointing towards the resultant point on the grid of 2D coordinate plane.

lsgrid = labelslidergrid!(fig,
    ["scale", "x-reference", "y-reference"], #edited from original
    Ref(LinRange(-10:0.01:10));
    formats = [x -> "$(round(x, digits = 2))"],
    labelkw = Dict([(:fontsize, 30)]),
    sliderkw = Dict([(:linewidth, 24)]),
    valuekw = Dict([(:fontsize, 30)])
)

Three sliders are:

# create listener
scale = lsgrid.sliders[1].value #edited from original

x-reference = lsgrid.sliders[2].value #edited from original

y-reference  = lsgrid.sliders[3].value #added 

Evaluating (x-result, y-result) as:

x = -10:0.01:10

m = @lift($scale .* x.^2) #quadratic function #edited from original
line1 = lines!(ax1, x, m, color = :blue, linewidth = 5) #edited from original

#new multi-variable scalar-valued functions
p(x,y,scale) = (x + scale * y-1)^2/(scale^2) #added 
z(x,y,scale) = cbrt(-p(x,y,scale)/2) #added 

#(x-result,y-result) = (x/1+(2*scale)*z ,y+z) #the x and y on the right hand side are (x-reference,y-reference)

How to make sliders for the input (x-reference,y-reference) and plot an arrow of scaling from this to (x-result,y-result)?

Any reference/help is appreciated. Thank you!

That tutorial you are referencing is quite old now. For example, labelslidergrid! will be deprecated soon and is replaced with SliderGrid. Have you tried the examples from the Makie website?

https://docs.makie.org/stable/examples/blocks/

I think what you’ll need to do is use connect! to connect an observable to a slider. For example:

x = Observable(1.0)

sg = SliderGrid(fig[1, 2],
            label = "slider1", range = -10:0.1:10, startvalue = 1)

connect!(x, sg[1])

A general problem I see in your code is the dash - in x-reference and y-reference. Julia will not see this as a variable. You should instead use something like x_ref or xref.

Also, I’ve been making a small collection of GLMakie interactive examples on my GitHub page, in case any of these are useful:

2 Likes

I wasn’t 100% sure what you asked for, but I crafted something anyways (based on the tutorial link you gave above):

using GLMakie
GLMakie.activate!()

################################################################################
# Sliders
################################################################################

# initialize plot

fig = Figure(resolution = (3840, 2160))

# add axis

ax1 = fig[1, 1] = Axis(fig,
    # borders
    aspect = 1,
    # title
    title = "Sliders Tutorial",
    titlegap = 48, titlesize = 60,
    # x-axis
    xautolimitmargin = (0, 0), xgridwidth = 2, xticklabelsize = 36,
    xticks = LinearTicks(20), xticksize = 18,
    # y-axis
    yautolimitmargin = (0, 0), ygridwidth = 2, yticklabelpad = 14,
    yticklabelsize = 36, yticks = LinearTicks(20), yticksize = 18
)

# darken axes

vlines!(ax1, [0], linewidth = 2)
hlines!(ax1, [0], linewidth = 2)

# create sliders

lsgrid = labelslidergrid!(fig,
    ["scale", "x-reference", "y-reference"], #edited from original
    Ref(LinRange(-10:0.01:10));
    formats = [x -> "$(round(x, digits = 2))"],
    labelkw = Dict([(:textsize, 30)]),
    sliderkw = Dict([(:linewidth, 24)]),
    valuekw = Dict([(:textsize, 30)])
)

# set starting position for slope

set_close_to!(lsgrid.sliders[1], 1.0)

# layout sliders

sl_sublayout = GridLayout(height = 150)
fig[2, 1] = sl_sublayout
fig[2, 1] = lsgrid.layout

# draw a function

x = -10:0.01:10
m = @lift($scale .* x.^2) #quadratic function #edited from original
line1 = lines!(ax1, x, m, color = :blue, linewidth = 5) #edited from original

# create listeners

scale = lsgrid.sliders[1].value #edited from original
xreference = lsgrid.sliders[2].value #edited from original
yreference  = lsgrid.sliders[3].value #added 

# xreference, yreference are Float32s
# but for arrows! below we need vectors of Float32s, so we promote them here

# arrow base points
xbase = @lift([$xreference])
ybase = @lift([$yreference])

#new multi-variable scalar-valued functions
p(x,y,scale) = (x + scale * y-1)^2/(scale^2) #added
z(x,y,scale) = cbrt(-p(x,y,scale)/2) #added

# arrow head points
# note: here we also return vectors
xhead = lift(xreference, yreference, scale) do x, y, s
    return [ x/1 + 2*s * z(x,y,s) ]
end
yhead = lift(xreference, yreference, scale) do x, y, s
    return [ y + z(x,y,s) ]
end

arrows!(ax1, xbase, ybase, xhead, yhead)

display(fig)

The above gives you now the arrow you can control with the sliders. Maybe you need to tune the computation of the end points a bit, because right now it does not seem to make any sense to me :laughing:

Modifications I made to your code:

  • You can’t use - in variable names, so I renamed x-reference to xreference, etc.
  • I replaced :fontsize with :textsize, because that was changed recently, but you might be running an older version of Makie.
  • Arrows can be drawn with arrows, cf. arrows - Beautiful Makie. For this to work, one has to pass Vector{Float32} (or Observables thereof) to arrows!. Hence, I add an extra lift for that to promote the xreference, yreference. The reason it wants a Vector instead of a single number for each component is that arrows is optimized to draw vector fields, see the link above.

Last remark: Next time please provide a minimal working example (MWE) of the code that is already working and others can then use to build on top off.

2 Likes

Hi Florian and Garrek,

Thanks for your replies and references! I will try to use above hints.

It’s fontsize everywhere now, not textsize :slight_smile:

2 Likes