DÉBAT #ENLD : Traités internationaux (images animées)

Le dernier post « tutoriel » a exactement une semaine. C’est à peu près le temps qu’il m’a fallu pour patauger dans ce que l’informatique nous offre de plus excitant : des installations d’extension et autres applications, mal documentées, et qui pour finir n’aboutissent jamais à rien.
C’est finalement grâce au plus que talentueux Jérémie Knüsel (qui ne souhaite sûrement pas être nommé), que je suis parvenu à quelque chose. Ce que je vais conter ci-dessous.
Dans cet article, nous allons observer comment le graphe se construit, comment les arêtes représentant les échanges du débat s’ajoutent à sa représentation visuelle, jusqu’à ce qu’il atteigne sa forme définitive. Nous rappelons que ne sont pris en compte que les tweets qui mentionnent un autre utilisateur. Ceux qui ne mentionnent personne ne sont pas visibles (si ce n’est dans la taille des représentations des utilisateurs, fonction du nombre de tweets écrits), une mention de soi-même n’étant pas non plus pris en compte. Il est donc impossible de tirer des conclusions sur le débat, sa qualité, ou quoi que ce soit, à partir de cette représentation. Les questions sont autres.
Comme d’habitude, il est difficile de s’adresser à des visiteurs uniquement intéressés par les résultats, en même temps qu’à des chercheurs ayant besoin de connaître les routines permettant de reproduire ces résultats. Donc, commençons par la fin :
Et poursuivons par le début.Nous avions vu comment récupérer les données sur Twitter, les transformer en data.frame, puis extraire les relations, et en faire un graphe. Je recopie le code quand même (pas le courage de tout commenter).

MON PRÉAMBULE

rm(list=ls())

library(twitteR)
library(igraph)

file <- "2012_04_30_enld.Rdata"
today <- "Apr_30"
main <- paste("#EnLD",today,"traités internationaux", sep=" ")
wd <- getwd()

RÉCUPÉRER ET GÉRER LES DONNÉES

res <- searchTwitter("#enld", n= 10^6, since ="2012-04-28")
res.df <- twListToDF(res)

res.df <- res.df[1:134,]
rownames(res.df) <- 1:nrow(res.df)

res.df <- res.df[-c(5,11,13),]
rownames(res.df) <- 1:nrow(res.df)

res.df$screenName <- tolower(res.df$screenName)
save(res,res.df,file=file)

Première ligne : récupération des tweets.
Deuxième ligne : transformation en data frame.
Troisième ligne : les lignes qu’on veut garder (ici : 1 à 134).
Quatrième ligne : on renumérote le data frame depuis 0.
Cinquième ligne : on retire les lignes qui ne concernent pas le débat (par exemple mes posts de blog).
Septième ligne : on met tout le monde en minuscules, c’est plus simple.
Huitième ligne : on sauvegarde toutes les données. Sécurité…

AUTEURS ET FRÉQUENCE DE TWEETS

auteurs <- c()
auteurs <- res.df$screenName
actors <- data.frame(table(auteurs),auteur=T)

MENTIONS & RELATIONS

actors.in <- gregexpr("@[0-9A-Za-z_]+",res.df$text)
nbre.mentions <- length(unlist(actors.in)[unlist(actors.in)!=-1])

twitterGraph <- function(auteurs, actors.in, res.df) {
 enld.aretes <- data.frame(
  auteur=rep(NA,nbre.mentions),
  mention=rep(NA,nbre.mentions), 

  text=rep(NA,nbre.mentions),
  created=rep(NA,nbre.mentions),
  id=rep(NA,nbre.mentions),
  RT=rep(FALSE,nbre.mentions)
 )
 k <- 0
 for (i in 1:length(actors.in)) {
  if (actors.in[[i]][1] != -1) {
   emetteur <- auteurs[i]
   for (j in 1:length(actors.in[[i]])) {
    k <- k+1
    arobase.pos <- actors.in[[i]][j]
    recepteur <- substr(res.df$text[i], arobase.pos+1,
    arobase.pos + attr(actors.in[[i]],which="match.length")[j] - 1)
    enld.aretes$auteur[k] <- tolower(emetteur)
    enld.aretes$mention[k] <- tolower(recepteur)
    enld.aretes$text[k] <- res.df$text[i]
    enld.aretes$created[k] <- res.df$created[i]
    enld.aretes$id[k] <- res.df$id[i]
    if (substr(res.df$text[i],1,2)=="RT") enld.aretes$RT[k] <- TRUE
   }
  }
 }
 enld.aretes
}

enld.aretes <- twitterGraph(auteurs=auteurs, actors.in=actors.in, res.df=res.df)

enld.aretes$created <- as.POSIXct(enld.aretes$created, origin = "1970-01-01 00:00:00 UTC")+60^2
relations <- enld.aretes

AUTEURS & INFORMATIONS

mentions.unique <- unique(enld.aretes$mention)
auteurs.unique <- unique(auteurs)
mentions.to.add <- c()
for (i in 1:length(mentions.unique)) {
 if (sum(grepl(mentions.unique[i], auteurs.unique)) == 0)  {
 mentions.to.add <- c(mentions.to.add, mentions.unique[i])
 }
}
actors <- rbind(actors, data.frame(
 auteurs=mentions.to.add,
 Freq=0,
 auteur=F)
 )

n <- length(actors$auteurs)

enld.auteurs <- data.frame(
 description=rep(NA,n),
 statusesCount=rep(NA,n),
 followersCount=rep(NA,n),
 friendsCount=rep(NA,n),
 nom=rep(NA,n),
 created=as.POSIXct(rep(NA,n)),
 location=rep(NA,n),
 id=rep(NA,n)
 )

for (i in 1:n) {
 temp <- getUser(actors$auteurs[i])
 enld.auteurs$description[i] <- temp$description
 enld.auteurs$statusesCount[i] <- temp$statusesCount
 enld.auteurs$followersCount[i] <- temp$followersCount
 enld.auteurs$friendsCount[i] <- temp$friendsCount
 enld.auteurs$nom[i] <- temp$name
 enld.auteurs$created[i] <- temp$created
 enld.auteurs$location[i] <- temp$location
 enld.auteurs$id[i] <- temp$id
}

actors$auteurs <- as.character(actors$auteurs)
vertices <- cbind(actors,enld.auteurs)
colnames(vertices)[1] <- "name"

save(res,res.df,vertices,relations,file=file)

CRÉATION DU MULTIGRAPHE

g <- graph.data.frame(vertices=vertices, d=relations)
g <- delete.edges(g,E(g)[is.loop(g)])

V(g)$d.in <- degree(g,mode="in")
V(g)$d.out <- degree(g,mode="out")
E(g)$weight <- count.multiple(g)

PARAMÈTRES GRAPHIQUES

pal <- rainbow(max(V(g)$d.in)+1,start=.7, end=.1)

V(g)$size <- log(V(g)$Freq+2)*2
V(g)$color <- pal[V(g)$d.in+1]
V(g)$label <- V(g)$name
V(g)$label.cex <- 1
V(g)$label.dist <- .2
V(g)$label.color <- "Red"
for (i in V(g)) {
 if (V(g)[i]$auteur) V(g)[i]$label.color <- "Black"
}
V(g)$frame.color <- "White"

E(g)$color <- "darkgrey"
E(g)$width <- pmin(E(g)$weight/1.5,5)
E(g)$curved <- .2
E(g)$arrow.size <- .8
E(g)$arrow.width <- .5

g$layout <- layout.fruchterman.reingold(g,
 repulsrad=10^6*vcount(g))

VISUALISATION

draw <- function(graph, main = "") {
 breaks <- 0:max(V(g)$d.in)
 layout(
  matrix(
   data=c(1,2),
   nrow=1,
   ncol=2),
  widths = c(10,1),
  heights = c(1,1)
 )
 par(mar=c(1,1,4,2))
 plot(graph)
 title(main = main, cex.main = 2)
 text(-0.9, 1,
  "La taille du\nsommet correspond
  \nau nombre de\ntweets écrits",
  cex=1.5
 )
 text(-0.9, -1,
  "L'épaisseur de\nl'arc correspond\nau nombre de\nmentions faites",
  cex=1.5
 )
 text(0.9,1,
  "Les sommets dont\nle nom d'utilisateur
  \nest en rouge\nn'ont pas\ncontribué au débat",
  cex=1.5
 )
 par(1,1,4,3)
 image(
  x=1,
  y=0:(max(V(g)$d.in)+1),
  z=t(matrix(0:(max(V(g)$d.in))))*1.001,
  col=pal[1:length(pal)],
  axes=FALSE,
  breaks=0:(max(V(g)$d.in)+1),
  xlab="",
  ylab="",
  xaxt="n"
 )
 axis(2,
  at = 0:max(V(g)$d.in)+.5,
  labels = 0:max(V(g)$d.in),
  col = "white",
  las = 1,
  line = -4.5
 )
}

SORTIE GRAPHIQUE

png(
 paste("avecRT_avecJ_",sub(" ","_",today),".png",sep=""),
 width=800,
 height=800
)
draw(g,
 main = paste(main,"\navec RT avec journalistes",sep="")
)
dev.off()

GÉNÉRATION DES PLOTS UTILISÉS POUR LA VIDÉO (UN PAR MINUTE)

r <- range(E(g)$created)
gap <- 60
r[1] <- min(r) - min(r) %% gap
r[2] <- max(r) - max(r) %% gap + gap
r.interval <- seq(r[1],r[2],60)

setwd(paste(wd,"/png",sep=""))
for (i in r.interval){
 temp <- delete.edges(g,E(g)[created>i])
 if (ecount(temp) > 0) {
 E(temp)$width <- pmin(count.multiple(temp)/1,8)
 }
 png(
  paste(i,"_avecRT_avecJ_",today,".png",sep=""),
  width=800,
  height=800
 )
 draw(
  temp,
  main = paste(
   main,
   "avec RT avec journalistes\n",
   as.POSIXct(i, origin = "1970-01-01 00:00:00 UTC"),
   sep=""
  )
 )
 dev.off()
}
setwd(wd)

À ce moment-là, on a r[2] – r[1] + 1 images enregistrées dans le dossier « png ». Ici je peux difficilement vous aider si vous avez un mac (un pc j’imagine même pas, pas envie d’essayer non plus). Le packageanimation permet de sauvegarder des vidéos. Il repose sur ImageMagick qui repose sur  ffmpeg, qui doit être installé à la ligne de commande… Il doit sûrement exister un moyen simple de faire fonctionner tout ça, mais oubliez iMovie et ce genre de bêtises. Si quelqu’un le connaît, qu’il me le fasse savoir, ce serait gentil.

En attendant, Jérémie m’a offert un accès à sa machine qui tourne bien entendu sous Linux, dans un monde où tout fonctionne (pas toujours très bien), mais où tout PEUT fonctionner.

Et donc, vous vouliez tout savoir, et je ne vous explique rien, et surtout pas comment faire cette vidéo mignonne.

Ha si ! Réflexe de mes années au Callcenter de l’EPFL : adressez-vous à votre support de proximité (par exemple un pote/collègue qui maîtrise sa machine pour de vrai).

Publicités