It can also be fun to do something like this with a small GLMakie GUI. Here’s a mockup where the “fit” is just a line from first to last point of random data, but you get the gist. Afterwards you have your acceptance results in the accepted Observable and can process that further.
using GLMakie
struct Fit
y::Vector{Float64}
end
n = 100
fits = [Fit(cumsum(randn(n))) for _ in 1:n]
accepted = Observable(zeros(Bool, length(fits)))
f = Figure()
ax = Axis(f[1, 1])
i = Observable(1)
lines!(ax, @lift(fits[$i].y))
pseudofit_points = lift(i) do i
f = fits[i]
len = length(f.y)
[Point2(1, f.y[1]), Point2(len, f.y[end])]
end
lines!(ax, pseudofit_points, color = @lift($accepted[$i] ? :lightgreen : :red), linestyle = :dash, linewidth = 3)
subgl = GridLayout(f[2, 1], tellwidth = false)
prevbutton = Button(subgl[1, 1], label = "Prev")
on(prevbutton.clicks) do _
i[] = mod1(i[] - 1, n)
reset_limits!(ax)
end
Label(subgl[1, 2], @lift("Fit $($i)"))
nextbutton = Button(subgl[1, 3], label = "Next")
on(nextbutton.clicks) do _
i[] = mod1(i[] + 1, n)
reset_limits!(ax)
end
togglebutton = Button(subgl[1, 4], label = @lift($accepted[$i] ? "Reject" : "Accept"))
on(togglebutton.clicks) do _
accepted.val[i[]] =! accepted.val[i[]]
notify(accepted)
end
f