########################Complex Systems Networks##########################
library(igraph)
##
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
library(readr)
#a<-read.csv("~/Box/Taurean/Year_1/SSNA/Visualizing_course_taking.csv")
b<-sns_music_collab <- read.csv("sns_music_collab.csv")
#b <- subset(b, year == 2020)
b<- b[,-1]
dim(b)
## [1] 1586 4
names(b)
## [1] "artist" "song" "position" "year"
#Creates a campus indicator by semester
#a$campus<-ifelse(a$term==min(a$term), as.character(a$sem1_campus), as.character(a$sem2_campus))
#head(a[a$sem1_campus!=a$sem2_campus,c("term", "sem1_campus", "sem2_campus", "campus")], 200)
#The following code retrieves the student-course connections to be saved under an graph object called "g"
#g<-graph.data.frame(a[,c("pseudoid","term_course", "gr_course", "campus")])
b$song <-paste(b$song,b$year,sep="_")
g<-graph.data.frame(b[,c("artist","song", "position", "year")])
#The following code adds the two-mode structure to the graph "g"
V(g)$type <- V(g)$name %in% b[,c("artist")]
table(V(g)$type)[2]
## TRUE
## 631
i<-table(V(g)$type)[2]
#Gets centrality measures
cent<-data.frame(bet=betweenness(g, normalized=T, directed = FALSE)/max(betweenness(g, normalized=T, directed = FALSE)),eig=evcent(g)$vector, degree=degree(g, mode="total"))
cent$name<-rownames(cent) #Ids in this case
head(cent);tail(cent)
## bet eig degree
## Santana 0.0005688123 6.017481e-17 5
## Rob Thomas 0.0000000000 7.429830e-18 1
## Sting 0.0000000000 0.000000e+00 1
## Missy 'Misdemeanor' Elliott 0.0438896850 8.285497e-04 3
## Dr Dre 0.0632788002 7.876422e-03 4
## SoulDecision 0.0000000000 0.000000e+00 1
## name
## Santana Santana
## Rob Thomas Rob Thomas
## Sting Sting
## Missy 'Misdemeanor' Elliott Missy 'Misdemeanor' Elliott
## Dr Dre Dr Dre
## SoulDecision SoulDecision
## bet eig degree
## Laugh Now Cry Later_2021 3.230726e-02 1.836624e-01 2
## Glad You Exist_2021 2.556460e-06 4.129379e-03 2
## Lemonade_2021 1.944188e-02 1.287694e-03 4
## Monster_2021 7.981816e-02 2.535812e-02 2
## Bed_2021 6.979238e-02 2.578108e-02 3
## All We Got_2021 1.150407e-04 1.391239e-17 2
## name
## Laugh Now Cry Later_2021 Laugh Now Cry Later_2021
## Glad You Exist_2021 Glad You Exist_2021
## Lemonade_2021 Lemonade_2021
## Monster_2021 Monster_2021
## Bed_2021 Bed_2021
## All We Got_2021 All We Got_2021
V(g)$label<-V(g)$name
V(g)$name<-1:length(V(g))
#In HTML visualizations (like NetworkD3) we need two datasets, one for links, another for nodes attributes.
#Gets edgelist from graph, also any other attribute at the edge level to be included in the mapping
links<-as.data.frame(cbind(get.edgelist(g), E(g)$position, E(g)$year))
#Needs to be numeric
links$V1<-as.numeric(as.character(links$V1))
links$V2<-as.numeric(as.character(links$V2))
str(links)
## 'data.frame': 1586 obs. of 4 variables:
## $ V1: num 1 2 3 4 5 5 6 7 8 9 ...
## $ V2: num 632 633 634 635 636 637 638 639 640 641 ...
## $ V3: chr "2" "6" "31" "56" ...
## $ V4: chr "2000" "2000" "2000" "2000" ...
links$V3<-round(as.numeric(as.character(links$V3)),3)
head(links)
## V1 V2 V3 V4
## 1 1 632 2 2000
## 2 2 633 6 2000
## 3 3 634 31 2000
## 4 4 635 56 2000
## 5 5 636 63 2000
## 6 5 637 64 2000
colnames(links)<-c("source","target", "value", "year")
#Counts begin at zero in computer programming
links[,1:2]<-(links[,1:2]-1)
dim(links)
## [1] 1586 4
b1<-aggregate(position~artist, data=b, FUN=mean)
#Adding attributes at the actor level
V(g)$size<- cent$bet[match(V(g)$label, cent$name)]
V(g)$group <- round(b1$position[match(V(g)$label, b1$artist)],3)
###############################################################################
#If you have codes with no attributes at the code level, this may be needed##
###############################################################################
# V(g)$firstgen <- ifelse(is.na(V(g)$firstgen), .5, V(g)$firstgen)
#V(g)$group <- ifelse(is.na(V(g)$group), 1, V(g)$group)
summary(V(g)$size)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00000 0.00000 0.01299 0.03655 0.04068 1.00000
summary(V(g)$group)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1.00 35.55 52.67 52.93 71.25 100.00 721
nodes <- data.frame(name=c(paste("Artist: ", V(g)$label[1:i], " Position: ", V(g)$group[1:i]),V(g)$label[(i+1):length(V(g)$label)]), size=abs(V(g)$size), position=V(g)$group)
nodes$name<-as.character(nodes$name)
#Name of course, rather than code
#nodes$name[(i+1):length(V(g)$label)] <- a$crse_ld[match(nodes$name[(i+1):length(V(g)$label)], a$term_course)]
#head(nodes);tail(nodes)
nodes$group<-NA
nodes$group[1:i]<-cut(nodes$position[1:i], c(1,35,52,71,max(nodes$position[1:i])), right=TRUE)
table(is.na(nodes$group))
##
## FALSE TRUE
## 626 726
table(nodes$group)
##
## 1 2 3 4
## 151 156 161 158
#head(nodes[is.na(nodes$group),],20)
nodes$group<-ifelse(is.na(nodes$group), "Song", ifelse(nodes$group==1, "Low Quartile", ifelse(nodes$group==2, "Second quartile", ifelse(nodes$group==3, "Third quartile", "Top quartile"))))
counts<-data.frame(table(nodes$group))
counts$labels <- paste(counts$Var1, ", N= ", counts$Freq, sep="")
nodes$groups <- counts$labels[match(nodes$group, counts$Var1)]
head(counts)
## Var1 Freq labels
## 1 Low Quartile 151 Low Quartile, N= 151
## 2 Second quartile 156 Second quartile, N= 156
## 3 Song 726 Song, N= 726
## 4 Third quartile 161 Third quartile, N= 161
## 5 Top quartile 158 Top quartile, N= 158
library(networkD3)
library(magrittr)
library(htmlwidgets)
##
## Attaching package: 'htmlwidgets'
## The following object is masked from 'package:networkD3':
##
## JS
library(htmltools)
netviz<-forceNetwork(Links = links, Nodes = nodes,
Source = 'source', Target = 'target',
NodeID = 'name',
Group = "groups", # color nodes by group calculated earlier
charge = -30, # node repulsion
linkDistance = JS("function(d) { return d.linkDistance; }"),#JS("function(d){return d.value}"),
linkWidth = JS("function(d) { return Math.sqrt(d.value)*2; }"),
opacity = 0.8,
Value = "value",
Nodesize = 'size',
radiusCalculation = JS("Math.sqrt(d.nodesize*30)+4"),
zoom = T,
fontSize=14,
bounded= F,
legend= TRUE)
# linkColour = JS("d3.scaleOrdinal(d3.schemeCategory10)"))
HTMLaddons <-
"function(el, x) {
d3.select('body').style('background-color', ' #212f3d ')
d3.selectAll('.legend text').style('fill', 'white')
d3.selectAll('.link').append('svg:title')
.text(function(d) { return 'Position: ' + d.value + ', Year: ' + d.year ; })
var options = x.options;
var svg = d3.select(el).select('svg')
var node = svg.selectAll('.node');
var link = svg.selectAll('link');
var mouseout = d3.selectAll('.node').on('mouseout');
function nodeSize(d) {
if (options.nodesize) {
return eval(options.radiusCalculation);
} else {
return 6;
}
}
d3.selectAll('.node').on('click', onclick)
function onclick(d) {
if (d3.select(this).on('mouseout') == mouseout) {
d3.select(this).on('mouseout', mouseout_clicked);
} else {
d3.select(this).on('mouseout', mouseout);
}
}
function mouseout_clicked(d) {
node.style('opacity', +options.opacity);
link.style('opacity', +options.opacity);
d3.select(this).select('circle').transition()
.duration(750)
.attr('r', function(d){return nodeSize(d);});
d3.select(this).select('text').transition()
.duration(1250)
.attr('x', 0)
.style('font', options.fontSize + 'px ');
}
}
"
netviz$x$links$linkDistance <- (1/links$value)*500
netviz$x$links$year <- links$year
onRender(netviz, HTMLaddons)
From our key actor analysis we see that the artist with the highest eigenvector centrality is Drake. The artist with the highest betweenness centrality is David Guetta.
topeig <- cent[order(-cent$eig),]
topbet <- cent[order(-cent$bet),]
head(topeig)
## bet eig degree name
## Drake 0.7997468 1.0000000 29 Drake
## Rihanna 0.9538800 0.5030951 23 Rihanna
## Too Good_2016 0.0845163 0.2586505 2 Too Good_2016
## Take Care_2012 0.0845163 0.2586505 2 Take Care_2012
## What's My Name?_2011 0.0845163 0.2586505 2 What's My Name?_2011
## Work_2016 0.0845163 0.2586505 2 Work_2016
head(topbet)
## bet eig degree name
## David Guetta 1.0000000 0.14066500 25 David Guetta
## Rihanna 0.9538800 0.50309506 23 Rihanna
## Justin Bieber 0.9066926 0.14260961 22 Justin Bieber
## Drake 0.7997468 1.00000000 29 Drake
## Ludacris 0.7911125 0.02348136 18 Ludacris
## Nicki Minaj 0.7879056 0.05639110 19 Nicki Minaj