There is probably a very simple solution to this, but I am having trouble coming up with it since I'm still pretty new to netlogo. I'd be very grateful for any suggestions. My model has multiple breeds of turtles with different numbers of turtles in each breed set by sliders. To make it easier to set some breeds-own variables later in the model, I want to create separate sequential ID variables for each breed. These would basically be like who numbers, but would run from 0 to n for each breed. So, let's say I create male and female breeds like this:
breed [males male]
breed [females female]
to setup
clear-all
create-breeds
set-id
ask turtles [setxy random-xcor random-ycor ]
reset-ticks
end
to create-breeds
create-males number-males [set color yellow]
ask males [set shape "circle"]
create-females number-females [set color yellow]
ask females [set shape "circle 2"]
end
to set-id
...
end
I then want to run a "set-id" procedure that will create a male id var that will number the male turtles from 0 to male n, and another female id var that will number the female turtles from 0 to female n. I am assuming the solution should include some combination of foreach or n-values, but I'm having a lot of trouble nailing it down exactly. Thanks!
Don't do it!
I'm pretty sure it won't "make it easier to set some breeds-own variables later in the model". Using who numbers is error prone enough as it is without adding another separate index on top of it. (You shouldn't use who numbers either: there is almost always a better way to do things.) I'd suggest you ask another, separate, question and tell us why you think you need that and what you plan to do with it. I'm confident that someone will be able to suggest an alternative approach.
That being said...
You are right that a combination of foreach and n-values would do the trick.
Assuming you have:
males-own [ id ]
females-own [ id ]
You can use the following procedure:
to set-id-for [ breed-agents ]
(foreach (sort breed-agents) (n-values count breed-agents [?]) [
ask ?1 [ set id ?2 ]
])
end
By using parenthesis around foreach, you can pass it as many lists as you like: it will "zip" them together and give you variables like ?1, ?2, etc., to address elements of each list. In our case, the first list is the agents and the second list is indices generated with n-values.
Call the procedure once for each breed:
set-id-for males
set-id-for females
Supposing you have created 10 males and called set-id-for males, you can verify that it worked using the command center:
observer> show sort [id] of males
observer: [0 1 2 3 4 5 6 7 8 9]
But please...
...don't do it.
You can do it if you create a global variable and you use it inside of create male/female procedures:
globals [id]
breed [males male]
breed [females female]
males-own [id-male]
females-own [id-female]
to setup
clear-all
create-breeds
ask turtles [setxy random-xcor random-ycor ]
reset-ticks
end
to create-breeds
set id 0
create-males number-males
[
set id-male id
set color yellow
set shape "circle"
set id id + 1
]
set id 0
create-females number-females
[
set id-female id
set color yellow
set shape "circle 2"
set id id + 1
]
end
And you can include the "set shape" inside of create procedure.
Related
In Redis, let's say I have a set called animals.
127.0.0.1:6379> sadd animals cat:bob cat:fred dog:joe dog:rover hamster:harvey
I know I can use SRANDMEMBER to pull a random member from the set, which might be any of the values.
And I know I can get all cats out of the set with something like SSCAN animals 0 MATCH cat:*
But is there a way to retrieve a random cat?
Edit for clarity: My example has the important designator at start of string, but I'm looking for something that follows a general pattern where the "match" might be anywhere within the string.
Not in a single command. If you are using a Sorted Set, you can get ranges of values based on the lexical content:
> ZADD animals 0 cat:bob 0 cat:fred 0 dog:joe 0 dog:rover 0 hamster:harvey
> ZRANGESTORE cats animals [cat: (cau BYLEX
> ZRANDMEMBER cats
> DEL cats
Note that [cat: means "range staring with cat, inclusive" and (cau means "range ending with cau, exclusive". I picked "cau" because it would be next in the sequence and would only pick cats.
This is, admittedly, a bit of a hack. 😉
I'm trying to find an efficient method of outputting a large number of turtle variables (20+) from a random selection of 100 turtles into an output field or text file. So far I have:
turtles-own [
variable1
variable2
variable3
variable4
.
.
.
]
to go
if (ticks < 1) [reset-timer]
ticks
if count turtles >= end-population [
ask n-of 100 turtles [
output-show variable1
output-show variable2
output-show variable3
output-show variable4
]
I then get a list of the variables of each cell in a single column:
1
My question is how can I get these variable values on the same line so of the output or a text file so I can easily work with these data? Furthermore, how would I implement this in BehaviorSpace? Using this same command:
ask n-of 100 turtles [
output-show variable1
output-show variable2
output-show variable3
output-show variable4
]
... in the final commands field does not result in any of these data showing up in the output file.
Thanks!
There are a variety of ways to do this- for example, the csv extension is great candidate if you want to manually output your values. If you want to do this quickly in BehaviorSpace, here's how I usually go about it.
I'm assuming you want the variable values for the same 100 turtles each time, rather than sampling a new 100 turtles for each variable. So, I think the easiest way is to just make a globals variable for each of the variables of interest, then make a procedure to fill those lists as needed. For example, with this setup:
globals [ a-final b-final c-final ]
turtles-own [ a b c ]
to setup
ca
crt 100
reset-ticks
end
to go
ask turtles [
set a random 100
set b one-of [ "Beep" "Boop" ]
set c precision random-float 10 2
]
end
Each tick the turtles are just randomly updating their a, b, and c variables for the sake of this toy version. Then, you have a procedure that subsamples some number of turtles (here, 10) from your total population and updates the storage lists:
to output
let selected-turtles n-of 10 turtles
set a-final [a] of selected-turtles
set b-final [b] of selected-turtles
set c-final [c] of selected-turtles
end
Now as long as that output runs right before your BehaviorSpace experiment ends, you can output those lists as a string, which you can easily separate and clean with R or similar software. For example, if you have a setup like:
You will get output that looks something like:
In the interface tab i have a slider whose value ranges between 2 & 10. Depending on the value defined by the user using this slider, that many number of turtles should be created.
I tried using multiple if statements but there is a problem in the succeeding steps.
if (slider-value = 2) [create2]
if (slider-value = 3) [create3]
if (slider-value = 4) [create4]
if (slider-value = 5) [create5]
After creating the turtles using the above if conditions, i have to assign additional rules to each individual turtle like co-ordinate position, rules for how they should move etc. and i tried again using multiple if statements. But it doesn't seem to work.
for example the sub-query for create is as follows
to create2
create-challengers 2
ask turtle 0 [set color blue set label-color blue set size 2
set xcor party1-left-right ]
ask turtle 1 [set color red set label-color red set size 2
set xcor party2-left-right ]
ask turtles [ update-rule set old-mysize 0 set shape "default"]
end
for creating 3 turtles:
to create3
create-challengers 3
ask turtle 0 [set color blue set label-color blue set size 2
set xcor party1-left-right ]
ask turtle 1 [set color red set label-color red set size 2
set xcor party2-left-right ]
ask turtle 2 [set color green set label-color green set size 2
set xcor party3-left-right ]
ask turtles [ update-rule set old-mysize 0 set shape "default"]
end
so on and so forth.
The main problem is even though program works irrespective of how many turtles the user has defined, all the 10 gets created but only user defined number of turtles move, i.e. if the user has assined 3 then when i run the program 10 turtles are created but only 3 move.
Is there a way to get around like in other programming languages where one can simply use an if-else statement.
Can someone suggest a way, would really appreciate the help.
Thanks in advance!
After the turtles are created i assign certain rules for them to move:
to update-rule
if (slider-values = 2) [update2]
if (slider-values = 3) [update3]
if (slider-values = 4) [update4]
if (slider-values = 5) [update5]
end
And once again i create multiple sub-rule for update2, update3 which are basically for the each turtle depending on how many the user has defined:
If there are 2 turtles:
to update2
ask turtle 0 [set my-rule party1-rule]
ask turtle 1 [set my-rule party2-rule]
end
in case of 3 turtle:
to update3
ask turtle 0 [set my-rule party1-rule]
ask turtle 1 [set my-rule party2-rule]
ask turtle 2 [set my-rule party3-rule]
end
Below are the movement rules
to adapt
if (my-rule = "hunter") [hunt]
;;NB stickers do nothing
if (my-rule = "aggregator") [aggregate]
end
to hunt
ifelse (mysize > old-mysize) [jump 1] [set heading heading + 90 + random-float 180 jump 1]
set old-mysize mysize
end
to run-general
create2 create3 create4 create5 create-voters update-support
ask challengers [adapt] update-support
end
to go
run-general
tick
end
As noted by Seth, the problem is likely to be in the move part of the code since the turtles are being created. Just as general comments, it looks like your code for creating 3 turtles is identical to that for creating 2 turtles except for the additional turtle. If this is generally true, your code would be much easier if you used a format like:
to setup-challengers
create-challengers 1 [set color blue set label-color blue set size 2
set xcor party1-left-right ]
create-challengers 1 [set color red set label-color red set size 2
set xcor party2-left-right ]
if slider-value >= 3
[ create-challengers 1 [ set color green set label-color green set size 2
set xcor party3-left-right ] ]
if slider-value >= 4
[ create-challengers 1 [ <whatever you want number 4 to look like> ] ]
ask challengers [<do stuff>]
end
This way you only need the code for each turtle to be written once so if you change your mind about colours or something, it is much easier to change.
Okay, try editing your code to look like this:
to adapt
type "Hunters: " print count turtles with [my-rule = "hunter"]
type "Aggregators: " print count turtles with [my-rule = "aggregator"]
if (my-rule = "hunter") [hunt]
if (my-rule = "aggregator") [aggregate]
end
This is a standard debugging trick. It will print the number of hunters and aggregators to the Command Center (bottom of the interface tab). This allows you to work out where code is going wrong. For example, in your case, it will let you know if the problem is with the movement code or with the code that assigns rules to turtles.
Another trick is to have something like print "Got to hunt procedure" if you are not sure whether a procedure is even being reached.
this if-else thing for a slider based setup is very nasty looking.
an alternative is to have a set of (global) lists for all properties that are set seperately for each individual.
then you can use the following code
;assuming global_list1 and global_list2 exist
to setup
let index 0
create-turtles slidervalue [
set turtle_value1 item index global_list1
set turtle_value2 item index global_list2
set index index + 1
]
end
then you only need to make sure that each turtles will know what to do when asked to do something
Geerten
I have a data set that allows linking friends (i.e. observing peer groups) and thereby one can observe the characteristics of an individual's friends. What I have is an 8 digit identifier, id, each id's friend id's (up to 10 friends), and then many characteristic variables.
I want to take an individual and create a variables that are the foreign born status of each friend.
I already have an indicator for each person that is 1 if foreign born. Below is a small example, for just one friend. Notice, MF1 means male friend 1 and then MF1id is the id number for male friend 1. The respondents could list up to 5 male friends and 5 female friends.
So, I need Stata to look at MF1id and then match it down the id column, then look over to f_born for that matched id, and finally input the value of f_born there back up to the original id under MF1f_born.
edit: I did a poor job of explaining the data structure. I have a cross section so 1 observation per unique id. Row 1 is the first 8 digit id number with all the variables following over the row. The repeating id numbers are between the friend id's listed for each person (mf1id for example) and the id column. I hope that is a bit more clear.
Kevin Crow wrote vlookup that makes this sort of thing pretty easy:
use http://www.ats.ucla.edu/stat/stata/faq/dyads, clear
drop team y
rename (rater ratee) (id mf1_id)
bys id: gen f_born = mod(id,2)==1
net install vlookup
vlookup mf1_id, gen(mf1f_born) key(id) value(f_born)
So, Dimitriy's suggestion of vlookup is perfect except it will not work for me. After trying vlookup with both my data set, the UCLA data that Dimitriy used for his example, and a toy data set I created vlookup always failed at the point the program attempts to save a temp file to my temp folder. Below is the program for vlookup. Notice its sets tempfile file, manipulates the data, and then saves the file.
*! version 1.0.0 KHC 16oct2003
program define vlookup, sortpreserve
version 8.0
syntax varname, Generate(name) Key(varname) Value(varname)
qui {
tempvar g k
egen `k' = group(`key')
egen `g' = group(`key' `value')
local k = `k'[_N]
local g = `g'[_N]
if `k' != `g' {
di in red "`value' is unique within `key';"
di in red /*
*/ "there are multiple observations with different `value'" /*
*/ " within `key'."
exit 9
}
preserve
tempvar g _merge
tempfile file
sort `key'
by `key' : keep if _n == 1
keep `key' `value'
sort `key'
rename `key' `varlist'
rename `value' `generate'
save `file', replace
restore
sort `varlist'
joinby `varlist' using `file', unmatched(master) _merge(`_merge')
drop `_merge'
}
end
exit
For some reason, Stata gave me an error, "invalid file," at the save `file', replace point. I have a restricted data set with requirments to point all my Stata temp files to a very specific folder that has an erasure program sweeping it every so often. I don't know why this would create a problem but maybe it is, I really don't know. Regardless, I tweaked the vlookup program and it appears to do what I need now.
clear all
set more off
capture log close
input aid mf1aid fborn
1 2 1
2 1 1
3 5 0
4 2 0
5 1 0
6 4 0
7 6 1
8 2 .
9 1 0
10 8 1
end
program define justlinkit, sortpreserve
syntax varname, Generate(name) Key(varname) Value(name)
qui {
preserve
tempvar g _merge
sort `key'
by `key' : keep if _n ==1
keep `key' `value'
sort `key'
rename `key' `varlist'
rename `value' `generate'
save "Z:\Jonathan\created data sets\justlinkit program\fchara.dta",replace
restore
sort `varlist'
joinby `varlist' using "Z:\Jonathan\created data sets\justlinkit program\fchara.dta", unmatched(master) _merge(`_merge')
drop `_merge'
}
end
// set trace on
justlinkit mf1aid, gen(mf1_fborn) key(aid) value(fborn)
sort aid
list
Well, this fixed my problem. Thanks to all who responded I would not have figured this out without you.
I want to give income attribute to agent which is based on patch value where the agent stays and slider parametre.
to setup
if pcolor = yellow
[sprout-resident 1
[set color sky
set shape "default"
set size 1
set-income
ask patch-here [set pcolor brown
set landuse "resident"
set is-bought? TRUE
set owner [who] of myself]]]
end
to set-income
ifelse land-price > buycapabilityhigh(this is the slider parametr) [set income "high"]
[ifelse land-price < buycapabilitymiddlle and land-price > buycapabilitylow [set income "middle"]
[if land-price < buycapabilitylow [set income "low"]]]
end
so I want to give agent category high middle low income based on land price where the agent stays and based on buycapability which is set by slider. Please help giving advice to code this kind of mechanism. Thanks
Is the variable land-price a patch's attributes ?
If it is, then I think the problems is in your set-income function.
You should use [land-price] of patch-here instead of just land-price in the if-statement.
Moreover, just like Alan said. you could just use a sequence of if statements.
it goes like this
if [land-price] of patch-here > ... [...]
if [land-price] of patch-here < ... and ... [...]
if [land-price] of patch-here < ... [...]