Updating plots in Julia

I’m updating a scatter plot with new points as my simulation runs and I need to loop over a certain parameter and have a few plots on my graph. I’m just struggling with trying to have a legend that can update with each plot that is added, is there any way to do this? My code so far is roughly as follows:

f1 = Figure(size=(800, 400))
axis1 = Axis(f1[1, 1], title="E-field vs J at varying B fields", xlabel="J/J_d", 
      ylabel="E/E0")
xlims!(axis1, 0, 1.2)
ylims!(axis1,-0.0, 0.5)  
colors = [:red, :green, :blue, :purple, :orange, :yellow, :cyan, :magenta]
legend(axis1)
display(GLMakie.Screen(), f1)
Bs = 0.0:b_step:b_max
for i in 1:length(Bs)
        b_field = 0.0
        j = 0.0
        t = 0            
        b_app = Bs[i]
        (j_a, E_a) = (Float64[], Float64[])
        while j<jmax
                    b_field = b_app
                    j = t * ramp_rate
        
                    E = (a1_avg_i - a1_avg_j) / parameters(s).k     
                    
                    push!(j_a, j/Jd_fact)
                    push!(E_a, E)
        
                    scatter!(axis1, j_a, E_a; markersize=5, color=colors[i]) 

I just need to have a legend that is initialised outside the loop to update with the loop over the range of “Bs”

That’s totally possible.

Take a look at this Makie documentation page as a good place to start:

I don’t see an attempt to create a legend in your code so it’s hard to know what you want to do :slight_smile:

I wasn’t able to create an updating one in my code so I left it out of the description. I have added the external legend now, but am still unsure of how to update it. I imagine it will be along the lines of:

legend!(axis1, "B = "*string(b_app)).

Added below scatter!, but imagine this will just rewrite the legend as the code loops.

Thanks! Will have a look

Before I attempt to find a solution, I still don’t quite get what you want. Can you break it down to the basics? Do you want a plot that is updating live, and at some point you add a new plot to it which you want reflected with an entry in the legend? Or do you want to update labels for existing plots? There’s no working update logic in your example so I can’t tell. The legend and legend! functions in your code don’t exist in Makie, for example. Is that GPT generated?

I have taken some parts out of my code to try to make the problem clearer but I might’ve mistakenly taken out some parts that allow it to work in the way I’ve described, but I don’t think so. Yes that’s the aim, I have a plot which is updating live atm and would like to add new entries to a legend as a new plot is added, and yup I got the legend fn from GPT when I asked it how to create a legend in Makie.

Currently the figure is created outside the for loop, data is stored in the float arrays within the loop and added to from within the while loop. Currently the scatter!() function should add a scatter point every time a data point is added to the arrays. As the for loop goes to the next value i, this will have a b_app=Bs[i] associated with it and will create a new plot on the figure, as shown by a new colour - there are not too many of these values for b_app, only about 5. I am hoping to add a legend to the plot that updates every time a new plot is added to the figure.

For the way I have it set up at the moment I imagine I would add a new legend by somehow looping over the different labels, using something like name="B= "Bs[i]"

You should not do a new scatter! for each point as that’s very slow after a short while, you should update the input array of a single scatter like here for example Animations | Makie

Updating the legend by adding entries to it is currently not supported with public API. However, it’s technically possible by accessing some internals:

f = Figure()

display(f)

ax = Axis(f[1, 1])

leg = Legend(f[1, 2], [], [])

for i in 1:5
    scat = scatter!(ax, cumsum(randn(100)), color = i, colorrange = (1, 5))
    push!(leg.entrygroups[][1][2], Makie.LegendEntry("Scatter $i", scat, Makie.block_defaults(Legend, Dict(), nothing)))
    notify(leg.entrygroups)
    sleep(1)
end

f

Just don’t rely on this interface staying the same over time.

Ah ok. I was just using that method as it seemed to work for the time being, but I will have a look at the link as I have quite a bit of data that ends up on the plot.

Thanks very much for the help! I will add that in for the time being, but will go back to the usual method of making the plot after all the data is added to an array. I was just using this method to make sure the data that was coming out looked correct over the Bs range.