Upload the libraries required.

DATA PREPARATION

Dataset 1: Edgelist

The first graph is represented as two sets, V and E, for vertices and edges, respectively.

edges <- read.csv("Dataset1-Media-Example-EDGES.csv", header=T, as.is=T) 
nodes <- read.csv("Dataset1-Media-Example-NODES.csv", header=T, as.is=T)
head(nodes); head(edges)
##    id               media media.type type.label audience.size
## 1 s01            NY Times          1  Newspaper            20
## 2 s02     Washington Post          1  Newspaper            25
## 3 s03 Wall Street Journal          1  Newspaper            30
## 4 s04           USA Today          1  Newspaper            32
## 5 s05            LA Times          1  Newspaper            20
## 6 s06       New York Post          1  Newspaper            50
##   from  to weight      type
## 1  s01 s02     10 hyperlink
## 2  s01 s02     12 hyperlink
## 3  s01 s03     22 hyperlink
## 4  s01 s04     21 hyperlink
## 5  s04 s11     22   mention
## 6  s05 s15     21   mention
nrow(nodes); length(unique(nodes$id))
## [1] 17
## [1] 17
nrow(edges); nrow(unique(edges[,c("from", "to")]))
## [1] 52
## [1] 49

Note that there are a greater number of edges than there are of unique edges, which means there are edges that which have identical endpoints. We can collapse or aggregate such edges into a single edge by summing their given weights. We use the aggregate() function.

edges <- aggregate(edges[,3], edges[,-3], sum)
edges <- edges[order(edges$from, edges$to),]
colnames(edges)[4] <- "weight"
rownames(edges) <- NULL

Dataset 2: Matrix

The second graph is represented different from the graph derived from Dataset 1.

nodes2 <- read.csv("Dataset2-Media-User-Example-NODES.csv", header=T, as.is=T)
edges2 <- read.csv("Dataset2-Media-User-Example-EDGES.csv", header=T, row.names=1)
head(nodes2)
##    id   media media.type media.name audience.size
## 1 s01     NYT          1  Newspaper            20
## 2 s02    WaPo          1  Newspaper            25
## 3 s03     WSJ          1  Newspaper            30
## 4 s04    USAT          1  Newspaper            32
## 5 s05 LATimes          1  Newspaper            20
## 6 s06     CNN          2         TV            56
head(edges2)
##     U01 U02 U03 U04 U05 U06 U07 U08 U09 U10 U11 U12 U13 U14 U15 U16 U17
## s01   1   1   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0
## s02   0   0   0   1   1   0   0   0   0   0   0   0   0   0   0   0   0
## s03   0   0   0   0   0   1   1   1   1   0   0   0   0   0   0   0   0
## s04   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0   0   0
## s05   0   0   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0
## s06   0   0   0   0   0   0   0   0   0   0   0   0   1   1   0   0   1
##     U18 U19 U20
## s01   0   0   0
## s02   0   0   1
## s03   0   0   0
## s04   0   0   0
## s05   0   0   0
## s06   0   0   0

edges2 represents a two-mode network, which means that the G is a bipartite graph where every edge connects a node from the column header row to a node from the row name column.

edges2 <- as.matrix(edges2)
dim(edges2)
## [1] 10 20
dim(nodes2)
## [1] 30  5

VISUALIZATION: igraph

The graph.data.frame function in the igraph packaage creates network objects. The function takes two data frames, the first d, which describes the edges of the network via two leading columns identifying the source and target node for each edge and all subsequent columns holding attribute data (e.g., weight, label, cost, etc.); and the second vertices, which consists of a leading column of node IDs and additional attribute columns as needed.

net <- graph.data.frame(edges, nodes, directed=T)
net
## IGRAPH DNW- 17 49 -- 
## + attr: name (v/c), media (v/c), media.type (v/n), type.label
## | (v/c), audience.size (v/n), type (e/c), weight (e/n)
## + edges (vertex names):
##  [1] s01->s02 s01->s03 s01->s04 s01->s15 s02->s01 s02->s03 s02->s09
##  [8] s02->s10 s03->s01 s03->s04 s03->s05 s03->s08 s03->s10 s03->s11
## [15] s03->s12 s04->s03 s04->s06 s04->s11 s04->s12 s04->s17 s05->s01
## [22] s05->s02 s05->s09 s05->s15 s06->s06 s06->s16 s06->s17 s07->s03
## [29] s07->s08 s07->s10 s07->s14 s08->s03 s08->s07 s08->s09 s09->s10
## [36] s10->s03 s12->s06 s12->s13 s12->s14 s13->s12 s13->s17 s14->s11
## [43] s14->s13 s15->s01 s15->s04 s15->s06 s16->s06 s16->s17 s17->s04

