-
Notifications
You must be signed in to change notification settings - Fork 3
Comprehensive example
In this tutorial we will work with another NetLogo sample model, AIDS. It simulates the spread of HIV in a population. We are going to extract and analyze three graphs from this model.
-
Couple graph. The nodes of this graph are the people in our population. An edge appears between two individuals when they are in couple and disappears when they break up. We will display this graph in a viewer. The positions and the colors of the nodes will be the same as in the NetLogo simulation.
-
Infection graph. This is a "who infected who" graph. At the beginning it will contain only several isolated nodes, the initially infected individuals. When someone is infected, we will add a new node in the graph together with an arc from the person who infected him. We will display this graph with automatic layout. The initial infection sources will be colored in red and the remaining nodes in black.
-
Cumulative graph. This one is like the couple graph, but edges do not disappear when people break up. We will color the nodes of this graph as in the NetLogo simulation, but we will use an automatic layout. This graph is very important and we will come back to it in the second part of this tutorial.
We will use three different senders, one for each graph. In the following procedure we clear all previously created senders, create our three senders, send 'graph cleared' events using each of them and setup style sheets for each graph.
to setup-senders
gs:clear-senders
(foreach (list "couple" "infection" "cumulative") (list 2001 2002 2003) [
gs:add-sender ?1 "localhost" ?2
gs:clear ?1
gs:add-attribute ?1 "ui.title" word ?1 " graph"
gs:add-attribute ?1 "ui.antialias" true
gs:add-attribute ?1 "ui.stylesheet" "node {size: 8px;} edge {fill-color: grey;}"
])
end
We will call this procedure at the beginning of setup
to setup
setup-senders
clear-all
...
end
Now let us take care of the nodes of our graphs. People are created in a procedure called setup-people
. As you already guess, we have to make them send 'node added' events just after their creation:
to setup-people
crt initial-people [
gs:add "couple"
gs:add "cumulative"
...
set infected? (who < initial-people * 0.025)
if infected? [
gs:add "infection"
set infection-length random-float symptoms-show
]
...
]
end
Note that we add all the people to the couple graph and to the cumulative graph, but only the initially infected people to the infection graph. We will add other nodes to the last graph dynamically, when new people are infected. To do this, we have to slightly modify the infect
procedure:
to infect
if coupled? and infected? and not known? and [not infected?] of partner [
if random-float 11 > condom-use or random-float 11 > ([condom-use] of partner) [
if random-float 100 < infection-chance [
ask partner [
set infected? true
gs:add "infection"
]
]
]
]
end
Now the nodes are added correctly to the three graphs, but we also have to send some of their attributes. To color them, we will use the "ui.style"
node attribute. Moreover, we need to send the coordinates of the people to the couple graph because we want its vertices to have the same positions as in the NetLogo simulation. We revisit the setup-people
procedure and change it as follows:
to setup-people
crt initial-people [
gs:add "couple"
gs:add "cumulative"
setxy random-xcor random-ycor
gs:add-attribute "couple" "xy" list xcor ycor
...
set infected? (who < initial-people * 0.025)
if infected? [
gs:add "infection"
gs:add-attribute "infection" "ui.style" "fill-color: red;"
set infection-length random-float symptoms-show
]
...
]
end
The colors are assigned in the procedure assign-color
which is called on each step. We change it as follows:
to assign-color
ifelse not infected? [
set color green
gs:add-attribute "couple" "ui.style" "fill-color: green;"
gs:add-attribute "cumulative" "ui.style" "fill-color: green;"
][
ifelse known? [
set color red
gs:add-attribute "couple" "ui.style" "fill-color: red;"
gs:add-attribute "cumulative" "ui.style" "fill-color: red;"
][
set color blue
gs:add-attribute "couple" "ui.style" "fill-color:blue;"
gs:add-attribute "cumulative" "ui.style" "fill-color: blue;"
]
]
end
There is one more thing that we have to add in the procedure move
to update the node positions in the couple graph:
to move
rt random-float 360
fd 1
gs:add-attribute "couple" "xy" list xcor ycor
end
Now the nodes and their attributes are correctly sent to the external application, but what about the edges of our graphs? Unlike our introduction example, this model does not use links. The trick is to create them temporarily just to make them send 'edge added' events and kill them as soon. People decide to couple in the couple
procedure which will be modified as follows:
to couple
let potential-partner one-of (turtles-at -1 0)
with [not coupled? and shape = "person lefty"]
if potential-partner != nobody [
if random-float 10.0 < [coupling-tendency] of potential-partner [
set partner potential-partner
create-link-with partner [
gs:add "couple"
gs:add "cumulative"
die
]
...
]
]
end
When a couple breaks up (this happens in the uncouple
procedure) we have to remove the edge from the couple graph, but not from the cumulative graph:
to uncouple ;; turtle procedure
if coupled? and (shape = "person righty") [
if (couple-length > commitment) or ([couple-length] of partner) > ([commitment] of partner) [
create-link-with partner [
gs:remove "couple"
die
]
...
]
]
end
And finally, when we add a node to the infection graph, we have to add it together with the arc from the infecting to the infected person:
to infect
if coupled? and infected? and not known? and [not infected?] of partner [
if random-float 11 > condom-use or random-float 11 > ([condom-use] of partner) [
if random-float 100 < infection-chance [
ask partner [
set infected? true
gs:add "infection"
]
create-link-to partner [
gs:add "infection"
die
]
]
]
]
end
In our introduction example we explained how to display the graph produced by a NetLogo model. We used a NetStream receiver, a graph and a viewer. Actually, the middle element of our chain, the graph, was not necessary. The viewer maintains an internal graph and can receive events directly from NetLogo. Moreover, it runs in the swing thread an pumps the proxy pipe when it is executed. If we only want to display a graph produced by Netlogo, we can do it more efficiently using the following class:
public class SimpleNetStreamViewer extends Viewer {
public SimpleNetStreamViewer(NetStreamReceiver receiver, boolean autoLayout) {
super(receiver.getDefaultStream());
addDefaultView(true);
if (autoLayout)
enableAutoLayout();
}
}
To start the viewers, we have just to instantiate objects of this type:
public static void main(String[] args) {
// couple graph viewer
new SimpleNetStreamViewer(new NetStreamReceiver(2001), false);
// infection graph viewer
new SimpleNetStreamViewer(new NetStreamReceiver(2002), true);
}
What about the viewer of the cumulative graph? The things are not as simple for it.