-
Notifications
You must be signed in to change notification settings - Fork 25
visualizing unaggregated agent data per step #88
Comments
Yeah okay, we can make it so that if you don't have an aggregating function, then multiple lines are plotted in one panel, one for each agent. Yes? My difficulty: what do you do when agents are deleted or more agents are added? It will lead to large and messy code :( cc @fbanning for now, custom plot is the way to go. |
If that's what you want to do, then the functions provided by InteractiveDynamics are currently not helpful for you at all.
I agree. It would probably be best to just use some custom plots (like we did in the HK example) to get the desired result.
Sure, that should be doable.
Adding/deleting new agents will definitely make the resulting plot look quite messy. Not so sure if it's really insightful to look at such a plot at all. But that's not really our concern, to be quite honest, because what you do with the framework we provide with this package is absolutely up to you. :) Alternative approachHere's an alternative approach that would leaves more choice and responsibility to the users: As I've already hinted at on Slack, I think it might be a good idea to make data collection in our interactive applications behave similar to the regular non-GUI That's why I propose that we unify the behaviour of Neither If pdata is empty, we don't plot anything. If it's not empty, we can iterate over this tuple and add the desired plots to the interactive app. What's cool about this is, that now we don't have to make any assumptions about the appropriate format of the data to be plotted but instead pass this responsibility to the users. Or we just do what George has proposed above (i.e. if |
My two cents as an user is that the gain in flexibility is very exciting. The gain in consistency is a good bonus too. (However, the proposal of @Datseris does solve my problem right away hahahaah). |
I almost got it via a custom plot! The only thinking I'm missing is rescaling it at each step, as done in the adata and mdata plots. Is it done here through the |
Yes.
Probably best to post a MWE of what you're doing so that we can better understand what you've already tried to do. You could for example take the custom plots example from the docs and alter the plots to reflect your use case. If you post something like that, we can have a look and give you a tip how to rescale the axes. |
Here is an working example that is very close to what I'm already doing. using Agents
using Distributions
using GLMakie
using InteractiveDynamics
mutable struct DummyAgent{n} <: AbstractAgent
id::Int
pos::NTuple{n,Float64}
am_I_plus::Bool
var_to_plot::Float64
end
function initialize_model(nagents=500, n=2)
space = ContinuousSpace(ntuple(x -> float(10),n), periodic = false)
model = ABM(DummyAgent{n}, space)
for i in 1:nagents
pos = Tuple(rand(Uniform(0,10), n))
add_agent_pos!(DummyAgent{n}(i, pos, false, rand(Uniform(0,10))), model)
end
for i in rand(allids(model), 250)
model[i].am_I_plus = true
end
return(model)
end
function var_increase(a)
a.am_I_plus ? a.var_to_plot += 1 : a.var_to_plot -= 1
end
function model_step!(model)
for i in allids(model)
var_increase(model[i])
end
end
function visualize_m(m)
fig,adf,mdf = abm_data_exploration(m,
dummystep,
model_step!)
var_wanna_observe = [Observable([m[i].var_to_plot * 10]) for i in allids(m)]
nsteps = Observable([0.])
function newstep(m, var_wanna_observe = var_wanna_observe, nsteps = nsteps)
model_step!(m)
var_values = [m[i].var_to_plot * 10 for i in allids(m)]
for (i,v) in enumerate(var_values)
var_wanna_observe[i][] = [v]
end
nsteps[] = push!(nsteps.val,nsteps.val[end]+ 1.)
end
fig,adf,mdf = abm_data_exploration(m, dummystep, newstep)
scatter(fig[1,2], nsteps, var_wanna_observe[1])
lines!(fig[1,2],nsteps, var_wanna_observe[1])
for i in var_wanna_observe[2:end]
scatter!(fig[1,2], nsteps, i)
lines!(fig[1,2], nsteps, i)
end
end
m = initialize_model()
visualize_m(m)
|
Hi, I'm finally back here
But
If a user wants to plot data, they use the interactive app and hence they must pass either
I wonder if all this complexity is necessary given how straightforward it is for users to be adding new plots to the app... I mean, I understand that it is difficult for the user @marcelovmaciel , hence this issue being open, but this doesn't necessarily mean that it is in general difficult. Furthermore, this is more about having familiarity with Makie.jl, not Agents.jl. So, we have to be careful about significantly increasing the complexity of the code, and the complexity of using the app, to counteract users not being able to use the already existing abilities of Makie.jl and InteractiveDynamics.jl on their own end. After the refactoring, where the interactive apps will just return an x = lift(model) do model
return whatever collected data in whatever form
end
ax = Axis in whatever location, even existing location
scatter!(ax, x) # or lines(x) or surface or whatever it is just too simple. It is simpler than making the decision of whether the interactive apps should scatter plot or not. (I guess we should also return the "time vector" observable that the current timeseries are plotted against...)
We need to be clear here. All flexibility you wish for, you already have. You can add arbitrary plots to any app, that show anything arbitrary of your choice, and is updated with the rest of the interactive app by using |
The snippet below has the same behavior as the previous one I posted (with less clutter), though I feel like I'm getting closer to something that would work. I truly don't understand why limits are not being update here. function visualize_m(m)
fig,adf,mdf = abm_data_exploration(m,
dummystep,
model_step!)
var_wanna_observe = [Observable([m[i].var_to_plot * 10]) for i in allids(m)]
nsteps = Observable([0.])
function newstep(m, var_wanna_observe = var_wanna_observe, nsteps = nsteps)
model_step!(m)
var_values = [m[i].var_to_plot * 10 for i in allids(m)]
for (i,v) in enumerate(var_values)
push!(var_wanna_observe[i].val, v)
end
nsteps[] = push!(nsteps.val,nsteps.val[end]+ 1.)
end
fig,adf,mdf = abm_data_exploration(m, dummystep, newstep)
ax = Axis(fig[1,2])
for i in var_wanna_observe[1:end]
lines!(ax, nsteps, i, linewidth = 0.5)
autolimits!(ax)
end
end
|
@marcelovmaciel Version 0.20.0 has been released. Please have a look at the updated docs section on custom plots and apply the new approach to your problem described here. It should now be possible to do whatever you want to do (and possibly even more). :) |
Right now the
adata
keyword inabm_data_exploration
requires an aggregating function. I'm interested in how to visualize unaggregated agent data per step, as done for instance in the HK example. More specifically, I'm interested in when collecting the agent-wise data applying a function and plot the evolution of the output of that function for each agent (so it is not only capturing a field value, but also doing some transformation on it and then visualizing it). I suppose I could do so in a custom plot, but I haven't been able to come up with such a code (and this may then be actually a Makie question).The text was updated successfully, but these errors were encountered: