Application shiny pour représenter votre réseau facebookA shiny app that displays your facebook network
Les scripts pour réaliser une interface web qui vous permet de représenter votre réseau facebook ? Voir l’article en anglais…
This post follows
this post and this other post that, respectively, described how to extract your friendship network from facebook and how to create a Graphical User Interface with R and the package shiny. In this, I simply provide a graphical user interface made with shiny to display your facebook network, with different options for representing the nodes (color, size…). The initial function commented on this post to collect information from your facebook network was re-written due to a recent change in the facebook graph API.
An example of how the application works is provided in this movie:
and the application may be testable here (where it is hosted by rstudio but I don’t know for sure how the application might react to many simultaneous connections because gathering the information from facebook takes several minutes at each time so you’d better be patient…).
Installing necessary packages
In this example, I am using several packages: shiny (now available on CRAN repositories), igraph to manipulate networks, RCurl and rjson to import and extract data from facebook and finally, RColorBrewer to better handle colors.
ui.R
The file ui.R
contains the description of the interface: mine is made of a left hand side panel where the options are set by the user (the access token pasted from the facebook graph API explorer and the meaning of node color, size and label) and of a right hand side panel where the results are displayed. The main functions used in this panel are:
-
textInput
to obtain a character string from the user (here, the facebook access token); -
selectInput
to make the user select an option from a list (here, meaning of the node color, size and label); -
checkboxInput
to display a checkbox clickable by the user; -
p
,br()
andHTML
for various HTML tags that can be used to print free text.
The interface also contains a right hand side panel, which is the main panel where the results are displayed. Thanks to the function conditionalPanel
, this panel displays a short user guide until an access token is given. Then, the main panel is divided into two tabs to organize outputs in a graphical part (where the network is displayed) and a statistical parts (where simple facts about the network are summarized). The outputs are displayed by using the functions plotOutput
(that displays a graph coming from the server.R
script and referenced by a name, here graph
) and tableOutput
(that displays a data frame coming from the server.R
script and referenced by a name, here stats
).
The full script is given below:
shinyUI(pageWithSidebar(
# Title of the application
headerPanel("Visualize your facebook network..."),
# Left hand side panel
sidebarPanel(
textInput("token",strong("Copy your access token here:"), ""),
selectInput("ncol", "Node color represents:",choices = c("community","betweenness","degree","uniform")),
selectInput("nsize", "Node size represents:",choices = c("degree","betweenness","uniform")),
selectInput("nname","Node names are:",choices=c("initials","facebook id","names")),
checkboxInput("lcc"," Only the largest connected component is displayed.",TRUE),
br(),
p(HTML("Script sources and explanations can be found on my blog.")),
p(HTML("This application is kindly provided by tuxette ;-)"))
),
# Right hand side panel
mainPanel(
# If the "token" text area is empty
conditionalPanel(
condition = "input.token == '' ",
h4("Basic user guide"),
p("To visualize your facebook network, please go to ", a("the facebook graph API Explorer", href="https://developers.facebook.com/tools/explorer")," to generate a token and copy it in the field on the left hand side panel. Do not forget to select proper permissions to give you access to your friends' data."),
p("You may wait for a long time for the first network to be displayed (until all your data are collected from facebook) and then you can change the way the network is displayed by selecting various options for the node colors, size and label.")
),
# If the "token" text area is not empty
conditionalPanel(
condition = "input.token != '' ",
tabsetPanel(
tabPanel("Chart",p(HTML("Wait a few minutes... I'm working...")),plotOutput("chart")),
tabPanel("Statistics",tableOutput("stats"))
)
)
)
))
server.R
The server.R
script reacts to changes in the input collected in the ui.R
(each referenced by a label and useable with input$LABEL
in the server.R
script) and calculates outputs that can be numerical values, data frames, charts… This script is made of 5 main functions:
-
facebook
is the generic function to collect information through the facebook graph API; -
fb.friends
usesfacebook
and the access token provided by the user to collect the list of friends. It is a reactive function, i.e., a function that reats to changes in the user’s input options; -
mainnet
usesfacebook
and the access token provided by the user to collect the information about mutual friendship among your friends. It is also a reactive function; -
output$chart
uses the two functionsfb.friends
andmainnet
to define a network and then to display it accordingly to the options specified by the user. It uses the package igraph to manipulate networks and it is also a reactive function that reacts to changes in the options chosen for representing the network; -
output$stats
uses the two functionsfb.friends
andmainnet
to define a network and then to calculate simple statistics. Mine told me that my network contains 150 friends among which Sabrina is the one who is the most connected.
The full script is given below:
library(RCurl)
library(rjson)
library(igraph)
library(RColorBrewer)
# Generic function that collects data from facebook through the facebook graph API
facebook = function( path = "me", access_token = token, options){
if( !missing(options) ){
options = sprintf( "?%s", paste( names(options), "=",
unlist(options), collapse = "&", sep = "" ) )
} else {
options = ""
}
data = getURL( sprintf(
"https://graph.facebook.com/%s%s/?access_token=%s", path, options,
access_token ) )
print(sprintf( "https://graph.facebook.com/%s%s/?access_token=%s",
path, options, access_token ))
fromJSON( data )
}
# Shiny ouputs calculation
shinyServer(function(input, output) {
# Collect information about the friends on facebook
fb.friends = reactive(function(){
friends = facebook( path="me/friends" , access_token=input$token)
friends.id = sapply(friends$data, function(x) x$id)
friends.name = sapply(friends$data, function(x) iconv(x$name,"UTF-8","ASCII//TRANSLIT"))
initials = function(x) paste(substr(x,3,3), collapse=" ")
friends.initial = sapply(strsplit(friends.name," "), initials)
list("initials"=friends.initial,"name"=friends.name,"fbid"=friends.id)
})
# Collect mutual friendship information on facebook
mainnet = reactive(function() {
the.friends = fb.friends()
N = length(the.friends$initials)
friendship.matrix = matrix(0,N,N)
for (i in 1:N) {
tmp = facebook( path=paste("me/mutualfriends", the.friends$fbid[i], sep="/") , access_token=input$token)
mutualfriends = sapply(tmp$data, function(x) x$id)
friendship.matrix[i,the.friends$fbid %in% mutualfriends] = 1
}
colnames(friendship.matrix) = the.friends$name
rownames(friendship.matrix) = the.friends$name
friendship.matrix
})
# Display the network
output$chart = reactivePlot(function() {
the.friends = fb.friends()
adj = mainnet()
the.full.graph = graph.adjacency(adj,mode="undirected")
V(the.full.graph)$initials = the.friends$initials
V(the.full.graph)$fbid = the.friends$fbid
if (input$lcc) {
the.clusters = clusters(the.full.graph)
the.graph = induced.subgraph(the.full.graph,which(the.clusters$membership==which.max(the.clusters$csize)))
} else {
the.graph = the.full.graph
}
if (input$ncol=="uniform") {
V(the.graph)$color = rep("seagreen",vcount(the.graph))
} else if (input$ncol=="degree") {
dclust = cut(degree(the.graph),9,label=F)
V(the.graph)$color = brewer.pal(9,"YlOrRd")[dclust]
} else if (input$ncol=="betweenness") {
bclust = cut(betweenness(the.graph),9,label=F)
V(the.graph)$color = brewer.pal(9,"YlOrRd")[bclust]
} else if (input$ncol=="community") {
all.cc = clusters(the.graph)
lcc = induced.subgraph(the.graph,which(all.cc$membership==which.max(all.cc$csize)))
clust = multilevel.community(lcc)
V(the.graph)$color = rep("yellow",vcount(the.graph))
V(the.graph)$color[match(clust$names,V(the.graph)$name)] = brewer.pal(12,"Paired")[clust$membership]
}
if (input$nsize=="degree") {
vsize = degree(the.graph)/max(degree(the.graph))*8
} else if (input$nsize=="betweenness") {
vsize = betweenness(the.graph)/max(betweenness(the.graph))*8
} else if (input$nsize=="uniform") {
vsize = rep(5,vcount(the.graph))
}
if (input$nname=="names") {
vname = V(the.graph)$name
} else if (input$nname=="facebook id") {
vname = V(the.graph)$fbid
} else if (input$nname=="initials") {
vname = V(the.graph)$initials
}
par(mar=rep(0,4))
set.seed(21121444)
plot(the.graph,layout=layout.auto,vertex.label=vname,vertex.label.font=1,vertex.label.color="black",vertex.color=V(the.graph)$color, vertex.frame.color=V(the.graph)$color,vertex.size=vsize)
})
# Calculate basic statistics
output$stats = reactiveTable(function() {
the.friends = fb.friends()
adj = mainnet()
the.full.graph = graph.adjacency(adj,mode="undirected")
deg = degree(the.full.graph)
the.bet = betweenness(the.full.graph)
data.frame(
Statistics = c("Number of friends", "Density", "Transitivity", "Average degree", "Max degree", "Average betweenness", "Max betweenness", "Best degree", "Best betweenness"),
Values = as.character(c(vcount(the.full.graph), paste(round(graph.density(the.full.graph)*100,0),"%",collapse=" "), paste(round(transitivity(the.full.graph)*100,0),"%",collapse=" "), round(mean(deg),1), max(deg), round(mean(the.bet),0), round(max(the.bet),0), names(which.max(deg)), names(which.max(the.bet)))),
stringsAsFactors=FALSE)
})
})
In case your would like to use and/or modify this application on your own computer (without the need to rely on the rstudio server), make sure all the necessary packages are installed, then copy/paste the two scripts ui.R
and server.R
in given directory (for instance, “DIR”) and, in R, run
library(shiny)
runApp("PATH2DIR/DIR")
where “PATH2DIR” is the path from your working directory to “DIR”.