Plotting elements of a list through time (ticks) - netlogo

I would need to study the distribution through time of items that are selected from a list, based on agent source’s breed (women and men).
At each tick, a breed woman or man creates a new object that is added in other turtles’lists. This/these objects can be selected at each step (ticks) by other turtles (women and/or men), spreading within the network.
In the plot, the y-axis should have the number of occurrences (frequency) of each object in the visited turtles (i.e. turtles that have selected that item from their lists).
Example:
object 3 is created by a man, object 5 is created by a woman.
man 2: count 1 object 3 (object 3 created) at tick 1
woman 4: count 1 object 5 (object 5 created) at tick 3
...
man 2: count 1 object 3 (object 3 picked) at tick 12
man 2: count 1 object 3 (object 3 picked) at tick 12
man 2: count 1 object 3 (object 3 picked) at tick 13
...
woman 31: count 1 object 5 (object 5 picked) at tick 21
Plots:
for object 3, I would have (dots in blue as it was created by a man)
x y
1 1
2 0
3 0
...
12 2
13 1
...
and for object 5 (dots in red as it was created by a woman):
x y
1 1
2 0
3 0
...
12 0
13 0
...
21 1
...
Do you have any suggestions on how I could plot over time items that are created, then picked by turtles and see, separately, the different distributions over time?