We can access nodes, edges, and attributes as follows.

E(net); V(net)
## + 49/49 edges (vertex names):
##  [1] s01->s02 s01->s03 s01->s04 s01->s15 s02->s01 s02->s03 s02->s09
##  [8] s02->s10 s03->s01 s03->s04 s03->s05 s03->s08 s03->s10 s03->s11
## [15] s03->s12 s04->s03 s04->s06 s04->s11 s04->s12 s04->s17 s05->s01
## [22] s05->s02 s05->s09 s05->s15 s06->s06 s06->s16 s06->s17 s07->s03
## [29] s07->s08 s07->s10 s07->s14 s08->s03 s08->s07 s08->s09 s09->s10
## [36] s10->s03 s12->s06 s12->s13 s12->s14 s13->s12 s13->s17 s14->s11
## [43] s14->s13 s15->s01 s15->s04 s15->s06 s16->s06 s16->s17 s17->s04
## + 17/17 vertices, named:
##  [1] s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 s13 s14 s15 s16 s17
E(net)$type; V(net)$media
##  [1] "hyperlink" "hyperlink" "hyperlink" "mention"   "hyperlink"
##  [6] "hyperlink" "hyperlink" "hyperlink" "hyperlink" "hyperlink"
## [11] "hyperlink" "hyperlink" "mention"   "hyperlink" "hyperlink"
## [16] "hyperlink" "mention"   "mention"   "hyperlink" "mention"  
## [21] "mention"   "hyperlink" "hyperlink" "mention"   "hyperlink"
## [26] "hyperlink" "mention"   "mention"   "mention"   "hyperlink"
## [31] "mention"   "hyperlink" "mention"   "mention"   "mention"  
## [36] "hyperlink" "mention"   "hyperlink" "mention"   "hyperlink"
## [41] "mention"   "mention"   "mention"   "hyperlink" "hyperlink"
## [46] "hyperlink" "hyperlink" "mention"   "hyperlink"
##  [1] "NY Times"            "Washington Post"     "Wall Street Journal"
##  [4] "USA Today"           "LA Times"            "New York Post"      
##  [7] "CNN"                 "MSNBC"               "FOX News"           
## [10] "ABC"                 "BBC"                 "Yahoo News"         
## [13] "Google News"         "Reuters.com"         "NYTimes.com"        
## [16] "WashingtonPost.com"  "AOL.com"

We try the simple plot function.

plot(net)

We can improve the interpretability of the visualization by removing loops (edges that start and end at the same node), reducing the sie of the arrowheads, and removing the labels (just from the visualization, not the underlying network object).

net <- simplify(net, remove.multiple = F, remove.loops = T)
plot(net, edge.arrow.size=.4, vertex.label=NA)

There are many ways to edit the parameters of the plot.

plot(net, edge.arrow.size=.4, edge.curved=.1)

plot(net, edge.arrow.size=.2, edge.color="orange", vertex.color="orange", vertex.frame.color="#ffffff", vertex.label=V(net)$media, vertex.label.color="black")

We can also reset parameters for particular vertices or edges based on their attributes.

# Different colors based on media type
colrs <- c("gray50", "tomato", "gold")
V(net)$color <- colrs[V(net)$media.type]
# Set node sizes according to their degrees = # of edges incident
deg <- igraph::degree(net, mode="all")
V(net)$size <- deg*3
# Alternatively, use audience size
V(net)$size <- V(net)$audience.size*0.6
# Change edge width based on weight parameter
E(net)$width <- E(net)$weight/6
# Node labels are IDs.  Change to null (blank)
V(net)$label <- NA
# Change arrow size & edge color and add legend
E(net)$arrow.size <- .2
E(net)$edge.color <- "gray80"
E(net)$width <- 1 + E(net)$weight/12
plot(net)
legend(x=-1.5, y=-1.1, c("Newspaper","TV","Online News"), pch=21,col="#777777",pt.bg=colrs,pt.cex=2, cex=.8,bty="n",ncol=1)

NETWORK LAYOUTS

