Unable to use InteractiveDynamics and Agents as Part of my Package

I am trying to use the latest InteractiveDynamics v0.20 and Agents v5.0 as part of my project. Since yesterday, I am getting the following error, whenever I try to precompile my package.

ERROR: LoadError: UndefVarError: abmplot not defined  
Stacktrace:

So, I tried to recreate it minimally as follows. I generated a new project ‘DaisyWorldTest’ using Pkg generate. I activated the project and added the following packages: Agents, InteractiveDynamics, CairoMakie, StatsBase, Random. The last two because the sample code requires it.
The project contains only two files
File 1: DaisyWorldTest.jl

module DaisyWorldTest

include("DaisyWorld.jl")

end # module

File 2: DaisyWorld.jl Exact same Agent Based Models · InteractiveDynamics (juliadynamics.github.io) Pasting it below for convenience

using InteractiveDynamics, Agents
using CairoMakie
daisypath = joinpath(dirname(pathof(InteractiveDynamics)), "agents", "daisyworld_def.jl")
include(daisypath)
model, daisy_step!, daisyworld_step! = daisyworld(; solar_luminosity = 1.0, solar_change = 0.0, scenario = :change)

daisycolor(a::Daisy) = a.breed # color of agents
as = 14 # size of agents
am = '♠' # marker of agents
heatarray = :temperature
heatkwargs = (colorrange = (-20, 60), colormap = :thermal)
plotkwargs = (;
    ac = daisycolor, as, am,
    scatterkwargs = (strokewidth = 1.0,),
    heatarray, heatkwargs
)

fig, ax, abmobs = abmplot(model; plotkwargs...)
fig

I use VSCode and when I do Alt+Enter (aka Execute active file in REPL) on DaisyWorld.jl, everything works as expected and I can see the Plot!
But when I precompile the DaisyWorldTest package. I get UndefVarError: abmplot not defined error. I am planning to build a traffic simulation package which uses Agents.jl and InteractiveDynamics.jl. It won’t work for me, if I can’t use Agents and InteractiveDynamics as part of a another project.

Please help!

What’s inside Daisyworld.jl ?

The same as in Agent Based Models · InteractiveDynamics (juliadynamics.github.io)

Just tried to run exactly your module and it worked just fine without any errors. I cannot reproduce your issue, sorry.

Edit:
So I can access everything as expected when using modules.

julia> IDTest.

Daisy                       daisy_step!                  eval                         plotkwargs
DaisyWorld                  daisycolor                   fig                          propagate_daisy!
abmobs                      daisypath                    heatarray                    solar_activity!
am                          daisyworld                   heatkwargs                   update_surface_temperature!
as                          daisyworld_step!             include
ax                          diffuse_temperature!         model
julia> IDTest.abmplot
abmplot (generic function with 1 method)

help?> IDTest.abmplot
  abmplot(model::ABM; kwargs...) → fig, ax, abmobs
  abmplot!(ax::Axis/Axis3, model::ABM; kwargs...) → abmobs

  Plot an agent based model by plotting each individual agent as a marker and using the agent's position field as its
  location on the plot. The same function is used to make custom composite plots and interactive applications for the
  model evolution using the returned abmobs. abmplot is also used to launch interactive GUIs for evolving agent based
  models, see "Interactivity" below.

...

Uninstalled Julia, Deleted everything related to julia. Did a fresh installation and getting the exact same error. Executing the DaisyWorld.jl file in REPL creates the plot. Bit When I go to Pkg(']) and precompile, I am getting the ‘undefVar error for abmplot’.

If its something weird only with my local system then the CI (github workflow) should have worked. It fails with the same. I have another fresh machine. I’ll try to recreate it on that machine and see how it goes. Thanks anyway.

I’ve created a file with your module in it. Loaded that module and executed everything in it, no problem. I really can’t tell where the difference is to what you did.

I have two files

  1. DaisyWorldTest.jl : This file is the primary file for the DaisyWorldTest module. This file ‘includes’ DaisyWorld’.jl
  2. DaisyWorld.jl file is not a module by itself. It ‘uses’ Agents and InteractiveDynamics and creates the plot.
    When I go to Pkg mode (‘]’) and do precompile. It fails with abmplot undefvar error.
    If I open the DaisyWorld.jl file and execute it in repl. It works perfectly and generates the plot.