What you could do is using length filter in order to get the count of objects created by either men or women (if I understood well, this is item 2 in your list example):
let selected (list item 0 list_1 item 1 list_1 item 2 list_1)
ifelse item 2 list_1 = women [
set list_1_w fput selected list_1_w
print (word "List objects created by women: " list_1_w)
let list_count_w (length (filter [a -> item 2 a = women] list_1_w)) /* added */
]
[ set list_1_m fput selected list_1_m
print (word "List objects created by men: " list_1_m)
let list_count_m (length (filter [a -> item 2 a = men] list_1_m)) /* added */
]
The two letvariables above return a count of objects created by women or men. This count considers only breed women and men, not distinguishing between objects created by woman x and objects created by man x. About plotting them, probably you should count all of them at each tick in order to have a chronology of the number of events (objects) selected through time by agents.
To track each object, an idea would be to create a temporary plot pen that can track all objects:
ask turtles [ /* here you should distinguish between objects created by women and objects created by men */
create-temporary-plot-pen (word who)
set-plot-pen-color color
plotxy ticks ___ /* you should add here variable that you want to consider */
]
The code above can create a multiplot to track all objects (but you will need to label them and keep track when they're selected).
It's just an idea. You (or someone else in the community) should change accordingly the code above to consider the different breeds and how to track these objects through time.
I hope this can be of some help!

Since I can't seem to get you to understand my questions, I have a different suggestion. Stop trying to do a plot. Instead, do a monitor on the screen that does the calculation (at each tick) of whatever it is you are trying to plot. You can have one monitor for each breed. Once you have the monitor working, just use the same code as the pen in a plot.

Related

NetLogo: getting randomly chosen position of a repeated value in a list

If I have the following: set list [8 1 0 3 4 2 0 1 2 4 25 0 3 3]. I would like to find a way to get, for example, a random item position for zero (2, 6 or 11) or for three (3, 12 or 13).
I have tried with:
let i (position (one-of list = 0) list )
print i
However, that only returns a boolean i. I know I could use position 0 list, but that gives priority to the first position (2, in the case of zero) while I would like it to randomly chosen from all values equal to zero on the list. I thought of using a while[], but I was wondering if there is a faster and simpler way.
In general, when you are working with lists, it is a good idea to familiarise yourself with anonymous procedures and some related primitives like map and filter.
I wrote a quick procedure, called positions that should be able to take care of this. First I create a list containing all the possible indexes: index-list.
Next, I use map to simultaneously go through the input-list and the index-list. It uses ifelse-value to check for each item of the input-list whether or not it corresponds to the input-item that you wanted to check it against. If they correspond, it returns the position of that item in the input-list. Otherwise it returns FALSE.
The final step is to filter out all the FALSE responses so that you are left with a list containing only the positions of your input-item in the input-list.
to-report positions [ input-item input-list ]
let index-list range length input-list
let position-list (map [ [list-item index] -> ifelse-value input-item = list-item [index][FALSE] ] input-list index-list)
report filter [index -> index != FALSE] position-list
end
Testing this gives [2 6 11] as a result, which corresponds with what you would expect
to test
let my-list [8 1 0 3 4 2 0 1 2 4 25 0 3 3]
show positions 0 my-list ;[2 6 11]
end

How to create a sequential counter in NetLogo 6.2?

I would like to know if there is any way to implement a sequential counter without using a list by intervals. I'm trying to implement the following: at the end of each tick is counting the population size (NFinal). And then, we would check the constancy of the population, through a subtraction (the logical test would be the result of this subtraction is equal to zero during 3 consecutive ticks?).
For example:
NFinal of tick 0 - NFinal of tick 1 = 0
NFinal of tick 1 - NFinal of tick 2 = 0
NFinal of tick 2 - NFinal of tick 3 = 0
If this is the scenario (with 3 sequential values ​​equal to zero), the simulation will stop.
However, if it is in the scenario:
NFinal of tick 0 - NFinal of tick 1 = 0
NFinal of tick 1 - NFinal of tick 2 = 0
NFinal of tick 2 - NFinal of tick 3 = 2
The simulation does not stop (since it did not have 3 zero values ​​in sequence) and therefore would reset the counter to continue the simulation.
However what I managed to implement was by intervals using list. I don't know if it's the best way. Well, every time I use the list my model is getting slower. Is there a simpler way to implement this?
Thanks in advance!
Attempt below:
globals [ StabilityList ConstanceInterval ]
to go
if ConstanceInterval = 0 [ stop ]
end
to StabilityCheckerProc
set StabilityList lput 1 StabilityList ;; 1 = NFinal
let i 3 ;;
if length StabilityList >= i
[
let t1 last StabilityList
let start ( length StabilityList - i )
let t0 item start StabilityList
set ConstanceInterval abs ( t1 - t0 )
]
set StabilityList get-last i StabilityList
end
to-report get-last [ num lst ]
let b length lst
let a b - num
report sublist lst ( ifelse-value ( a < 0 ) [ 0 ] [ a ] ) b
end
You could use a counter to track the number of occurrences in a row, such that if your condition is satisfied you increase the counter, and if it is not you reset the counter. For example:
globals [ zero-tracker ]
to setup
ca
reset-ticks
end
to go
let variable-placeholder random 5
ifelse variable-placeholder = 0 [
; If a zero is recorded (eg, the result of your subtraction operation,
; increase the zero-tracker by one
set zero-tracker zero-tracker + 1
] [
; If anything BUT a zero is recorded, reset the zero-tracker
set zero-tracker 0
]
tick
if zero-tracker = 3 [
stop
]
end
Luke's answer is the answer.
But, if for any reason you did have a problem that needed to look at the last X things, and a counter was not going to work, you could use a list, but keep it at length X.
;; in setup, initialize the list with 'memory-size' items
set memory map [ -> 0] range 0 memory-size
;; in go, add a new memory to the list, and drop an old memory
set memory but-first lput value memory
;; then do what you must to examine the memories
< that code here >
Still slower than using a counter, but probably faster than accumulating and taking sections from an ever-growing list of values.
If you do need to maintain an ever-growing list of values, you might still maintain this smaller list.
Finally, even when using the ever-growing list of values, it would be fewer operations to take the sublist off the front of the list:
;; add new memory to front of list
set memory fput value memory
;; get last three memories from front of list
let last-three sublist memory 0 3 ;; no math or length needed
As always, test any assertion that something might be faster.

Updating counter of picked objects from a list

I would like to update the counter of an element in a list, every time it is picked from turtles.
To do that, I am setting the item I am interested in and adding 1 to it (counter).
I created a global variable called it_cnt and I set it equal to 0 in the hatch where I create the objects (in order to know which turtle owns that item initially).
This is where I initialise the counter:
ask buyers [
hatch-obj random 5 [
set it_cnt 0
]
]
Please see below the list that I am considering
let picked_obj (list item 0 obj_in_shop_bag item 1 obj_in_shop_bag item 2 obj_in_shop_bag item 3 obj_in_shop_bag)
I am updating the counter as follows
let new_id_cnt item 3 picked_obj + 1
to add 1 in case the picked_obj is chosen by a buyer. However, when I print the list to see if it works
print (word " ; " item 0 obj_in_shop_bag " ; " item 1 obj_in_shop_bag " ; " item 2 obj_in_shop_bag " ; " item 3 new_id_cnt)
if the item is picked twice from different buyers in different ticks (ticks are item 0 in the list), the only value that I get is 1, as it was reset.
I would greatly appreciate if you could tell me how to fix the counter in order to let it work correctly.
Many thanks.
This is not an answer but is too long for comments. I can't make sense of the question.
You have set it_cnt 0 in the hatch but you say it's a global variable. So if you have 10 buyers, each of them hatches 0 to 4 obj and that single copy of the global variable is set to the value 0 by every one of the potentially 40 objs. Why? Do you mean that it's a turtle variable that is owned by obj?
Where you are updating the counter, you have suddenly switched the name from it_cnt to new_id_cnt. That won't update anything, there is no connection shown between the values of these two variables.

Netlogo: How to compute sum of items of lists within a list?

I would like to make the sum = the total of pollen recieved by a plant from other plants (Donnors) which is stored in a list of a list (own by each turtle = plant).
The following code make an error (when computing the sum):
OF expected input to be an agent or agentset but got the list
[[119.05593 50 50] [301.25853 50 50] [30.23906 50 50] [460.525845 50
50] [55.16717 50 50] [301.25853 50 50]] instead.
Does any one could help me about the mistake in the line "set Tot_pol sum ..." ?
Many thanks for your help.
to check-pol [m] ;; we check the pollen recieved by the two morphs
set Donnors [] ;; empty list of pollen donnors
ask zsps with [morph = m] ;; morph of the pollen reciever
[
set totpol 0
;; check for pollen donnors and morph for compatiblity within a radius :
ask zsps with[distance myself <= 20 and morph != m]
[
set totpol (NMaleFlowers * 100 * item round (distance myself) pollination-list) ;; the farther the less pollen
set Donnors lput [ (list totpol NMaleFlowers NFemFlowers)] of myself Donnors
]
set Tot_pol sum [ item (position 0 Donnors) Donnors ] of Donnors ;; total of pollen recieved
]
end
Luke's answer is good and should fix your problem. I suspect, however, that you are going to be doing lots of these types of sums. You may wish to set up a to-report that you can use for whichever item you want to sum over, just by passing the item number and the name of the list of lists. It would look like this:
to-report sum-item [#pos #listoflists ]
let items map [ x -> item #pos x ] #listoflists
report reduce [ [a b] -> a + b] items
end
The first line extracts the relevant item (remember index from 0) into a new list which the second line sums.
You would then use it with set Tot_pol sum-item 0 Donnors
Here's an answer that is not actually responding to your question. Instead, it is a more NetLogo-ish way of doing what I think you are trying to do with your code.
to check-pol [m]
ask zsps with [morph = m]
[ let senders zsps with [distance myself <= 20 and morph != m]
set totpol sum [NMaleFlowers * 100 * round (distance myself)] of senders
]
end
Your code gets into levels of ask that I think are unnecessary. What I think you are doing with your list is keeping track of the pollen donors. But an agentset is a cleaner approach and then you can simply pull out the information you want from the agentset using of.
Further, when you ask zsps with[distance myself <= 20 and morph != m] to set variable values in your code, then THOSE agents (not the receiving agent) are the ones having their variables changed. I think you are trying to take the perspective of the receiver of pollen, who looks around and received pollen from the other agents that are close enough. So the receiving agent should have the value changed.
This is not tested.
I'm not 100% sure what you're after here (you may want to look at the Minimum, Complete, and Verifiable Example guidelines), but if I'm reading you right you want the sum of the first item for each entry in the Donners list.
As to why your approach didn't work- NetLogo is telling you with that error that you've used of with a list, but of only works with agents or agentsets. Instead, you have to use a list processing approach. The simplest way might be to use sum in conjunction with map first in order to get what you need:
to sum-first-item
let example-list [ [ 1 2 3 ] [ 4 5 6 ] [ 7 8 9 ] ]
let sum-of-firsts sum map first example-list
print sum-of-firsts
end
To translate to Donnors, try:
set Tot_pol sum map first Donnors
That should work, but without reproducible a code example I can't check.

Applying Operations on each element of the list

I wish to divide each element in a list by a number, I have tried the following:
Approach 1:
set item 0 (new-vec item 0 vec / number)
set item 1 (new-vec item 1 vec / number)
gives error this isn't something you can use set on
Approach 2:
foreach new-vec
[ set ? ? / number]
doesn't seem to work.
Please help. Thanks in advance.
This is because NetLogo lists are immutable data structures.
If you really want mutability you can always use the array extension, but once you've learned to use NetLogo's immutable lists properly, this is almost never necessary: the lists primitives are usually all that you need.
To divide all the numbers in a list by some other number, use map:
let new-vec [10 50 100]
let number 10
let divided-vec map [ ? / number ] new-vec
will assign the list [1 5 10] to divided-vec.
The map operation builds a new list by applying an operation to each element of the list you pass to it. In the example above, I assigned the new list to a new variable (divided-vec), but if you wanted, you could also assign it back to new-vec:
set new-vec map [ ? / number ] new-vec
This will behave as if you modified new-vec in place, though it won't be the case.
If you want to apply an operation to just one item in a list, you can do it with a combination of replace-item and item:
let my-list [2 4 6 8 10]
show replace-item 1 my-list (item 1 my-list * 100)
will show: [2 400 6 8 10]
This is how to do it in NetLogo 6, which changed anonymous procedures and thus how this is done in map:
let new-vec [10 50 100]
let number 10
let divided-vec map [ i -> i / number ] new-vec