We next explore how R enables associating coordinates to each node in a network object. We use a the Barabasi-Albert model, a simple stochastic graph-building algorithm.

bamnet <- barabasi.game(80)
V(bamnet)$frame.color <- "white"
V(bamnet)$color <- "orange"
V(bamnet)$size <- 10
E(bamnet)$arrow.mode <- 0
plot(bamnet)

summary(bamnet)
## IGRAPH D--- 80 79 -- Barabasi graph
## + attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n),
## | algorithm (g/c), frame.color (v/c), color (v/c), size (v/n),
## | arrow.mode (e/n)

The network consists of 80 nodes and 79 undirected edges. We can rearrange the layout of the nodes.

# Random layout
plot(bamnet, layout=layout.random)

# Instead of setting the layout (e.g., "random") in the plot() function we can define the layout we want in advance and store that layout in a variable.  The variable would then be an argument in the plot() funtion when called.
l <- layout.circle(bamnet)
plot(bamnet, layout=l)

We explore how the layout is represented.

l
##                [,1]          [,2]
##  [1,]  1.000000e+00  0.000000e+00
##  [2,]  9.969173e-01  7.845910e-02
##  [3,]  9.876883e-01  1.564345e-01
##  [4,]  9.723699e-01  2.334454e-01
##  [5,]  9.510565e-01  3.090170e-01
##  [6,]  9.238795e-01  3.826834e-01
##  [7,]  8.910065e-01  4.539905e-01
##  [8,]  8.526402e-01  5.224986e-01
##  [9,]  8.090170e-01  5.877853e-01
## [10,]  7.604060e-01  6.494480e-01
## [11,]  7.071068e-01  7.071068e-01
## [12,]  6.494480e-01  7.604060e-01
## [13,]  5.877853e-01  8.090170e-01
## [14,]  5.224986e-01  8.526402e-01
## [15,]  4.539905e-01  8.910065e-01
## [16,]  3.826834e-01  9.238795e-01
## [17,]  3.090170e-01  9.510565e-01
## [18,]  2.334454e-01  9.723699e-01
## [19,]  1.564345e-01  9.876883e-01
## [20,]  7.845910e-02  9.969173e-01
## [21,]  6.123032e-17  1.000000e+00
## [22,] -7.845910e-02  9.969173e-01
## [23,] -1.564345e-01  9.876883e-01
## [24,] -2.334454e-01  9.723699e-01
## [25,] -3.090170e-01  9.510565e-01
## [26,] -3.826834e-01  9.238795e-01
## [27,] -4.539905e-01  8.910065e-01
## [28,] -5.224986e-01  8.526402e-01
## [29,] -5.877853e-01  8.090170e-01
## [30,] -6.494480e-01  7.604060e-01
## [31,] -7.071068e-01  7.071068e-01
## [32,] -7.604060e-01  6.494480e-01
## [33,] -8.090170e-01  5.877853e-01
## [34,] -8.526402e-01  5.224986e-01
## [35,] -8.910065e-01  4.539905e-01
## [36,] -9.238795e-01  3.826834e-01
## [37,] -9.510565e-01  3.090170e-01
## [38,] -9.723699e-01  2.334454e-01
## [39,] -9.876883e-01  1.564345e-01
## [40,] -9.969173e-01  7.845910e-02
## [41,] -1.000000e+00  1.224606e-16
## [42,] -9.969173e-01 -7.845910e-02
## [43,] -9.876883e-01 -1.564345e-01
## [44,] -9.723699e-01 -2.334454e-01
## [45,] -9.510565e-01 -3.090170e-01
## [46,] -9.238795e-01 -3.826834e-01
## [47,] -8.910065e-01 -4.539905e-01
## [48,] -8.526402e-01 -5.224986e-01
## [49,] -8.090170e-01 -5.877853e-01
## [50,] -7.604060e-01 -6.494480e-01
## [51,] -7.071068e-01 -7.071068e-01
## [52,] -6.494480e-01 -7.604060e-01
## [53,] -5.877853e-01 -8.090170e-01
## [54,] -5.224986e-01 -8.526402e-01
## [55,] -4.539905e-01 -8.910065e-01
## [56,] -3.826834e-01 -9.238795e-01
## [57,] -3.090170e-01 -9.510565e-01
## [58,] -2.334454e-01 -9.723699e-01
## [59,] -1.564345e-01 -9.876883e-01
## [60,] -7.845910e-02 -9.969173e-01
## [61,] -1.836910e-16 -1.000000e+00
## [62,]  7.845910e-02 -9.969173e-01
## [63,]  1.564345e-01 -9.876883e-01
## [64,]  2.334454e-01 -9.723699e-01
## [65,]  3.090170e-01 -9.510565e-01
## [66,]  3.826834e-01 -9.238795e-01
## [67,]  4.539905e-01 -8.910065e-01
## [68,]  5.224986e-01 -8.526402e-01
## [69,]  5.877853e-01 -8.090170e-01
## [70,]  6.494480e-01 -7.604060e-01
## [71,]  7.071068e-01 -7.071068e-01
## [72,]  7.604060e-01 -6.494480e-01
## [73,]  8.090170e-01 -5.877853e-01
## [74,]  8.526402e-01 -5.224986e-01
## [75,]  8.910065e-01 -4.539905e-01
## [76,]  9.238795e-01 -3.826834e-01
## [77,]  9.510565e-01 -3.090170e-01
## [78,]  9.723699e-01 -2.334454e-01
## [79,]  9.876883e-01 -1.564345e-01
## [80,]  9.969173e-01 -7.845910e-02