I found a fix, but I am still unsatisfied without being able to figure out what I did wrong.

Fix: I wrapped the code inside DaisyWorld.jl inside a module. Now, the DaisyWorld.jl starts with the line
`module MyModule’.

I modified the DaisyWorldTest.jl as follows

include("DaisyWorld.jl")

using .MyModule

Now precompile works fine. No more issues…

I am moving on. .But why? what did I do wrong?..whats the difference?
I am slightly worried that if I don’t address this debt, I might have to pay the cost later.

@fbanning Thank you very much for your help. I really appreciate it.

Edit: Replicated the same in a new machine (mac mini). Followed the steps as explained in the first post. Same error!

I’m still not able to replicate this in a new environment (add InteractiveDynamics, Agents, CairoMakie) with exactly your two files (DaisyWorldTest.jl as the module that includes Daisworld.jl). If I then just run DaisyWorldTest.jl in this environment, it compiles and works just fine. No errors, nothing. I can produce the plot just fine after including DaisyWorldTest.jl by running DaisyWorldTest.abmplot(DaisyWorldTest.model; DaisyWorldTest.plotkwargs...) just as we could expect it from how you laid out your code. Sorry, I don’t think this is an issue with Agents and/or InteractiveDynamics.

Kindly explain what you mean by “run DaisyWorldTest.jl”. Did you try “precompile”.
If you meant executing the file in REPL. It works for me as well. No issues there. But precompile fails.
Made a quick video. Unfortunately, can’t upload here. Sent to you in slack.

Edit: uploaded the video to youtube as an unlisted video

Yes, worked without any problems.

@codekomali did you manage to get a solution to this? I am having similar issues with the Flocking example in Agents.

Based on the publication connected with Agents.jl ( https://doi.org/10.1177/00375497211068820) abmplot should actually be abm_plot, which does work. So this is probably just a typo in the Tutorial docs. The same goes for abmvideo.

For the Flocking example I still have errors that stem from the Scheduler with:

ABM( SchellingAgent, space; properties, rng, scheduler = Schedulers.Randomly())
ERROR: UndefVarError: Randomly not defined

and with the marker definition:

const bird_polygon = Polygon(Point2f[(-0.5, -0.5), (1, 0), (-0.5, 0.5)])
ERROR: UndefVarError: Point2f not defined

but for now just removing and using the defaults suffices.

They have recently been reworked and renamed. If you’re using an up-to-date version of InteractiveDynamics.jl, you should switch to using abmplot/abmvideo.

1 Like

Further to this topic, there appears to be something missing from the Flocking example in the tutorial. Everything works fine until I replace the abmplot by abmvideo:

abmvideo(
	"flocking.mp4", model, agent_step!;
	am = boid_marker,
	framerate = 20, frames = 100,
	title = "Flocking"
)

When I do this, I get the following error:

ERROR: type Nothing has no field visual_distance
Stacktrace:
  [1] getproperty
...
 [11] abmvideo(file::String, model::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, agent_step!::typeof(Main.Basics.agent_step!), model_step!::typeof(Agents.dummystep); spf::Int64, framerate::Int64, frames::Int64, title::String, showstep::Bool, figure::NamedTuple{(:resolution,), Tuple{Tuple{Int64, Int64}}}, axis::NamedTuple{(), Tuple{}}, recordkwargs::NamedTuple{(:compression,), Tuple{Int64}}, kwargs::Base.Pairs{Symbol, typeof(Main.Basics.boid_marker), Tuple{Symbol}, NamedTuple{(:am,), Tuple{typeof(Main.Basics.boid_marker)}}})
    @ InteractiveDynamics C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\convenience.jl:149

Any ideas?

No idea just now. Could you post the full stacktrace?

Edit: I’ve just tried to reproduce your error with the example model from the docs and that produced the video just fine.

Edit 2: Scratch that , I found a problem but it throws a completely different stacktrace than what you posted. Would still be great if you could post the full version of it so that we can have a look if it’s the same cause.

Also please post the versions of Agents, Makie and InteractiveDynamics that you use. I’ve used Agents v5.6.3, GLMakie v0.6.13, InteractiveDynamics v0.21.11 for my tests.

Thanks. OK, here goes …

The versions are:

Agents v5.6.3
GLMakie v0.6.13
InteractiveDynamics v0.21.11

The code is:

module Basics

using Agents, LinearAlgebra, Random, GLMakie, InteractiveDynamics

@agent Boid ContinuousAgent{2} begin
	speed::Float64
	cohere_factor::Float64
	separation::Float64
	separate_factor::Float64
	match_factor::Float64
	visual_distance::Float64
end

function initialize_model(;
    n_boids = 100,
    speed = 1.0,
    cohere_factor = 0.25,
    separation = 4.0,
    separate_factor = 0.25,
    match_factor = 0.01,
    visual_distance = 5.0,
    extent = (100, 100),
)
    space2d = ContinuousSpace(extent; spacing = visual_distance/1.5)
    model = ABM(Boid, space2d, scheduler = Schedulers.Randomly())
    for _ in 1:n_boids
        vel = Tuple(rand(model.rng, 2) * 2 .- 1)
        add_agent!(
            model,
            vel,
            speed,
            cohere_factor,
            separation,
            separate_factor,
            match_factor,
            visual_distance,
        )
    end
    return model
end

function agent_step!(boid, model)
	# Obtain the ids of neighbors within the bird's visual distance
	neighbor_ids = nearby_ids(boid, model, model.visual_distance)
	N = 0
	match = separate = cohere = (0.0, 0.0)
	# Calculate behaviour properties based on neighbors
	for id in neighbor_ids
		N += 1
		neighbor = model[id].pos
		heading = neighbor .- boid.pos

		# `cohere` computes the average position of neighboring birds
		cohere = cohere .+ heading
		if edistance(boid.pos, neighbor, model) < model.separation
			# `separate` repels the bird away from neighboring birds
			separate = separate .- heading
		end
		# `match` computes the average trajectory of neighboring birds
		match = match .+ model[id].vel
	end
	N = max(N, 1)
	# Normalise results based on model input and neighbor count
	cohere = cohere ./ N .* model.cohere_factor
	separate = separate ./ N .* model.separate_factor
	match = match ./ N .* model.match_factor
	# Compute velocity based on rules defined above
	boid.vel = (boid.vel .+ cohere .+ separate .+ match) ./ 2
	boid.vel = boid.vel ./ norm(boid.vel)
	# Move bird according to new velocity and speed
	move_agent!(boid, model, boid.speed)
end

const boid_polygon = Polygon(Point2f[(-0.5, -0.5), (1, 0), (-0.5, 0.5)])
function boid_marker(b::Boid)
	φ = atan(b.vel[2], b.vel[1]) #+ π/2 + π
	scale(rotate2D(boid_polygon, φ), 2)
end

## Plotting the flock
function demo()
	model = initialize_model()
#	figure, = abmplot(model; am = boid_marker)
#	figure
	abmvideo(
		"flocking.mp4", model, agent_step!;
		am = boid_marker,
		framerate = 20, frames = 100,
		title = "Flocking"
	)
end

end

The stack trace is:

ERROR: type Nothing has no field visual_distance
Stacktrace:
  [1] getproperty
    @ .\Base.jl:38 [inlined]
  [2] getproperty(m::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, s::Symbol)
    @ Agents C:\Users\hswt136nia\.julia\packages\Agents\9UdZV\src\core\model.jl:165
  [3] agent_step!(boid::Main.Basics.Boid, model::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG})
    @ Main.Basics C:\Users\hswt136nia\OneDrive\Documents\Rock Dene Cottage\Playing\Julia\Sandpit\Basics.jl:44
  [4] step!(model::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, agent_step!::typeof(Main.Basics.agent_step!), model_step!::typeof(Agents.dummystep), n::Int64, agents_first::Bool)
    @ Agents C:\Users\hswt136nia\.julia\packages\Agents\9UdZV\src\simulations\step.jl:55
  [5] step!
    @ C:\Users\hswt136nia\.julia\packages\Agents\9UdZV\src\simulations\step.jl:48 [inlined]
  [6] step!(abmobs::InteractiveDynamics.ABMObservable{Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, typeof(Main.Basics.agent_step!), typeof(Agents.dummystep), Nothing, Nothing, Nothing, Nothing, Bool}, n::Int64; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ InteractiveDynamics C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\model_observable.jl:53
  [7] step!
    @ C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\model_observable.jl:51 [inlined]
  [8] (::InteractiveDynamics.var"#93#96"{Int64, Int64, InteractiveDynamics.ABMObservable{Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, typeof(Main.Basics.agent_step!), typeof(Agents.dummystep), Nothing, Nothing, Nothing, Nothing, Bool}, Observables.Observable{Int64}})(io::Makie.VideoStream)
    @ InteractiveDynamics C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\convenience.jl:152
  [9] Record(func::InteractiveDynamics.var"#93#96"{Int64, Int64, InteractiveDynamics.ABMObservable{Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, typeof(Main.Basics.agent_step!), typeof(Agents.dummystep), Nothing, Nothing, Nothing, Nothing, Bool}, Observables.Observable{Int64}}, figlike::Makie.Figure; framerate::Int64)
    @ Makie C:\Users\hswt136nia\.julia\packages\Makie\Ppzqh\src\display.jl:583
 [10] #record#957
    @ C:\Users\hswt136nia\.julia\packages\Makie\Ppzqh\src\display.jl:577 [inlined]
 [11] abmvideo(file::String, model::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, agent_step!::typeof(Main.Basics.agent_step!), model_step!::typeof(Agents.dummystep); spf::Int64, framerate::Int64, frames::Int64, title::String, showstep::Bool, figure::NamedTuple{(:resolution,), Tuple{Tuple{Int64, Int64}}}, axis::NamedTuple{(), Tuple{}}, recordkwargs::NamedTuple{(:compression,), Tuple{Int64}}, kwargs::Base.Pairs{Symbol, typeof(Main.Basics.boid_marker), Tuple{Symbol}, NamedTuple{(:am,), Tuple{typeof(Main.Basics.boid_marker)}}})
    @ InteractiveDynamics C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\convenience.jl:149
 [12] demo()
    @ Main.Basics C:\Users\hswt136nia\OneDrive\Documents\Rock Dene Cottage\Playing\Julia\Sandpit\Basics.jl:85
 [13] top-level scope
    @ REPL[3]:1

Sorry to be bothersome, but are you making progress on this? I need to make the decision whether to use Agents and InteractivDynamics in a simulation course in the coming spring semester, and I’m not really making any progress at all at the moment. If you don’t have time to look at it, I’ll take a deeper dive myself.

Best wishes,
Niall.

The problem is not in the package but in your stepping function.

You have assigned the kwargs of the initialize_model() function to the agents as agent variables. (Right now they seem to be the same for all agents which makes this a bit unnecessary but maybe you wanted to make them heterogeneous in the long run, I don’t know. Doesn’t matter too much right now. I’ll just assume you know what you’re doing and won’t question this choice.)

You try to access model.visual_distance inside your agent_step! function even though you did not add it as a model property. I suspect you wanted to write boid.visual_distance instead since this is inside the agent stepping function.

The same applies to all other calls to the agent variables, e.g. cohere_factor, separation, etc. Just change them to boid. instead of model. inside the agent_step! function and everything works as expected. (Just tested it myself to be sure.)

Well, that’s a bit embarrassing - I’m sorry to have wasted your time. I didn’t check the code thoroughly because I thought I’d checked it when I used it last year. Thank you very much for your time and effort!