Slider in scatter plot adds new layers but doesnt delete old ones

I would like to turn information in a dataframe into a scatterplot which I can filter with help of sliders. What I came up with is this:

using Makie, GLMakie

fig = Figure() # initialize canvas

plot = Axis(fig[1, 1]) # initialize plot

sg = SliderGrid( # create slider grid
    fig[2, 1],
    (label = "x-limit", range = 0:0.1:10, format = "{:.1f}", startvalue = 0.5),
    (label = "y-limit", range = 0:0.1:10, format = "{:.1f}", startvalue = 0.5),
    )

xlimy, ylimy = sg.sliders[1].value, sg.sliders[2].value # turn slider values into simple observable variables

df = DataFrame("xcoord" => rand(10)*10, "ycoord" => rand(10)*10) # create random dataframe

onany(xlimy, xlimy) do value_x, value_y # if any of the slider values change run this block of code
    begin
    @isdefined(scattery) && delete!(plot, scattery) # my hope was to check if there already is a scatter plot in my canvas. if so i wanted it to get deleted. this doesn't work
    temp_df = filter(x -> (x.xcoord >= value_x) & (x.ycoord >= value_y), df) # filter df based on slider values
    scattery = scatter!(plot, temp_df.xcoord, temp_df.ycoord) # draw a scatterplot on canvas
    end
end

My plot doesnt behave as expected. whenever i change slider values the old scatterplot remains and a new scatterplot layer is written over it (you can tell by how the dot colours change). Also, the y-slider doesn’t seem to be working at all. What I’d like is one single scatterplot layer that automatically adjusts according to the slider values.

I also tried some solution with @lift, which I didnt get to work at all. can anyone help me out? Thanks in advance

The docs have a slider example where one point is moved around using two sliders Slider

The point is, don’t use scatter! in the onany, that will add more and more plot objects. Instead, modify a single observable that is plotted once.

I’ve tried that as well, the issue persists. Did it work for you?

If you don’t add plots in the onany block, I don’t see how that particular issue could persist. How did your attempt look?

Maybe something like this :

using GLMakie, DataFrames

fig = Figure() # initialize canvas

plot = Axis(fig[1, 1]) # initialize plot

sg = SliderGrid( # create slider grid
    fig[2, 1],
    (label = "x-limit", range = 0:0.1:10, format = "{:.1f}", startvalue = 0.5),
    (label = "y-limit", range = 0:0.1:10, format = "{:.1f}", startvalue = 0.5),
    )

xlimy, ylimy = sg.sliders[1].value, sg.sliders[2].value # turn slider values into simple observable variables

df = DataFrame("xcoord" => rand(10)*10, "ycoord" => rand(10)*10) # create random dataframe

points = lift(xlimy,ylimy) do value_x,value_y
       temp_df = filter(x -> (x.xcoord >= value_x) & (x.ycoord >= value_y), df)
       [Point2f(x,y) for (x,y) in zip(temp_df.xcoord,temp_df.ycoord)]
  end

scatter!(plot,points)

If you see, scatter! is called only once but the array of points is what evolves through observables. In your case, you were plotting something new every time the sliders moved. My implementation is not very well thought so it is not the best.

A couple tangential comments:

  1. No need to import Makie, only GLMakie is needed. If you are following a tutorial where both are used you may be looking at something old.
  2. Where you do, onany, you are using both time xlimy, I think you want ylimy in one of those.
  3. You missed DataFrames in the example.
1 Like

Thanks so much!

A difference to what I tried before was the list comprehension returnin an array of Point2f objects, I wasnt aware this is how the points need to get defined. Do I need to know more of the GLMakie-compatible objects for other kinds of plots? is there e.g. another specific struct that we need for interactive 3D plotting?

Ah yes. In my experience it is useful to have both coordinates in a point and not as independent observables by themselves. If you do not sometimes it happens that one gets updated too fast before the other one and you will get an error because the vectors x and y are not the same length. If you have a Point2f this does not happen.

I think the documentation in Makie is super well written and thought so it is a great resource to go through those examples and tutorials Tutorials

Another great resource with examples is Beautiful Makie

1 Like