A layout is evidently nothing more than a matrix of size N x 2 where each row records the x,y coordinates of the node. We can generate plots with layouts that we can generate manually, e.g., a list of latitude and longitude pairs.

We explore a couple layouts defined within the igraph package. Note that random and circle used above, is an example.

# 3D sphere layout (which is a list of (x,y,z) coordinates)
l <- layout.sphere(bamnet)
plot(bamnet, layout=l)

# Force-directed layouts.  Such layouts simulate a physical system where the nodes are charged particles that repulse each other and edges act as springs such that the heavier the weight of the edge, the closer the two incident edges.  A commonly used for-directed layout algorithm is Fruchterman-Reingold.
l <- layout.fruchterman.reingold(bamnet)
par(mfrow=c(1,2), mar=c(0,0,0,0))
plot(bamnet, layout=layout.fruchterman.reingold)
plot(bamnet, layout=l)

# Notice that repeated use of Fructerman-Reingold yields different layouts.  Saving the layout in a variable before plotting the network negates this behavior.

By default, the coordinates of layouts are rescaled so that each coordinate fits within the interval [-1,1]. We can override this as follows.

par(mfrow=c(1,2), mar=c(0,0,0,0))
plot(bamnet, layout=l)
l <- layout.norm(l, ymin=-.7, ymax=.7, xmin=-.7, xmax=.7)
plot(bamnet, rescale=F, layout=l)

We look at all available layouts defined within igraph.

layouts <- grep("^layout\\.", ls("package:igraph"), value=TRUE)
# Remove layouts inapplicable to our particular graph
layouts <- layouts[!grepl("bipartite|merge|norm|sugiyama", layouts)]
par(mfrow=c(3,3))
for(layout in layouts) {
  print(layout)
  l <- do.call(layout, list(net))
  plot(net, edge.arrow.mode=0, layout=l, main=layout) }
## [1] "layout.auto"
## [1] "layout.circle"
## [1] "layout.davidson.harel"
## [1] "layout.drl"
## [1] "layout.fruchterman.reingold"
## [1] "layout.fruchterman.reingold.grid"
## Warning in layout.fruchterman.reingold.grid(structure(list(17, TRUE, c(0, : Grid Fruchterman-Reingold layout was removed,
## we use Fruchterman-Reingold instead.
## [1] "layout.gem"
## [1] "layout.graphopt"
## [1] "layout.grid"
## [1] "layout.grid.3d"
## Warning: layout.grid.3d is deprecated from
## igraph 0.8.0, please use layout_on_grid instead

## [1] "layout.kamada.kawai"
## [1] "layout.lgl"
## [1] "layout.mds"
## [1] "layout.random"
## [1] "layout.reingold.tilford"
## Warning in .Call("R_igraph_layout_reingold_tilford", graph, root, mode, :
## At structural_properties.c:3297 :graph contains a cycle, partial result is
## returned
## [1] "layout.sphere"
## [1] "layout.spring"
## Warning in layout.spring(structure(list(17, TRUE, c(0, 0, 0, 0, 1, 1, 1, :
## Spring layout was removed, we use Fruchterman-Reingold instead.
## [1] "layout.star"
## [1] "layout.svd"
## Warning in layout.svd(structure(list(17, TRUE, c(0, 0, 0, 0, 1, 1, 1, 1, :
## SVD layout was removed, we use Fruchterman-Reingold instead.

