假设我们有以下Agents.jl + Makie.jl工作流:
using Agents, Random, AgentsPlots, Makie, Observables
mutable struct BallAgent <: AbstractAgent
id::Int
pos::Tuple{Float64, Float64}
vel::Tuple{Float64, Float64}
mass::Float64
end
function ball_model(; speed = 0.002)
space2d = ContinuousSpace(2; periodic = true, extend = (1, 1))
model = AgentBasedModel(BallAgent, space2d, properties = Dict(:dt => 1e0, :i => Observable(0)))
Random.seed!(1001)
for ind ∈ 1:500
pos = Tuple(rand(Float64, 2))
vel = (sincos(rand(Float64) * 2π) |> reverse) .* speed
add_agent!(pos, model, vel, 1e0)
end
index!(model)
return model
end
agent_step!(agent::BallAgent, model) = move_agent!(agent, model, model.dt)
function AbstractPlotting.:plot!(scene::AbstractPlotting.Plot(AgentBasedModel))
ab_model = scene[1][]
position = Observable([a.pos for a ∈ allagents(ab_model)])
on(ab_model.i) do i
position[] = [a.pos for a ∈ allagents(ab_model)]
end
scatter!(scene, position, markersize = 0.01)
end
function create_animation()
model = ball_model()
scene = plot(model)
display(AbstractPlotting.PlotDisplay(), scene)
for i ∈ 1:600
Agents.step!(model, agent_step!, 1)
model.i[] = i
sleep(1/60)
end
end现在由于AgentsPlot.jl不支持Makie,我必须为它制作一个配方,目前我更新绘图的方式是注册一个回调,该回调更新可观察到的位置,该回调被传递给scatter。
问题是我在一个Int observable上注册了这个回调,这个Int observable附加到专门为此而创建的AgentBasedModel上。这似乎是一种丑陋的方式。
model = AgentBasedModel(BallAgent, space2d, properties = Dict(:dt => 1e0, :i => Observable(0))) i是我们将回调附加到的可观察对象,如下所示:
on(ab_model.i) do i
position[] = [a.pos for a ∈ allagents(ab_model)]
end我必须在这里更新它,这样回调就会像这样被调用:
for i ∈ 1:600
model.i[] = i发布于 2020-04-13 01:25:42
使其更优雅的一种方法是在模型本身上添加一个回调,然后使用Observables.notify!(model)触发回调。这样你就不需要另一个变量来跟踪了,但我仍然觉得它可以变得更优雅。
using Agents, Random, AgentsPlots, Makie, Observables
mutable struct BallAgent <: AbstractAgent
id::Int
pos::Tuple{Float64, Float64}
vel::Tuple{Float64, Float64}
mass::Float64
end
function ball_model(; speed = 0.002)
space2d = ContinuousSpace(2; periodic = true, extend = (1, 1))
model = AgentBasedModel(BallAgent, space2d, properties = Dict(:dt => 1e0))
Random.seed!(1001)
for ind ∈ 1:500
pos = Tuple(rand(Float64, 2))
vel = (sincos(rand(Float64) * 2π) |> reverse) .* speed
add_agent!(pos, model, vel, 1e0)
end
index!(model)
return model
end
agent_step!(agent::BallAgent, model) = move_agent!(agent, model, model.dt)
function AbstractPlotting.:plot!(scene::AbstractPlotting.Plot(AgentBasedModel))
model = scene[1]
position = Observable([a.pos for a ∈ allagents(model[])])
on(model) do _model
position[] = [a.pos for a ∈ allagents(_model)]
end
scatter!(scene, position, markersize = 0.01)
end
function create_animation()
model = Observable(ball_model())
scene = plot(model)
display(AbstractPlotting.PlotDisplay(), scene)
for i ∈ 1:600
Agents.step!(model[], agent_step!, 1)
Observables.notify!(model)
sleep(1/60)
end
end编辑:Observables.notify!(model)简单地执行model[] = model[]
https://stackoverflow.com/questions/61175187
复制相似问题