首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Julia中为Agents.jl制作Makie.jl plot食谱动画的优雅方法是什么?

在Julia中为Agents.jl制作Makie.jl plot食谱动画的优雅方法是什么?
EN

Stack Overflow用户
提问于 2020-04-13 01:09:48
回答 1查看 228关注 0票数 4

假设我们有以下Agents.jl + Makie.jl工作流:

代码语言:javascript
复制
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是我们将回调附加到的可观察对象,如下所示:

代码语言:javascript
复制
  on(ab_model.i) do i
        position[] = [a.pos for a ∈ allagents(ab_model)]
    end

我必须在这里更新它,这样回调就会像这样被调用:

代码语言:javascript
复制
  for i ∈ 1:600
        model.i[] = i
EN

回答 1

Stack Overflow用户

发布于 2020-04-13 01:25:42

使其更优雅的一种方法是在模型本身上添加一个回调,然后使用Observables.notify!(model)触发回调。这样你就不需要另一个变量来跟踪了,但我仍然觉得它可以变得更优雅。

代码语言:javascript
复制
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[]

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61175187

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档