HIGHLIGHTING NETWORK ASPECTS

plot(net)

The plot for the net network object might be helpful if it were “sparsified,” i.e., if relatively unimportant links between nodes were discarded.

hist(edges$weight)

mean(edges$weight)
## [1] 12.40816
sd(edges$weight)
## [1] 9.905635

One can specify a threshold weight such that all edges with weight values less than the given value are discarded. Here, we discard edges with weights less than the mean for the network. Use the delete.edges() function from the igraph package to delete edges.

threshold <- mean(edges$weight)
net_sparse <- igraph::delete.edges(net, E(net)[weight<threshold])
l <- layout.fruchterman.reingold(net_sparse, repulserad=vcount(net)^2.1)
## Warning in layout_with_fr(structure(list(17, TRUE, c(0, 0, 0, 0, 1, 1, 2, :
## Argument `repulserad' is deprecated and has no effect
plot(net_sparse, layout=l)

Recall that each edge has a type attribute of either “hyperlink” or “mention.” We can plot the network according to the type of connection as follows.

E(net)$width <- 1.5
plot(net, edge.color=c("dark red", "slategrey")[(E(net)$type=="hyperlink")+1], vertex.color="gray40", layout=layout.circle)

net.m <- net - E(net)[E(net)$type=="mention"]
net.h <- net - E(net)[E(net)$type=="hyperlink"]
par(mfrow=c(1,2))
plot(net.h, vertex.color="orange", main="Hyperlink")
plot(net.m, vertex.color="blue", main="Mention")

ALTERNATIVE REPRESENTATION OF NETWORKS

Heatmap of Network Matrix

netmat <- get.adjacency(net, attr="weight", sparse=F)
colnames(netmat) <- V(net)$media
rownames(netmat) <- V(net)$media
palf <- colorRampPalette(c("gold","dark orange"))
heatmap(netmat[,17:1], Rowv = NA, Colv = NA, col = palf(100), scale="none", margins=c(10,10))

PLOTTING BIMODAL NETWORKS

head(nodes2)
##    id   media media.type media.name audience.size
## 1 s01     NYT          1  Newspaper            20
## 2 s02    WaPo          1  Newspaper            25
## 3 s03     WSJ          1  Newspaper            30
## 4 s04    USAT          1  Newspaper            32
## 5 s05 LATimes          1  Newspaper            20
## 6 s06     CNN          2         TV            56
head(edges2)
##     U01 U02 U03 U04 U05 U06 U07 U08 U09 U10 U11 U12 U13 U14 U15 U16 U17
## s01   1   1   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0
## s02   0   0   0   1   1   0   0   0   0   0   0   0   0   0   0   0   0
## s03   0   0   0   0   0   1   1   1   1   0   0   0   0   0   0   0   0
## s04   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0   0   0
## s05   0   0   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0
## s06   0   0   0   0   0   0   0   0   0   0   0   0   1   1   0   0   1
##     U18 U19 U20
## s01   0   0   0
## s02   0   0   1
## s03   0   0   0
## s04   0   0   0
## s05   0   0   0
## s06   0   0   0
net2 <- graph.incidence(edges2)
table(E(net2)$type)
## < table of extent 0 >
plot(net2, vertex.label=NA)

We modify the network object visualization so that subscriber nodes can be distinguished from media nodes.

V(net2)$color <- c("blue", "orange")[V(net2)$type+1]
V(net2)$shape <- c("square", "circle")[V(net2)$type+1]
V(net2)$label <- ""
V(net2)$label[V(net2)$type==F] <- nodes2$media[V(net2)$type==F]
V(net2)$label.cex=.4
V(net2)$label.font=2
plot(net2, vertex.label.color="white", vertex.size=(2-V(net2)$type)*8)

For some bimodal networks, it might be useful to use a layout that accentuates the bimodality.

plot(net2, vertex.label=NA, vertex.size=7, layout=layout.bipartite)

We can also use text instead of shapes to represent nodes.

plot(net2, vertex.shape="none", vertex.label=nodes2$media, vertex.label.color=V(net2)$color, vertex.label.font=2, vertex.label.cex=.6, edge.color="gray70", edge.width=2)

For a customized visualization, we can use images to represent nodes.

