In previous NetLogo tutorials, I discussed some of the powerful features of NetLogo, and the use of extensions. In this post, we will look at the extension which links to the R toolkit (see this article on the extension, and this documentation).
The R extension can be used for data analysis and visualisation, as an alternative to writing data to files and reading them back. Even more helpful is the use of R to implement agent decision-making. Here we provide very simple examples of both uses of R (a third use would be hybrid models such as this).
To use the R extension, follow the installation instructions here. In addition, the rJava package must be installed in R, and the jri folder inside the rJava folder must contain the files JRIEngine.jar
and REngine.jar
(if need be, Google can find these files). The NetLogo file must begin with extensions [ r ]
.
Our first demonstration is an implementation of Conway’s “Game of Life.” A global variable (history
) stores a list of the fraction of cells that are alive at each step. The NetLogo code below uses R to plot that list. The r:eval
function executes arbitrary R code, while r:put
assigns a NetLogo value to a named R variable (converting, for example, NetLogo lists into vectors). There are also variations of r:put
(r:putagent
, r:putagentdf
, r:putlist
, r:putnamedlist
, and r:putdataframe
– see this table).
to rplot-graph ;; code for "Plot Life" button
if (is-life?) [
r:put "life.hist" history
r:eval "png (filename = \"C:/NetLogo/Life_plot.png\", width = 1600, height = 800, pointsize=18)"
r:eval "par (mar=c(5,5,0.8,0.5))"
r:eval "xs <- 0:(length(life.hist)-1)"
r:eval "plot (life.hist ~ xs, type=\"l\", lwd=4, col=\"red\", xlab=\"Step\", ylab=\"Density\", ylim=c(0,max(life.hist)), cex.lab=2, cex.axis=1.5)"
r:eval "dev.off()"
]
end
The resulting plot is as follows:
More sophisticated statistical analysis in R includes the use of spatial techniques.
The implementation combines variables for both examples in this tutorial:
globals [
is-life? ;; distinguish between the two demos
;; for LIFE
cell-count ;; total number of cells
total ;; total number of live cells
history ;; list of totals
;; for BACTERIA
window ;; number of steps over which to analyse
]
patches-own [
;; for LIFE
alive? ;; is cell alive?
counter ;; used to pass number of live neighbours between Phase 1 and Phase 2
;; for BACTERIA
value ;; simulated chemical concentration
]
turtles-own [
;; for BACTERIA
hist ;; history of concentration values
]
The setup code for the “Game of Life” is fairly straightforward, using two utility functions to make a patch alive or dead:
;; code for SETUP button -- Life
to setup-life
clear-all
set is-life? true
set cell-count (count patches)
ask patches [
ifelse (random-float 1 < average-life-density) [birth] [death]
]
reset-ticks
set history (list (total / cell-count))
end
to death ;; this procedure applies to a specific patch
set alive? false
set pcolor white
end
to birth ;; this procedure applies to a specific patch
set alive? true
set pcolor blue
set total (total + 1)
end
The step code is also straightforward, using two phases (one to count live neighbours, and one to compute the future state):
to go ;; single simulation step for both demos
if-else (is-life?) [
;; LIFE
;; First phase
ask patches [ set counter (count neighbors with [alive?]) ]
;; Second phase
set total 0
ask patches [
ifelse (counter = 3 or (counter = 2 and alive?))
[ birth ]
[ death ]
]
set history (lput (total / cell-count) history) ;; Record current density
tick
] [
;; BACTERIA
... snip ...
]
end
The second demo (see screenshot above) simulates bacterial chemotaxis. Bacteria move up a chemical gradient by moving in a straight line if the concentration is increasing, and by randomly changing direction if it is not. We make the decision using the reporter below, which calculates the slope of the best-fit line through the datapoints (this is a very simple example of using R code to implement an agent’s decision-making). The r:get
reporter is used to return the value of an R expression (in this case, the slope):
to-report calculate-slope [ lst ] ;; R interface -- calculate slope for values in lst
r:put "valu.hist" lst
r:eval "valu.index <- 1:length(valu.hist)"
r:eval "valu.lm <- lm(valu.hist ~ valu.index)"
report r:get "valu.lm$coefficients[2]"
end
A slightly more efficient option would have been to use r:eval
to define an R function in setup, and then to call it here with valu.hist
as an argument.
Related uses of R for agent decision-making include implementations of neural networks, clustering, pattern-recognition, and the like.
Returning to our example, most of the setup code calculates a chemical gradient, but some bacteria are also created:
;; code for SETUP button -- Bacteria
to setup-bacteria
clear-all
set is-life? false
set window 4
;; create gradient
repeat 3 [
let x random-xcor
let y random-ycor
let v (0.1 + random-float 0.5)
let r (1 + v * world-width / 2)
ask patches [
let d ((distancexy x y) / r)
set value (value + v * exp (- d))
]
]
let min-value (min ([value] of patches))
let max-value (max ([value] of patches))
ask patches [
set pcolor (30 + (9.9 * (value - min-value) / (max-value - min-value)))
]
;; create some bacteria
crt 20 [
setxy random-xcor random-ycor
set color red
set size 6
set hist (list value)
]
reset-ticks
end
The implementation of bacterial chemotaxis is straightforward, using the previously defined reporter calculate-slope
:
to go ;; single simulation step for both demos
if-else (is-life?) [
;; LIFE
... snip ...
] [
;; BACTERIA
ask turtles [
fd 1
set hist (lput value hist)
if (length(hist) > window) [ set hist (bf hist) ]
if (length(hist) = window) [
if (calculate-slope hist <= 0) [
set heading (random-float 360)
set hist (list value)
]
]
]
tick
]
end
The complete NetLogo file can be found at found at Modeling Commons. Also worth looking at is the RNetLogo package for running NetLogo inside R.
Like this:
Like Loading...