Let's take a look at representing a network in R using the network object from the Statnet package. To get the Statnet package, see R Toolkit.

We'll construct a 4 level network – a root, some departments, some people in each department and some grants of each of the people. We'll add attributes to these objects and display the results.

None of this uses VIVO. Here we are just getting comfortable with data representation. We'll use "real" data in subsequent examples.

A One Node Network

We need to start somewhere. Let's create a new network called "net" with a single node or vertex.

 #
 # Learning to use network and network plotting functions for VIVO data
 #
 # M. Conlon April 11, 2011
 #
 # 
 # start with a root node
 net <-network.initialize(1,directed=F)
 net %v% "type" <- "Root"
 net %v% "vertex.names" <- "COM"
 net %v% "amt" <-0

That's all you need to create a single node network with some attributes. The network has one node with name "COM" (that's short for "College of Medicine" at UF). The %v% lines set various attribute lists to singleton values. Here I've started a "type" attribute to differentiate the types of things that will be in this network – Departments, people, grants, and a single root vertex. The amt attribute will hold dollar amounts for grants and totals for grants at other levels in the network.

Adding Departments to the Network

Next, let's create three departments. Two lines of code are needed for each department. First, add a vertex to the network. Note that that the same attributes are being set for each vertex – type,vertex.names and amt. Second, the vertex is linked to the root by asserting an edge connecting the department to the root.

 #
 # create some departments
 #
 add.vertices(net,1,list(list(type="Department",vertex.names="Radiology",amt=0)))
 net["COM","Radiology"]<-1
 add.vertices(net,1,list(list(type="Department",vertex.names="Pathology",amt=0)))
 net["COM","Pathology"]<-1
 add.vertices(net,1,list(list(type="Department",vertex.names="Pediatrics",amt=0)))
 net["COM","Pediatrics"]<-1

Edge assertions are simple matrix element assignments in an edge matrix with the same name as the network object. This is all provided by the statnet package. From and to are specified by vertex names. The value "1" indicates an edge between the vertices.

There is much more that can be done with edges and edge attributes. We are keeping things simple here.

Adding People to the Departments

Let's add people to each of the departments. We use the same method as previously – create a vertex for each person and connect it to the department vertex.

 #
 # create some people in the departments
 #
 add.vertices(net,1,list(list(type="Person",vertex.names="Mancuso",amt=0)))
 net["Radiology","Mancuso"]<-1
 add.vertices(net,1,list(list(type="Person",vertex.names="Sistrom",amt=0)))
 net["Radiology","Sistrom"]<-1 
 add.vertices(net,1,list(list(type="Person",vertex.names="Rathe",amt=0)))
 net["Radiology","Rathe"]<-1 

There. We have added three people to the Radiology Department.

In the code below, we first add 15 people to Pathology and 30 people to Pediatrics. We use an R loop to repetitively add the vertices and edges. We generate a "name" for each person using the R paste function. The people in Pathology will be named P1, P2, ... P15. The people in Pediatrics will be named M1, M2, ... M30.

Experienced R programmers will ask "Do we need loops? Why not add all the Pediatric vertices at once and then all the Pediatric edges at once?" And the answer is "Of course." We have simplified the code for the presentation here. R programmers would figure out how to add 15 Pediatric people in two lines – one for vertices and one for edges.

 for (i in 1:15) {
   name <- paste("P",i,sep="")
   add.vertices(net,1,list(list(type="Person",vertex.names=name,amt=0)))
   net["Pathology",name]<-1
 }
 for (i in 1:30) {
   name <- paste("M",i,sep="")
   add.vertices(net,1,list(list(type="Person",vertex.names=name,amt=0)))
   net["Pediatrics",name]<-1
 }

Adding Grants for each person

Finally, we wish to add grant vertices and an edge connecting the grant vertex to a corresponding person. Each grant will have a name (again automatically generated) and an award amount. In the example, the award amount is stored in the attribute "amt". We generate award amounts as a random number.

We have a bit of a conundrum. In our previous work, we explicitly added code for for each department and then for each department, we wrote code to add people to the department. It's not feasible to write code for each person on the network to add their grants. Even in the simple work we are presenting here, we now have 48 people in the network. How do we proceed?