library(png)
mediaimg <- readPNG("Images/news.png")
userimg <- readPNG("Images/user.png")
V(net2)$raster <- list(mediaimg, userimg)[V(net2)$type+1]
plot(net2, vertex.shape="raster", vertex.label=NA, vertex.size=16, vertex.size2=16,edge.width=2)

detach(package:png)
detach(package:igraph)

INTERACTIVE AND ANIMATED NETWORK VISUALIZATIONS

Interactive Networks Using D3.js

library(networkD3)
E1 <- data.frame(from=as.numeric(factor(edges$from))-1, to=as.numeric(factor(edges$to))-1)
N1 <- cbind(idn=factor(nodes$media, levels=nodes$media), nodes)
forceNetwork(Links=E1, Nodes=N1, Source="from", Target="to", NodeID="idn", Group="type.label", linkWidth=1, linkColour="#afafaf", fontSize=12, zoom=T, legend=T,Nodesize=6, opacity=.8, charge=-300, width=600, height=600)

## Aside: Using the network Package
Plots using the network package is similar to those made using igraph.

library(network)
net3 <- network(edges, vertex.attr=nodes, matrix.type="edgelist", loops=F, multiple=F, ignore.eval=F)

net3[,]
##     s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 s13 s14 s15 s16 s17
## s01   0   1   1   1   0   0   0   0   0   0   0   0   0   0   1   0   0
## s02   1   0   1   0   0   0   0   0   1   1   0   0   0   0   0   0   0
## s03   1   0   0   1   1   0   0   1   0   1   1   1   0   0   0   0   0
## s04   0   0   1   0   0   1   0   0   0   0   1   1   0   0   0   0   1
## s05   1   1   0   0   0   0   0   0   1   0   0   0   0   0   1   0   0
## s06   0   0   0   0   0   1   0   0   0   0   0   0   0   0   0   1   1
## s07   0   0   1   0   0   0   0   1   0   1   0   0   0   1   0   0   0
## s08   0   0   1   0   0   0   1   0   1   0   0   0   0   0   0   0   0
## s09   0   0   0   0   0   0   0   0   0   1   0   0   0   0   0   0   0
## s10   0   0   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0
## s11   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
## s12   0   0   0   0   0   1   0   0   0   0   0   0   1   1   0   0   0
## s13   0   0   0   0   0   0   0   0   0   0   0   1   0   0   0   0   1
## s14   0   0   0   0   0   0   0   0   0   0   1   0   1   0   0   0   0
## s15   1   0   0   1   0   1   0   0   0   0   0   0   0   0   0   0   0
## s16   0   0   0   0   0   1   0   0   0   0   0   0   0   0   0   0   1
## s17   0   0   0   1   0   0   0   0   0   0   0   0   0   0   0   0   0
net3 %n% "net.name" <- "Media Network"
net3 %v% "media"
##  [1] "NY Times"            "Washington Post"     "Wall Street Journal"
##  [4] "USA Today"           "LA Times"            "New York Post"      
##  [7] "CNN"                 "MSNBC"               "FOX News"           
## [10] "ABC"                 "BBC"                 "Yahoo News"         
## [13] "Google News"         "Reuters.com"         "NYTimes.com"        
## [16] "WashingtonPost.com"  "AOL.com"
net3 %e% "type"
##  [1] "hyperlink" "hyperlink" "hyperlink" "mention"   "hyperlink"
##  [6] "hyperlink" "hyperlink" "hyperlink" "hyperlink" "hyperlink"
## [11] "hyperlink" "hyperlink" "mention"   "hyperlink" "hyperlink"
## [16] "hyperlink" "mention"   "mention"   "hyperlink" "mention"  
## [21] "mention"   "hyperlink" "hyperlink" "mention"   "hyperlink"
## [26] "hyperlink" "mention"   "mention"   "mention"   "hyperlink"
## [31] "mention"   "hyperlink" "mention"   "mention"   "mention"  
## [36] "hyperlink" "mention"   "hyperlink" "mention"   "hyperlink"
## [41] "mention"   "mention"   "mention"   "hyperlink" "hyperlink"
## [46] "hyperlink" "hyperlink" "mention"   "hyperlink"
net3 %v% "col" <- c("gray70", "tomato", "gold")[net3 %v% "media.type"]
plot(net3, vertex.cex=(net3 %v% "audience.size")/7, vertex.col="col")