Open street map example#
The zombie outbreak model showcases an ABM running on a map, using OpenStreetMapSpace
.
using Agents
using Random
using CairoMakie
using OSMMakie
CairoMakie.activate!(px_per_unit = 1.0)
Update message: Agents v6
This is a new major version of Agents.jl with lots of cool stuff!
However, from this version onwards, we will stop posting update messages
to the REPL console!
If you want to be updated, follow this discourse post:
https://discourse.julialang.org/t/agents-jl-v6-releases-announcement-post/111678
(and see the CHANGELOG.md file online for a list of changes!)
The helper function is adapted from Agents.abmvideo
and correctly displays animations in Jupyter notebooks
function abmvio(model;
dt = 1, framerate = 30, frames = 300, title = "", showstep = true,
figure = (size = (600, 600),), axis = NamedTuple(),
recordkwargs = (compression = 23, format ="mp4"), kwargs...
)
# title and steps
abmtime_obs = Observable(abmtime(model))
if title ≠ "" && showstep
t = lift(x -> title*", time = "*string(x), abmtime_obs)
elseif showstep
t = lift(x -> "time = "*string(x), abmtime_obs)
else
t = title
end
axis = (title = t, titlealign = :left, axis...)
# First frame
fig, ax, abmobs = abmplot(model; add_controls = false, warn_deprecation = false, figure, axis, kwargs...)
resize_to_layout!(fig)
# Animation
Makie.Record(fig; framerate, recordkwargs...) do io
for j in 1:frames-1
recordframe!(io)
Agents.step!(abmobs, dt)
abmtime_obs[] = abmtime(model)
end
recordframe!(io)
end
end
abmvio (generic function with 1 method)
Agents for zombies and healthy humans
@agent struct Zombie(OSMAgent)
infected::Bool
speed::Float64
end
initialise model
function initialise_zombies(; seed = 1234)
map_path = OSM.test_map()
properties = Dict(:dt => 1 / 60)
model = StandardABM(
Zombie,
OpenStreetMapSpace(map_path);
agent_step! = zombie_step!,
properties = properties,
rng = Random.MersenneTwister(seed)
)
for id in 1:100
start = random_position(model) ## At an intersection
speed = rand(abmrng(model)) * 5.0 + 2.0 ## Random speed from 2-7kmph
human = add_agent!(start, Zombie, model, false, speed)
OSM.plan_random_route!(human, model; limit = 50) ## try 50 times to find a random route
end
# We'll add patient zero at a specific (longitude, latitude)
start = OSM.nearest_road((9.9351811, 51.5328328), model)
finish = OSM.nearest_node((9.945125635913511, 51.530876112711745), model)
speed = rand(abmrng(model)) * 5.0 + 2.0 ## Random speed from 2-7kmph
zombie = add_agent!(start, model, true, speed)
plan_route!(zombie, finish, model)
return model
end
initialise_zombies (generic function with 1 method)
Stepping function
function zombie_step!(agent, model)
# Each agent will progress along their route
# Keep track of distance left to move this step, in case the agent reaches its
# destination early
distance_left = move_along_route!(agent, model, agent.speed * model.dt)
if is_stationary(agent, model) && rand(abmrng(model)) < 0.1
# When stationary, give the agent a 10% chance of going somewhere else
OSM.plan_random_route!(agent, model; limit = 50)
# Start on new route, moving the remaining distance
move_along_route!(agent, model, distance_left)
end
# Agents will be infected if they get too close (within 10m) to a zombie.
if agent.infected
map(i -> model[i].infected = true, nearby_ids(agent, model, 0.01))
end
return
end
zombie_step! (generic function with 1 method)
Animation#
zombie_color(agent) = agent.infected ? :green : :black
zombie_size(agent) = agent.infected ? 10 : 8
zombies = initialise_zombies()
vio = abmvio(zombies;
title = "Zombie outbreak", framerate = 15, frames = 200,
agent_color = zombie_color, agent_size = zombie_size
)
save("zombie.mp4", vio)
vio |> display
Downloading artifact: osm_map_gottingen
[ Info: Created OSMGraph object with kwargs: `network_type=drive`, `weight_type=distance`, `graph_type=static`, `precompute_dijkstra_states=false`, `largest_connected_component=true`
This notebook was generated using Literate.jl.