The code sample below begins by creating three vectors of the attributes of the nodes creates so far – vt stores types, vn stores names and va stores amounts (all zero so far, we have't added any grants yet).

The rest of the code is two nested loops. The outer loop scans the entire network looking for Person nodes. When a Person nodes is found, a number of grants (ng) is generated as a random from 0 to 9 using the R runif function.

Then an inner loop processes each grant:

  • A grant name is generated
  • A grant amount is generated using the R function rexp.
  • And then the grant is added to the network just as the previous nodes were added – a call to call.vertices followed by adding an edge connecting the grant to the person.

Following the addition of the grant to the network, three short sequences of code update the amt total for the corresponding person, department and root nodes. The amounts are retrieved, the corresponding amt is added and the amounts are put back in the network object.

Again, an experienced R programmer could remove steps. The code shown here is designed for clarity, not conciseness nor speed.

 #
 # Add grants as another level
 #
 vt<-get.vertex.attribute(net,"type")
 vn<-get.vertex.attribute(net,"vertex.names")
 va<-get.vertex.attribute(net,"amt")

 for (i in 1:network.size(net)) {
   if (vt[i] == "Person") {
     di<-get.neighborhood(net,i)[1]  # get department index for this person
     ng <- floor(10*runif(1))   
     if (ng > 0) {
       for (j in 1:ng) {
         gname <- paste(vn[i],".G",j,sep="")
         gamt=floor(50000*rexp(1)*rexp(1))
         add.vertices(net,1,list(list(type="Grant",vertex.names=gname,amt=gamt)))
         net[vn[i],gname]<-1
 #
 # Add the grant amounts to the corresponding person grant total
 #
         va<-get.vertex.attribute(net,"amt")
         va[i]<-va[i]+gamt
         set.vertex.attribute(net,"amt",va)
 #
 # Add the grant amounts to the corresponding department total
 #
         va<-get.vertex.attribute(net,"amt")
         va[di]<-va[di]+gamt
         set.vertex.attribute(net,"amt",va)
 #
 # Add the grant amount to the root total
 #
         va<-get.vertex.attribute(net,"amt")
         va[1]<-va[1]+gamt
         set.vertex.attribute(net,"amt",va)
       }
     }
   }
 } 

Whew. We not only added grants to each person, we created grant totals for persons, departments and the root (the collection of all departments). These grant totals represent the total number of dollars awarded to the person, to the persons in a department and to all the persons in all the departments. These totals will be very valuable in making displays and reports from the data.

Displaying the results

Now we can display the network using the built-in features of R and the statnet package. A plot can be generated with a single statement:

 plot(net)

The result is shown below:

Default network visualization

All the nodes are the same color. Perhaps we'd like to see the grants colored differently from the people and so on. This is easily done. The plot() function can use vertex attributes to control display. For example:

 plot(net,vertex.col="type")

The result is shown below:

Vertices colored by type. Departments are black. The root is blue

Finally, the code below assigns colors to vertices using the R palette functions (a rainbow palette). The plot displays the size of each node based on the value of the vertex attribute amt. So the root node will be biggest. A formula is used to scale the node sizes based on the log of grant dollars – so 1 million dollars has size "6", a one thousand dollar grant has size "3", and so on.

 #
 #  generate a plot of departments, people and grants
 #

 palette(rev(rainbow(6)))
 plot(net,vertex.col="type",
   vertex.cex=0.25*(1+floor(log10(1+get.vertex.attribute(net,"amt")))))

The result is shown below:

Vertices by Type and Amt. Larger vertices represent more grant dollars. Note some very small "people" vertices – these have no associated grants and therefore no grant dollars.

R and statnet provide many more options for displaying graphs and networks. If you are not familiar with R, you will want to review the help system regarding the plot function and the par (graphical parameters) function. It is straightforward to display labels, control the presentation of edges, use different shapes for vertices and much more.

Summary

The code provided here is for idea generation. What attributes would be good to show on such a plot? What other plots can be made? How would we display publications? Or multi-level organizational structure?

In subsequent work, we will use live VIVO data rather than simulated data in the examples here.