silico.biotoul.fr
 

M1 BBS Graphes TP Recherche de communautés dans les graphes

From silico.biotoul.fr

(Difference between revisions)
Jump to: navigation, search
m (Distribution de la paralogie)
m (Assemblage des cinq méthodes)
 
(248 intermediate revisions not shown)
Line 1: Line 1:
-
==Introduction==
+
=Introduction=
-
Nous allons réaliser une analyse de génomique comparative qui s’inspire d’un travail publié par Snipen et Liland (2015). Le but est d’identifier le core et le pan génome d’un ensemble de souches bactériennes. Le core génome est l’ensemble des gènes communs à toutes les souches. Le pan génome est l’ensemble des gènes codés par au moins une des souches. Dans ce contexte un gène est en réalité une famille de gènes ou un cluster de gènes similaires. Idéalement, une famille de gènes serait une collection de gènes orthologues. Néanmoins, comme une analyse pan génomique ne produit pas toujours des groupes de gènes orthologues, il est préférable de parler de clusters de gènes. Bien que ce concept de clusters de gènes joue un rôle central dans les analyses de génomiques comparatives, il n’y a pas de consensus sur la façon de les calculer! Dans ce TP, nous allons explorer une approche basée sur la détection de communautés dans un graphe.
+
Nous allons réaliser une analyse de génomique comparative qui s’inspire d’un travail publié par [https://www.ncbi.nlm.nih.gov/pubmed/25888166 Snipen et Liland (2015)]. Le but est d’identifier le core et le pan génome d’un ensemble de souches bactériennes. Le core génome est l’ensemble des gènes communs à toutes les souches. Le pan génome est l’ensemble des gènes codés par au moins une des souches ([https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1216834/ Tettelin et al., 2005]). Dans ce contexte un gène est en réalité une famille de gènes ou un cluster de gènes similaires. Idéalement, une famille de gènes serait une collection de gènes orthologues. Néanmoins, comme une analyse pan génomique ne produit pas toujours des groupes de gènes orthologues, il est préférable de parler de '''clusters de gènes'''.  
 +
Bien que ce concept de clusters de gènes joue un rôle central dans les analyses de génomiques comparatives, il n’y a pas de consensus sur la façon de les calculer ([https://pubmed.ncbi.nlm.nih.gov/31891864/ Kim et al., 2020])! Dans ce TP, nous allons explorer une approche basée sur la détection de communautés dans un graphe.
 +
 
 +
Snipen et Liland ont écrit un package R qui permet de répondre à cette question ([https://cran.r-project.org/web/packages/micropan/index.html micropan]). Ils ont mis à disposition une étude de cas (casestudy.pdf) afin de guider les utilisateurs de ce package.
-
Snipen et Liland ont écrit un package R qui permet de répondre à cette question (micropan). Ils ont mis à disposition une étude de cas casestudy. pdf afin de guider les utilisateurs de ce package.
 
==Les données==
==Les données==
-
12 souches de ''Yersinia pestis'' seront analysées. Les données sont disponible sur le serveur '''silico''' dans le répertoire ''enseignement/m1-bioinfo/Graphe/micropan/Ypestis''. Les protéines en format FASTA sont dans le répertoire ''data/proteins''. Les comparaisons entre pairs de génomes sont réalisées à l’aide de '''Blast+''' et une annotation des domaines Pfam des protéines est réalisée avec '''HMMER3'''. Les fichiers pré-calculés sont disponibles dans les répertoires ''blast'' et ''pfam''. Ils sont également disponibles sous forme compressée.
+
Nous allons travailler avec la bactérie ''Yersinia pestis'' une bactérie à Gram négatif du genre ''Yersinia''. Elle est responsable de la '''peste'''.
 +
Elle a été découverte en 1894 par '''Alexandre Yersin''', un bactériologiste franco-suisse travaillant pour l'Institut Pasteur, durant une épidémie de peste à Hong Kong, en même temps que Kitasato Shibasaburō mais séparément. Kitasato tout d'abord la baptisa Pasteurella pestis en l'honneur de Pasteur. Ce n'est que plus tard qu'elle prit son nom actuel, en hommage à Yersin.  
 +
12 souches de ''Yersinia pestis'' seront analysées. Les données sont disponible sur le serveur '''silico''' dans le répertoire ''enseignement/m1-bioinfo/Graphe/micropan/Ypestis''. Les protéines en format FASTA sont dans le répertoire ''data/proteins''. Les comparaisons entre paires de génomes sont réalisées à l’aide de '''Blast+''' et une annotation des domaines Pfam des protéines est réalisée avec '''HMMER3'''. Les fichiers pré-calculés sont disponibles dans les répertoires ''blast'' et ''pfam''. Ils sont également disponibles sous forme compressée.
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/homologs.tar.gz homologs.tar.gz]
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/data.tar.gz data.tar.gz]
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/blast.tar.gz blast.tar.gz]
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/pfam.tar.gz pfam.tar.gz]
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/res.tar.gz res.tar.gz]
 +
Dans un premier temps nous allons télécharger my_micropan.R et les archives data et homologs.
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/my_micropan.R my_micropan.R]
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/data.tar.gz data.tar.gz]
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/homologs.tar.gz /homologs.tar.gz]
 +
ou sous linux:
 +
<pre style="color:purple;white-space: pre-wrap;white-space: -moz-pre-wrap;white-space: -pre-wrap;white-space: -o-pre-wrap">
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/my_micropan.R
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/data.tar.gz
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/homologs.tar.gz
 +
</pre>
 +
Vous pouvez effectuer les téléchargements des fichiers dans une Chunk bash dans Rstudio.
 +
<!--
 +
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/blast.tar.gz
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/my_micropan.R
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/res/blast_distances_10_5 res/.
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/res/blast_similarity10_5.txt res/.
 +
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/pfam.tar.gz
 +
-->
Les noms des protéines sont construits de la façon suivante:  
Les noms des protéines sont construits de la façon suivante:  
* Première lettre en majuscule : la première lettre du genre (Y pour ''Yersinia'')  
* Première lettre en majuscule : la première lettre du genre (Y pour ''Yersinia'')  
* Les trois lettres suivantes en minuscule : les trois premières lettres de l’espèce (pes pour ''pestis'')  
* Les trois lettres suivantes en minuscule : les trois premières lettres de l’espèce (pes pour ''pestis'')  
-
* La cinquième lettre majuscule est le code souche (A pour KIM)  
+
* La cinquième lettre majuscule est le code souche (A pour la souche KIM)  
* Les deux chiffres suivant se réfèrent au numéro du chromosome (01 pour le chromosome 1)  
* Les deux chiffres suivant se réfèrent au numéro du chromosome (01 pour le chromosome 1)  
* Un point est utilisé comme séparateur, il est suivit du nom de la protéine
* Un point est utilisé comme séparateur, il est suivit du nom de la protéine
 +
==Mise en œuvre==
==Mise en œuvre==
-
Nous allons utiliser les librairies : '''micropan''' et '''iGraph''' et le fichier my_micropan.R qui contient des fonctions de micropan modifiées pour prendre en compte les préfixes de nos protéines.  
+
Pour la création d'un rapport en format HTML, utilisez la librairie '''knitr''' pour prédéfinir les formats des figures et les valeurs par défaut d'autres paramètres.
 +
 
<source lang='rsplus'>
<source lang='rsplus'>
-
source(“my_micropan.R”)
+
library(knitr)
 +
knitr::opts_chunk$set(fig.align='center', fig.width=6, fig.height=4, fig.path='Figs/', echo=TRUE, warning=FALSE, message=FALSE, cache=TRUE)
</source>
</source>
 +
 +
Définir le répertoire de travail
 +
 +
<source lang='rsplus'>
 +
knitr::opts_knit$set(root.dir = "/home/user/TP5/")
 +
</source>
 +
 +
=== Chargement des fichiers ===
 +
Vous pouvez effectuer les téléchargements des fichiers dans une Chunk bash dans Rstudio.
 +
 +
<source lang='rsplus'>
 +
if [ ! -f my_micropan.R ];
 +
then
 +
  wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/my_micropan.R -nc
 +
else
 +
  echo skip my_micropan.R
 +
fi
 +
if [ ! -d data ];
 +
then
 +
  wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/data.tar.gz -nc
 +
  tar -xvf data.tar.gz
 +
else
 +
  echo skip data
 +
fi
 +
if [ ! -d homologs ];
 +
then
 +
  wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/homologs.tar.gz -nc
 +
  tar -xvf homologs.tar.gz
 +
else
 +
  echo skip homologs
 +
fi
 +
</source>
 +
 +
Nous allons utiliser les librairies : '''igraph''' et le fichier my_micropan.R qui contient des fonctions de micropan modifiées pour prendre en compte les préfixes de nos protéines.
 +
 +
<source lang='rsplus'>
 +
getwd()
 +
list.files()
 +
source("my_micropan.R")
 +
</source>
 +
 +
<source lang='rsplus'>
 +
library(dplyr)
 +
library(igraph)
 +
 +
options (stringsAsFactors = FALSE)
 +
savepar <- par()
 +
par(las=1)
 +
color <- "coral"
 +
</source>
 +
==Tableau de données==
==Tableau de données==
Lecture du tableau décrivant les souches utilisées dans l’analyse.
Lecture du tableau décrivant les souches utilisées dans l’analyse.
 +
<source lang='rsplus'>
<source lang='rsplus'>
-
setwd(root_dir)
 
genome_table_file <- "data/Ypestis.csv"
genome_table_file <- "data/Ypestis.csv"
</source>
</source>
-
*Utilisez la fonction '''read.table()''' pour charger le fichier dans la variable genome_table. Le fichier est tabulé avec un entête.
+
*Utilisez la fonction '''read.table()''' pour charger le fichier dans la variable ''genome_table''. Le fichier est tabulé avec un entête (''sep = "\t" , header= TRUE'').
 +
 
 +
<source lang='rsplus'>
 +
genome_table <- read.table(file=genome_table_file, sep = "\t" , header= TRUE)
 +
head(genome_table)
 +
</source>
Les fichiers contenant les séquences des protéines en format FASTA sont dans le sous répertoire ''data/proteins''. Les noms des fichiers sont dans la première colonne de ''genome_table''.
Les fichiers contenant les séquences des protéines en format FASTA sont dans le sous répertoire ''data/proteins''. Les noms des fichiers sont dans la première colonne de ''genome_table''.
Line 31: Line 118:
Lire chaque fichier FASTA avec la commande '''readLines()'''. Le nombre de protéines est égal au nombre de ‘>’ présents dans le fichier (utilisez '''grep()''' par exemple).
Lire chaque fichier FASTA avec la commande '''readLines()'''. Le nombre de protéines est égal au nombre de ‘>’ présents dans le fichier (utilisez '''grep()''' par exemple).
 +
 +
++
 +
<source lang='rsplus'>
 +
in_files <- c()
 +
for (i in 1:nrow(genome_table) ) {
 +
# file list
 +
in_files[i] <- file.path("data/proteins", genome_table$File[i])
 +
# number of proteins
 +
nb_entries <- length(grep('>', readLines(in_files[i])))
 +
genome_table[i, 5] <- nb_entries
 +
}
 +
colnames(genome_table)[5] <- c('Proteome')
 +
kable(genome_table)
 +
</source>
*Tracer la distribution de la taille des protéomes (avec '''boxplot()''').
*Tracer la distribution de la taille des protéomes (avec '''boxplot()''').
-
==Comparaisons des pairs de protéomes==
+
++
-
Pour chaque pair de génomes (A, B), chaque protéine du génome A est comparée à toutes les protéines du génome B et réciproquement à l’aide de '''BlastP'''. Les alignements avec une E value < 1 sont retenus. Les résultats, sous forme tabulée, sont dans le sous répertoire ''blast''. Les noms des fichiers sont de la forme ''YpesA_vs_YpesB.txt''.
+
<source lang='rsplus'>
 +
rainbowcols <- rainbow(6, s = 0.5)
 +
barplot(table(table(homologs$Query)), ylim=c(0, 50), col = rainbowcols, main='', xlab="nombre d'alignements", ylab="fréquence")
 +
</source>
 +
 
 +
Remarque : le package '''seqinr''' a été développé pour l'exploration, l'analyse et la visualisation des séquences biologiques. Il offre des fonctions pour faciliter la manipulation de fichiers en format FASTA (ex. '''read.fasta()''').
 +
 
 +
=Orthologs 1:1=
 +
Dans un premier temps, nous allons réaliser la recherche de groupes de gènes orthologues avec des fichiers BlastP¨tabulés dans lesquels les liens d'orthologies calculés ont été ajoutés.
 +
==Inspection des liens d'orthologies==
 +
La commande **readBlastTable()** de *micropan* peut être utilisée pour relire les fichiers de sortie de blast en format tabulé.
 +
 
 +
<source lang='rsplus'>
 +
blast.file <- 'homologs/YpesA-YpesB.par'
 +
 
 +
columnames <- c("Query", "Hit", "Percent.identity", "Alignment.length", "Mismatches", "Gap.openings", "Query.start", "Query.end", "Hit.start", "Hit.end", "E.value", "Bit.score", "Homology.type", "Query.length", "Hit.length", "Query.score", "Hit.score","Paire.score")
 +
homologs <- read.table(blast.file, sep = "\t", quote = "", header = F, col.names = columnames, stringsAsFactors = F)
 +
names(homologs)
 +
</source>
 +
 
 +
Trois colonnes ont été ajoutées au fichier de résultats de blastp:
 +
Homology.type, Query.length, Hit.length, Query.score, Hit.score, Paire.score
 +
 
 +
La première colonne donne le type d'homologie : Iso (orthologs 1:1), Ort (orthologs), BeH (Best Hit), IsP (Best BBH paralogs) and BeP (Best paralogs). Les autres colonnes renferment les longueurs des séquences et les scores normalisés par rapport à ces longueurs. 
 +
 
 +
*Combien d'alignement(s) attendez-vous par protéines?
 +
''table(homologs$Query)'' vous donne le nombre de fois qu'une protéine est présente dans le fichier.
 +
*Tracez la distribution du nombre d'alignement par protéine.
 +
 
 +
<source lang='rsplus'>
 +
rainbowcols <- rainbow(6, s = 0.5)
 +
barplot(table(table(homologs$Query)), ylim=c(0, 50), col = rainbowcols, main='', xlab="nombre d'alignements", ylab="fréquence")
 +
</source>
 +
 
 +
*Identifiez la protéine qui a le plus d'alignements et analysez les alignements obtenus.
 +
++
 +
<source lang='rsplus'>
 +
max_hits <- which.max(table(homologs$Query))
 +
subtab <- homologs[homologs$Query == names(max_hits), ]
 +
kable(subtab %>% arrange(Query.start))
 +
</source>
 +
 
 +
*Est-ce que toutes les protéines de A ont un alignement dans B?
 +
++
 +
<source lang='rsplus'>
 +
cat("Sur les ", genome_table[genome_table$File == "YpesA", 5], " proteines de YpesA, seules ", length(unique(homologs$Query)), " ont au moins un alignement avec YpesB.", sep="")
 +
</source>
 +
 
 +
==Extraction du graphe des orthologues 1:1==
 +
Nous allons retenir que les liens du type Homology.type == 'Iso' qui sont des orthologues 1:1.
 +
 
 +
Écriture du graphe dans le fichier "res/iso_gr".
 +
<source lang='rsplus'>
 +
dir.create("res", showWarnings = TRUE)
 +
graph_file <- "res/iso_gr"
 +
if (file.exists(graph_file)) file.remove(graph_file)
 +
 
 +
sum <- 0
 +
blast_files_list <- file.path("homologs", dir("homologs"))
 +
for( i in 1:length(blast_files_list)) {
 +
  blast_file <- blast_files_list[i]
 +
  cat("read blast file", blast_file, "...\n")
 +
  blast_res <- read.table(blast_file, sep = "\t", quote = "", header = F, col.names = columnames, stringsAsFactors = F)
 +
  blast_iso <- blast_res[blast_res$Homology.type == 'Iso', c(1,2)]
 +
  write.table(as.data.frame(blast_iso), file=graph_file, append=TRUE, row.names=FALSE, col.names=FALSE, quote=FALSE)
 +
  sum <- sum + nrow(blast_iso)
 +
}
 +
cat(sum, " rows in files\n")
 +
</source>
 +
 
 +
*Décrivez les différentes étapes réalisées dans votre bloc de commandes.
 +
 
 +
==Traitement du graphe==
 +
Relire ce fichier comme un graphe (fonction ''read.graph()'' de ''igraph'', avec ''format="ncol"'').
 +
 
 +
++
 +
<source lang='rsplus'>
 +
gr <- read.graph(file=graph_file, format="ncol")
 +
</source>
 +
 
 +
Affichez le nombre de sommets et d’arêtes (''vcount()'' et ''ecount()'').
 +
 
 +
++
 +
Le graphe est composé de `r vcount(gr)` sommets et de `r ecount(gr)` arêtes.
 +
 
 +
Appliquez la fonction ''simplify()'' sur le graphe.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
gr_iso <- simplify(gr)
 +
</source>
 +
 
 +
Affichez le nombre de sommets et d’arêtes du graphe simplifié.
 +
 
 +
++
 +
Le graphe simplifié est composé de `r vcount(gr_iso)` sommets et de `r ecount(gr_iso)` arêtes.
 +
 
 +
*Comparez le nombre de sommets et d’arêtes des deux graphes et expliquez les différences observées.
 +
*Quel-est le but de la fonction simplify()?
 +
==Composantes connexes==
 +
Nous allons maintenant extraire les composantes connexes (CC) du graphe à l'aide de la fonction ''decompose.graph()'' en utilisant le ''mode="strong"''.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
iso_cc <- decompose.graph(gr_iso, mode="strong")
 +
</source>
 +
 
 +
La liste des objets graphe sera conservée dans la variable ''iso_cc''.
 +
 
 +
''iso_cc'' est la liste des CC du graphe.
 +
<source lang='rsplus'>iso_cc[[i]]</source> est la ième CC.
 +
 
 +
==Propriétés des composantes connexes==
 +
 
 +
Calculez le nombre de nœuds et le nombre d'arêtes de chaque CC et représentez graphiquement le résultat.
 +
 
 +
Vous pouvez utiliser ''lapply()'' sur la liste de CC pour calculer le nombre de sommets et le nombre d'arêtes de chaque CC.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
iso_cc_property <- cbind(unlist(lapply(iso_cc, vcount)), unlist(lapply(iso_cc, ecount)))
 +
colnames(iso_cc_property) <- c("vertex", "edges")
 +
vmax <- max(iso_cc_property[,1])
 +
 
 +
plot(iso_cc_property[iso_cc_property[,1] <= vmax, ], las=1, xlim=c(0, vmax), pch=20, col="coral")
 +
</source>
 +
 
 +
*Quel est le nombre d'arêtes maximum d'un graphe en fonction du nombre de sommets?
 +
*Ajoutez la courbe correspondant au nombre d'arêtes maximum d'un graphe en fonction du nombre de sommets (fonction ''curve()'').
 +
 
 +
++
 +
<source lang='rsplus'>
 +
xlimit <- 22
 +
curve(<fonction(x)>, from = 0, to = xlimit, n = 200, col="purple", add=T)
 +
</source>
 +
 
 +
*A quoi correspondent les zones du graphe délimitées par cette courbe et quelle est la propriété des CC localisées sur la courbe?
 +
*Quel est le nombre maximum de sommets pour qu'une CC soit une clique dans notre jeu de données?
 +
*Combien de CC de ce type sont observées dans le jeu de données?
 +
 
 +
++
 +
<source lang='rsplus'>
 +
table(iso_cc_property[,1], iso_cc_property[,2])
 +
cross <- table(iso_cc_property[,1], iso_cc_property[,2])
 +
# arr.ind logical; should array indices be returned when x is an array?
 +
maxidx <- which(cross == max(cross), arr.ind = TRUE)
 +
maxrow <- rownames(cross)[maxidx[1]]
 +
maxcol <- colnames(cross)[maxidx[2]]
 +
#cat("Il y a ", max(cross), " CC composées de ", maxrow, " sommets et ", maxcol, " arêtes (", max(cross)/length(iso_cc)*100, "% des CC)", sep="")
 +
</source>
 +
 
 +
*Représentez graphiquement une clique.
 +
 +
<source lang='rsplus'>
 +
iso_cc[[5]]</source> par exemple.
 +
<source lang='rsplus'>
 +
myiso_cc <- iso_cc[[5]]
 +
plot.igraph(myiso_cc, vertex.shape="sphere", vertex.size=15, vertex.label.cex=0.8, vertex.label.dist=0, edge.color="red")
 +
</source>
 +
 
 +
Un embellissement!
 +
 
 +
<source lang='rsplus'>
 +
myiso_cc <- iso_cc[[5]]
 +
local_gene_list <- substr(V(myiso_cc)$name, 5, 5)
 +
local_strain_list <- unique(local_gene_list)
 +
tocolor <- unlist(lapply(local_gene_list, function(x,y) grep(x, y), local_strain_list))
 +
mycolor = rainbow(length(local_strain_list));
 +
palette(mycolor);
 +
plot.igraph(myiso_cc, vertex.shape="sphere", vertex.size=15, vertex.color=tocolor, vertex.label.cex=0.8, vertex.label=local_gene_list, vertex.label.dist=0, vertex.label.color="white", edge.color="red", edge.width=E(myiso_cc)$weight)
 +
</source>
 +
 
 +
*Décrivez les différentes étapes réalisées dans ce bloc de commandes.
 +
 
 +
*Combien de sommets et d'arêtes possède la CC 5?
 +
 
 +
==Taux de paralogie==
 +
 
 +
Nous allons écrire une fonction qui calcule le taux de gènes paralogues dans une liste de gènes. Pour cela nous allons
 +
  compter le nombre de gènes G présent dans la liste,
 +
  en extraire le nombre de souches S.
 +
S'il n'y a pas de paralogue, chaque souche est représentée par un seul gène (G=S), sinon (G>S), on a plus d'un gène par souche.
 +
 
 +
Pour estimer le taux de paralogues, on divise la différence entre nombre de gènes et nombre de souches (G-S) par le nombre de gènes G.
 +
 
 +
Les fonctions à utiliser sont :
 +
  **substr()** pour extraire le nom de souche à partir du nom de gène
 +
  **unique()** pour obtenir le nombre de souche.
 +
L'expression `V(graph)$name` permet d'obtenir la liste des sommets du graphe.
 +
<source lang='rsplus'>
 +
count_paralogs <- function(lst)
 +
{
 +
  ...
 +
  return(paralogs)
 +
}
 +
</source>
 +
++
 +
<source lang='rsplus'>
 +
count_paralogs <- function(lst)
 +
{
 +
  all_strains <- substr(lst,1,5)
 +
  strain_list <- unique(all_strains)
 +
  paralogs <- (length(all_strains) - length(strain_list))/length(all_strains)
 +
  return(paralogs)
 +
}
 +
</source>
 +
 
 +
==Distribution de la paralogie==
 +
 
 +
Représentez la distribution de la paralogie dans les CC.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
pdm1 <- data.frame(Vcount=numeric(), Pcount=numeric())
 +
j <- 0
 +
for (i in 1:length(iso_cc))
 +
{
 +
cc_num    <- i
 +
CC        <- iso_cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
 
 +
j <- j+1
 +
list_name <- V(CC)$name
 +
 
 +
  pdm1[j, 1] <- vcount(CC)
 +
pdm1[j, 2] <- round(count_paralogs(list_name), 3)
 +
}
 +
hist(pdm1$Pcount, nclass=10)
 +
</source>
 +
 
 +
Tracez le taux de paralogie des CC en fonction du nombre de sommets.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
vmax <- max(pdm1$Vcount)
 +
plot(pdm1[,c(1,2)], las=1, pch=20, col=color, ylim=c(0,1))
 +
</source>
 +
 
 +
*Quelle est le taux minimum de paralogie en fonction du nombre de protéines par CC?
 +
*Tracez la courbe correspondante.
 +
 
 +
++
 +
Jusqu'à 12 protéines présentes (le nombre de souches) le taux minimum de paralogie est de 0. Au-delà, il est minimum si toutes les souches sont présentes au moins une fois.
 +
 
 +
<source lang='rsplus'>
 +
vmax <- max(pdm1$Vcount)
 +
plot(pdm1[,c(1,2)], las=1, pch=20, col=color, ylim=c(0,1))
 +
curve((x-nrow(genome_table))/x, from=nrow(genome_table), to=vmax, n=200, col="purple", add=T)
 +
</source>
 +
 
 +
==Modularité des CC==
 +
 
 +
Nous pouvons calculer la modularité d'un graphe avec la fonction ''cluster_fast_greedy()'' d'igraph (''fastgreedy.community()'' suivant la version). La modularité du graphe est donnée par `max(fastgreedy$modularity)`.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
pdm2 <- data.frame(Vcount=numeric(), Pcount=numeric(), Density=numeric(), Modularity=numeric())
 +
j <- 0
 +
for (i in 1:length(iso_cc))
 +
{
 +
cc_num    <- i
 +
CC        <- iso_cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
 
 +
j <- j+1
 +
list_name <- V(CC)$name
 +
fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
 +
 +
  pdm2[j, 1] <- vcount(CC)
 +
pdm2[j, 2] <- count_paralogs(list_name)
 +
pdm2[j, 3] <- graph.density(CC,loops=FALSE)
 +
pdm2[j, 4] <- max(fastgreedy$modularity)
 +
}
 +
kable(head(pdm2))
 +
</source>
 +
 
 +
*Tracer la distribution de Q.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
hist(pdm2$Modularity, nclass=10, col=color, ylim=c(0, 50))
 +
</source>
 +
 
 +
*Tracez la modularité des CC en fonction du taux de paralogie.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
plot(pdm2[,c(2,4)], las=1, pch=20, col=color)
 +
</source>
 +
 
 +
*Ajoutez la droite de régression *Modularity* en fonction de *Pcount*.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
cor <- lm(pdm2$Modularity ~ pdm2$Pcount)
 +
summary(cor)
 +
plot(pdm2[,c(2,4)], las=1, pch=20, xlim=c(0,1), ylim=c(0,1), col=color)
 +
curve(cor$coefficients[2]*x +cor$coefficients[1], from=0.05, to=1, col="purple", add=T)
 +
</source>
 +
 
 +
*Commentez le résultat obtenu.
 +
 
 +
==Partitionnement en communautés==
 +
Plusieurs méthodes sont disponibles dans igraph pour partitionner un graphe en communautés. Nous allons, dans un premier temps, comparer les méthodes fastgreedy, walktrap, edge betweenness et louvain. Ces méthodes sont utilisées de façon similaire (vous pouvez ajouter la méthode cluster_leiden si elle disponible dans votre version d'igraph):
 +
 
 +
*`fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)`
 +
*`walktrap <- cluster_walktrap(CC, modularity=TRUE)`
 +
*`edge <-  cluster_edge_betweenness(CC, modularity=TRUE)`
 +
*`louvain    <- cluster_louvain(CC)`
 +
 
 +
Le nombre de communautés trouvée dans la CC j peut être obtenu avec *length(méthode)*.
 +
*`size[j, 1] <- length(fastgreedy)`
 +
*`size[j, 2] <- length(walktrap)`
 +
*`size[j, 3] <- length(edge)`
 +
*`size[j, 4] <- length(louvain)`
 +
 
 +
avec la modularité Q associée:
 +
*`Modularity5[j, 1] <- round(max(fastgreedy$modularity), 3)`
 +
*`Modularity5[j, 2] <- round(max(walktrap$modularity), 3)`
 +
*`Modularity5[j, 3] <- round(max(edge$modularity), 3)`
 +
*`Modularity5[j, 4] <- round(max(edge$modularity), 4)`
 +
 
 +
===Un exemple avec fastgreedy===
 +
Un exemple simple:
 +
<source lang='rsplus'>
 +
stop = 100
 +
for (cc_num in 2:stop) {
 +
  CC <- iso_cc[[cc_num]]
 +
  fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
 +
  Q = round(max(fastgreedy$modularity), 3)
 +
  cat("CC", cc_num, " modularité", Q, "\n")
 +
}
 +
</source>
 +
 
 +
Un code un peu plus complexe:
 +
<source lang='rsplus'>
 +
vmin <- 12
 +
vmax <- max(sapply(iso_cc, vcount, simplify=TRUE))
 +
edgecolor <- "red"
 +
 
 +
pdm5 <- data.frame(Vcount=numeric(), Pcount=numeric())
 +
Modularity5 <- data.frame(fastgreedy=numeric())
 +
Size5 <- data.frame(fastgreedy=numeric())
 +
 
 +
j <- 0
 +
for (i in 2:length(iso_cc)) {
 +
cc_num    <- i
 +
CC        <- iso_cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
if ( nb_vertex > vmin && nb_vertex <= vmax ) {
 +
 
 +
fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
 +
Q = round(max(fastgreedy$modularity), 3)
 +
if ( Q > 0.45 ) {
 +
j <- j+1
 +
list_name <- V(CC)$name     
 +
pdm5[j, 1] <- cc_num
 +
pdm5[j, 2] <- nb_vertex
 +
pdm5[j, 3] <- count_paralogs(list_name)
 +
 
 +
Modularity5[j, 1] <- Q
 +
Size5[j, 1] <- length(fastgreedy)
 +
 
 +
cat("CC", cc_num, vcount(CC), Modularity5[j, 1], Modularity5[j, 2], Modularity5[j, 3], Modularity5[j, 4], "\n")
 +
 
 +
Layout <- layout.fruchterman.reingold(CC)
 +
titre <- paste(cc_num, "fastgreedy", round(Modularity5[j, 1],2), Size5[j, 1], sep=" ")
 +
plot(fastgreedy, CC, layout=Layout,
 +
vertex.label=NA, vertex.size=3, vertex.shape="sphere",
 +
edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 +
 
 +
cat ("Press [enter] to continue or quit")
 +
line <- readline()
 +
if ( line == 'quit') stop("user interruption")
 +
}
 +
}
 +
}
 +
</source>
 +
Réinitialiser ''layout''
 +
<source lang='rsplus'>
 +
par <- par(mar=c(5.1,4.1,4.1,2.1))
 +
layout(1)
 +
</source>
 +
 
 +
Avec un code couleur pour les souches:
 +
<!--
 +
<source lang='rsplus'>
 +
vmin <- 12
 +
vmax <- max(sapply(iso_cc, vcount, simplify=TRUE))
 +
edgecolor <- "red"
 +
 +
pdm5 <- data.frame(Vcount=numeric(), Pcount=numeric())
 +
Modularity5 <- data.frame(fastgreedy=numeric())
 +
Size5 <- data.frame(fastgreedy=numeric())
 +
 +
j <- 0
 +
for (i in 2:length(iso_cc)) {
 +
cc_num    <- i
 +
CC        <- iso_cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
if ( nb_vertex > vmin && nb_vertex <= vmax ) {
 +
list_name <- V(CC)$name
 +
fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
 +
Q = round(max(fastgreedy$modularity), 3)
 +
if ( Q > 0.3 ) {
 +
j <- j+1
 +
 +
pdm5[j, 1] <- cc_num
 +
pdm5[j, 2] <- vcount(CC)
 +
pdm5[j, 3] <- count_paralogs(list_name)
 +
 +
Modularity5[j, 1] <- Q
 +
Size5[j, 1] <- length(fastgreedy)
 +
 +
cat("CC", cc_num, vcount(CC), Modularity5[j, 1], Modularity5[j, 2], Modularity5[j, 3], Modularity5[j, 4], "\n")
 +
 +
local_gene_list <- substr(V(CC)$name, 5, 5)
 +
local_strain_list <- unique(local_gene_list)
 +
tocolor <- unlist(lapply(local_gene_list, function(x,y) grep(x, y), local_strain_list))
 +
 
 +
Layout <- layout.fruchterman.reingold(CC)
 +
titre <- paste(cc_num, "fastgreedy", round(Modularity5[j, 1],2), Size5[j, 1], sep=" ")
 +
plot(CC, layout=Layout,
 +
    vertex.size=15, vertex.shape="sphere", vertex.color=tocolor,
 +
    vertex.label.cex=0.8, vertex.label=local_gene_list, vertex.label.dist=0,
 +
    edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 +
 +
cat ("Press [enter] to continue or quit")
 +
line <- readline()
 +
if ( line == 'quit') stop("user interruption")
 +
}
 +
}
 +
}
 +
</source>
 +
-->
 +
 
 +
===Ajouter les autres méthodes===
 +
Le principe :
 +
<source lang='rsplus'>
 +
stop = length(iso_cc)
 +
for (cc_num in 2:stop) {
 +
  CC <- iso_cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
  fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
 +
  Q = round(max(fastgreedy$modularity), 2)
 +
  if ( Q > 0.45 ) {
 +
    list_name <- V(CC)$name
 +
    P <- round(count_paralogs(list_name), 2)
 +
 
 +
    walktrap <- walktrap.community(CC, modularity=TRUE)
 +
    W <- round(max(walktrap$modularity), 2)
 +
    edge <- edge.betweenness.community(CC, modularity=TRUE)
 +
    E <- round(max(edge$modularity), 2)
 +
    louvain <- cluster_louvain(CC)
 +
    L <- round(max(louvain$modularity), 2)
 +
    cat("CC", cc_num, nb_vertex, P, Q, W, E, L, "\n")
 +
  }
 +
}
 +
</source>
 +
l'application:
 +
 
 +
++
 +
<source lang='rsplus'>
 +
par(mar=c(1,1,1,1))
 +
layout(matrix(1:4, 1, 4))
 +
vmin <- 12
 +
vmax <- max(sapply(iso_cc, vcount, simplify=TRUE))
 +
edgecolor <- "red"
 +
pdm5 <- data.frame(CC=numeric(), Vcount=numeric(), Pcount=numeric())
 +
Modularity5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric())
 +
Size5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric())
 +
 
 +
j <- 0
 +
for (i in 2:length(iso_cc))
 +
{
 +
cc_num    <- i
 +
CC        <- iso_cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
if ( nb_vertex > vmin && nb_vertex <= vmax ) {
 +
list_name <- V(CC)$name
 +
#fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
 +
fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
 +
if ( max(fastgreedy$modularity) > 0.45 ) {
 +
j <- j+1
 +
walktrap  <- cluster_walktrap(CC, modularity=TRUE)
 +
edge      <- cluster_edge_betweenness(CC, modularity=TRUE)
 +
louvain    <- cluster_louvain(CC)
 +
 
 +
     
 +
pdm5[j, 1] <- cc_num
 +
pdm5[j, 2] <- vcount(CC)
 +
pdm5[j, 3] <- count_paralogs(list_name)
 +
 
 +
  Modularity5[j, 1] <- round(max(fastgreedy$modularity), 3)
 +
  Modularity5[j, 2] <- round(max(walktrap$modularity), 3)
 +
  Modularity5[j, 3] <- round(max(edge$modularity), 3)
 +
  Modularity5[j, 4] <- round(max(louvain$modularity), 3)
 +
 
 +
  if ( min(Modularity5[j,]) < max(Modularity5[j,])) {
 +
  Size5[j, 1] <- length(fastgreedy)
 +
  Size5[j, 2] <- length(walktrap)
 +
  Size5[j, 3] <- length(edge)
 +
  Size5[j, 4] <- length(louvain)
 +
 
 +
 
 +
 
 +
   
 +
    #cat("CC", cc_num, vcount(CC), Modularity5[j, 1], Modularity5[j, 2], Modularity5[j, 3], "\n")
 +
 
 +
  Layout = layout.fruchterman.reingold(CC)
 +
  titre <- paste(cc_num, "fastgreedy", round(Modularity5[j, 1],3), Size5[j, 1], sep=" ")
 +
  plot(fastgreedy, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 +
 
 +
  titre <- paste("walktrap",  round(Modularity5[j, 2],3), Size5[j, 2], sep=" ")
 +
  plot(walktrap, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 +
 
 +
  titre <- paste("edge",  round(Modularity5[j, 3],3), Size5[j, 3], sep=" ")
 +
  plot(edge, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 +
 
 +
  titre <- paste("louvain",  round(Modularity5[j, 4],3), Size5[j, 3], sep=" ")
 +
  plot(louvain, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 +
       
 +
  cat ("Press [enter] to continue or quit")
 +
  line <- readline()
 +
  if ( line == 'quit') stop()
 +
  }
 +
}
 +
}
 +
}
 +
 
 +
par <- par(mar=c(5.1,4.1,4.1,2.1))
 +
layout(1)
 +
</source>
 +
 
 +
===spinglass===
 +
La méthode spinglass repose sur un plus grand nombre de paramètres:
 +
<source lang='rsplus'>
 +
spinglass <- cluster_spinglass(CC, spins=my_spins, start.temp=start_temp, stop.temp=stop_temp, cool.fact=cool_fact, update.rule=update.rule, gamma=my_gamma)`
 +
</source>
 +
 
 +
====Illustration avec la CC 1584====
 +
<source lang='rsplus'>
 +
my_gamma <- 1
 +
my_spins <- 25
 +
stop_temp <- 0.8
 +
start_temp <- 1
 +
cool_fact <- 0.95
 +
update.rule <- "config"
 +
iter <- 100
 +
 
 +
# test
 +
CC <- iso_cc[[1584]]
 +
Qiter <- array(0, c(iter))
 +
spinglass_iter <- list()
 +
 
 +
for ( k in 1:iter )  {
 +
spinglass <- cluster_spinglass(CC, weights=E(CC)$weight+10, spins=my_spins,
 +
start.temp=start_temp, stop.temp=stop_temp,
 +
cool.fact=cool_fact, update.rule=update.rule,
 +
gamma=my_gamma)
 +
Qiter[k] <- modularity(spinglass)
 +
spinglass_iter[[k]] <- spinglass
 +
}
 +
step <- which.max(Qiter)
 +
membership <- membership(spinglass_iter[[step]])
 +
modularity <- round(max(Qiter), 3)
 +
</source>
 +
Distribution de Q en fonction des itérations :
 +
<source lang='rsplus'>
 +
plot(Qiter, ylim=c(0,1), xlab="iteration", ylab="Modularity")
 +
hist(Qiter, col=color, xlim=c(0,1))
 +
</source>
 +
*Diminuez la valeur de ''stop.temp'' (0.4 par exemple). Que pouvez-vous observer?
 +
 
 +
====Assemblage des cinq méthodes====
 +
Nous allons fixer les paramètres suivant:
 +
<pre>
 +
  `my_gamma <- 1`
 +
  `my_spins <- 25`
 +
  `stop_temp <- 0.8`
 +
  `start_temp <- 1`
 +
  `cool_fact <- 0.95`
 +
  `update.rule <- "config"`
 +
</pre>
 +
et nous allons réitérer spinglass 10 fois pour chaque CC. L'itération maximisant la modularité sera conservée. 
 +
<pre>
 +
  `iter <- 10`
 +
</pre>
 +
*Assemblez les cinq méthodes dans un seul bloc.
 +
 
 +
Principe :
 +
<source lang='rsplus'>
 +
my_gamma <- 1
 +
my_spins <- 25
 +
stop_temp <- 0.1
 +
start_temp <- 1
 +
cool_fact <- 0.95
 +
update.rule <- "config"
 +
iter <- 10
 +
 
 +
stop = length(iso_cc)
 +
for (cc_num in 2:stop) {
 +
  CC <- iso_cc[[cc_num]]
 +
  nb_vertex <- vcount(CC)
 +
  fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
 +
  Q = round(max(fastgreedy$modularity), 2)
 +
  if ( Q > 0.45 ) {
 +
    list_name <- V(CC)$name
 +
    P <- round(count_paralogs(list_name), 2)
 +
 
 +
    walktrap <- walktrap.community(CC, modularity=TRUE)
 +
    W <- round(max(walktrap$modularity), 2)
 +
    edge <- edge.betweenness.community(CC, modularity=TRUE)
 +
    E <- round(max(edge$modularity), 2)
 +
    louvain <- cluster_louvain(CC)
 +
    L <- round(max(louvain$modularity), 2)
 +
 +
    Qiter <- array(0, c(iter))
 +
    spinglass_iter <- list() 
 +
    for ( k in 1:iter ) {
 +
      spinglass <- spinglass.community(CC, , spins=my_spins,
 +
        start.temp=start_temp, stop.temp=stop_temp,
 +
        cool.fact=cool_fact, update.rule=update.rule,
 +
        gamma=my_gamma)
 +
      Qiter[k] <- modularity(spinglass)
 +
      spinglass_iter[[k]] <- spinglass
 +
    }
 +
    S <- round(max(Qiter), 2)
 +
    if ( min(qiter) < max(qiter)) {
 +
      cat("CC", cc_num, nb_vertex, P, Q, W, E, L, S, "\n")
 +
    }
 +
  }
 +
}
 +
</source>
 +
l'ensemble
 +
 
 +
++
 +
<source lang='rsplus'>
 +
par(mar=c(1,1,1,1))
 +
layout(matrix(1:5, 1, 5))
 +
vmin <- 12
 +
vmax <- max(sapply(iso_cc, vcount, simplify=TRUE))
 +
pdm5 <- data.frame(cc_num=numeric(), Vcount=numeric(), Pcount=numeric())
 +
Modularity5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric(), spinglass=numeric())
 +
Size5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric(), spinglass=numeric())
 +
 +
my_gamma <- 1
 +
my_spins <- 25
 +
stop_temp <- 0.1
 +
start_temp <- 1
 +
cool_fact <- 0.95
 +
update.rule <- "config"
 +
iter <- 10
 +
 +
j <- 0
 +
for (i in 2:length(iso_cc))
 +
{
 +
cc_num    <- i
 +
CC        <- iso_cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
if ( nb_vertex > vmin && nb_vertex <= vmax ) {
 +
list_name <- V(CC)$name
 +
fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
 +
if ( max(fastgreedy$modularity) > 0.3 ) {
 +
j <- j+1
 +
walktrap  <- cluster_walktrap(CC, modularity=TRUE)
 +
edge      <- cluster_edge_betweenness(CC, modularity=TRUE)
 +
louvain    <- cluster_louvain(CC)
 +
 +
Qiter <- array(0, c(iter))
 +
spinglass_iter <- list() 
 +
for ( k in 1:iter ) {
 +
spinglass <- cluster_spinglass(CC, , spins=my_spins,
 +
start.temp=start_temp, stop.temp=stop_temp,
 +
cool.fact=cool_fact, update.rule=update.rule,
 +
gamma=my_gamma)
 +
Qiter[k] <- modularity(spinglass)
 +
spinglass_iter[[k]] <- spinglass
 +
}
 +
step <- which.max(Qiter)
 +
membership <- membership(spinglass_iter[[step]])
 +
 +
pdm5[j, 1] <- cc_num
 +
pdm5[j, 2] <- vcount(CC)
 +
pdm5[j, 3] <- count_paralogs(list_name)
 +
 +
Modularity5[j, 1] <- round(max(fastgreedy$modularity), 3)
 +
Modularity5[j, 2] <- round(max(walktrap$modularity), 3)
 +
Modularity5[j, 3] <- round(max(edge$modularity), 3)
 +
Modularity5[j, 4] <- round(max(louvain$modularity), 3)
 +
Modularity5[j, 5] <- round(max(Qiter), 3)
 +
 +
Size5[j, 1] <- length(fastgreedy)
 +
  Size5[j, 2] <- length(walktrap)
 +
Size5[j, 3] <- length(edge)
 +
Size5[j, 4] <- length(edge)
 +
Size5[j, 5] <- length(unique(membership))
 +
 +
#cat("CC", cc_num, vcount(CC), Modularity5[j, 1], Modularity5[j, 2], Modularity5[j, 3], Modularity5[j, 4], "\n")
 +
      #if ( Modularity5[j, 5] > min(Modularity5[j,])) {
 +
  Layout = layout.fruchterman.reingold(CC)
 +
  titre <- paste(cc_num, "fastgreedy", round(Modularity5[j, 1],3), Size5[j, 1], sep=" ")
 +
  plot(fastgreedy, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 +
 
 +
  titre <- paste("walktrap",  round(Modularity5[j, 2],3), Size5[j, 2], sep=" ")
 +
  plot(walktrap, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 +
 
 +
  titre <- paste("edge",  round(Modularity5[j, 3],3), Size5[j, 3], sep=" ")
 +
  plot(edge, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 +
 
 +
  titre <- paste("louvain",  round(Modularity5[j, 4],3), Size5[j, 3], sep=" ")
 +
  plot(louvain, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 +
 +
  titre <- paste("spinglass",  round(Modularity5[j, 4],3), Size5[j, 4], sep=" ")
 +
  plot(spinglass_iter[[step]], CC, layout=Layout, vertex.label=NA, vertex.size=3, edge.color='grey', edge.width=E(CC)$weight, main=titre)
 +
  cat ("Press [enter] to continue or quit")
 +
  line <- readline()
 +
  #if ( line == 'quit') stop()
 +
  #}
 +
}
 +
}
 +
}
 +
par <- par(mar=c(5.1,4.1,4.1,2.1))
 +
layout(1)
 +
</source>
 +
 
 +
Pour chaque CC triez les méthodes en fonction des modularités obtenues.
 +
Représentez graphiquement les résultats.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
Modu_stat <- apply(Modularity5, 1, function(x) rank(signif(x[1:5], digits=5), ties.method = "max"))
 +
 
 +
# fréquence des différents rangs
 +
Modu_tab <- apply(Modu_stat, 1, function(x) {
 +
  his <- hist(x, breaks=(0:5), plot=F)
 +
  his$count
 +
})
 +
rainbowcols <- rainbow(5, s = 0.2)
 +
barplot(Modu_tab, col=rainbowcols, ylab="frequency", ylim=c(0,25))
 +
</source>
 +
 
 +
Pour chaque CC triez les méthodes en fonction du nombre de communautés obtenues.
 +
Représentez graphiquement les résultats.
 +
 
 +
++
 +
<source lang='rsplus'>
 +
Size_stat <- apply(Size5, 1, function(x) rank(signif(x[1:4], digits=5), ties.method = "max"))
 +
 
 +
Size_tab <- apply(Size_stat, 1, function(x) {
 +
  his <- hist(x,breaks=(0:4), plot=F)
 +
  his$count
 +
})
 +
barplot(Size_tab)
 +
</source>
 +
 
 +
*Commentez les résultats.
 +
 
 +
Pour obtenir les résultats sur toutes les CC, relancez la boucle en supprimant le test:
 +
<source lang='rsplus'>
 +
      cat ("Press [enter] to continue or quit")
 +
      line <- readline()
 +
      if ( line == 'quit') stop()
 +
</source>
 +
 
 +
*Tracez les deux plots et commentez les résultats obtenus avec les CC de taille supérieur à 12 arêtes!
 +
 
 +
=End=
 +
<!--
 +
=BlastP scores=
 +
==Comparaisons des paires de protéomes==
 +
Pour chaque paire de génomes (A, B), chaque protéine du génome A est comparée à toutes les protéines du génome B et réciproquement à l’aide de '''BlastP'''. Les alignements avec une E value < 1 sont retenus. Les résultats, sous forme tabulée, sont dans le sous répertoire ''blast''. Les noms des fichiers sont de la forme ''YpesA_vs_YpesB.txt''.
*Pourquoi utiliser les protéines à la place des gènes?
*Pourquoi utiliser les protéines à la place des gènes?
Line 50: Line 922:
</source>
</source>
-
Nous utiliserons les résultats pré-calculés présents dans le répertoire blast.
+
La méthode spinglass repose sur un plus grand nombre de paramètres:
 +
*`spinglass <- cluster_spinglass(CC, spins=my_spins, start.temp=start_temp, stop.temp=stop_temp, cool.fact=cool_fact, update.rule=update.rule, gamma=my_gamma)`
 +
 
 +
Nous allons fixer les paramètres suivant:
 +
 
 +
<pre>
 +
  `my_gamma <- 1`
 +
  `my_spins <- 25`
 +
  `stop_temp <- 0.1`
 +
  `start_temp <- 1`
 +
  `cool_fact <- 0.95`
 +
  `update.rule <- "config"`
 +
</pre>
 +
et nous allons réitérer spinglass 10 fois pour chaque CC. L'itération maximisant la modularité sera conservée. 
 +
<pre>
 +
  `iter <- 10`
 +
</pre>
 +
Boucle pour spinglass:
 +
 
 +
<source lang='rsplus'>
 +
  my_gamma <- 1
 +
  my_spins <- 25
 +
  stop_temp <- 0.1
 +
  start_temp <- 1
 +
  cool_fact <- 0.95
 +
  update.rule <- "config"
 +
  iter <- 10
 +
 
 +
  # test
 +
  CC <- iso_cc[[1584]]
 +
  Qiter <- array(0, c(iter))
 +
  spinglass_iter <- list()
 +
 
 +
  for ( k in 1:iter )
 +
  {
 +
  spinglass <- cluster_spinglass(CC, weights=E(CC)$weight+10, spins=my_spins,
 +
            start.temp=start_temp, stop.temp=stop_temp,
 +
            cool.fact=cool_fact, update.rule=update.rule,
 +
            gamma=my_gamma)
 +
    Qiter[k] <- modularity(spinglass)
 +
    spinglass_iter[[k]] <- spinglass
 +
  }
 +
  step <- which.max(Qiter)
 +
  membership <- membership(spinglass_iter[[step]])
 +
  modularity <- round(max(Qiter), 3)
 +
</source>
==Inspection des résultats du BlastP All/All==
==Inspection des résultats du BlastP All/All==
Line 86: Line 1,003:
Pour une meilleur représentation, vous pouvez basculer l’histogramme (horiz=T). Il peut être nécessaire de redéfinir les marges du graphe (mar=c(5.1,20.1,4.1,2.1))
Pour une meilleur représentation, vous pouvez basculer l’histogramme (horiz=T). Il peut être nécessaire de redéfinir les marges du graphe (mar=c(5.1,20.1,4.1,2.1))
-
==Distances entre les pairs de gènes==
+
==Distances entre les paires de gènes==
-
Le package micropan a une fonction ('''bDist()''') qui permet de calculer les distances entre pairs de gènes à partir des résultats des '''BlatsP'''. Se reporter au paragraphe BLAST distances de Microbial pangenomics in R - A case study.
+
Le package micropan a une fonction ('''bDist()''') qui permet de calculer les distances entre paires de gènes à partir des résultats des '''BlatsP'''. Se reporter au paragraphe BLAST distances de Microbial pangenomics in R - A case study.
-
Un filtre sur les E values peut être utilisé. (evalue < 1e-05). Cette distance est normalisée entre 0 et 1. La fonction '''file.path()''' renvoie la liste des fichiers présents dans un répertoire (ici ''blast''). La fonction '''mybDist'''(blast_files, e.value = threshold) renvoie un ''data.frame'' avec les distances calculées entre pairs de protéines pour toutes les comparaisons (''blast_files'').
+
Un filtre sur les E values peut être utilisé. (evalue < 1e-05). Cette distance est normalisée entre 0 et 1. La fonction '''file.path()''' renvoie la liste des fichiers présents dans un répertoire (ici ''blast''). La fonction '''mybDist'''(blast_files, e.value = threshold) renvoie un ''data.frame'' avec les distances calculées entre paires de protéines pour toutes les comparaisons (''blast_files'').
Le data.frame peut être “sauvée” dans un fichier avec la fonction '''save()''' et rechargé avec la fonction '''load()'''.
Le data.frame peut être “sauvée” dans un fichier avec la fonction '''save()''' et rechargé avec la fonction '''load()'''.
Line 105: Line 1,022:
*Tracez la distribution des similarités (vérification!).  
*Tracez la distribution des similarités (vérification!).  
-
*Ecrire les pairs de similarités dans un fichier sous la forme d’une table ('''write.table()''').
+
*Ecrire les paires de similarités dans un fichier sous la forme d’une table ('''write.table()''').
==Graphe==
==Graphe==
Line 196: Line 1,113:
==Partitionnement en communautés==
==Partitionnement en communautés==
Plusieurs méthodes sont disponibles dans igraph pour partitionner un graphe en communautés. Nous allons, dans un premier temps, comparer les méthodes fastgreedy, walktrap et edge betweenness. Ces trois méthodes sont utilisées de façon similaire:
Plusieurs méthodes sont disponibles dans igraph pour partitionner un graphe en communautés. Nous allons, dans un premier temps, comparer les méthodes fastgreedy, walktrap et edge betweenness. Ces trois méthodes sont utilisées de façon similaire:
-
   `fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)`
+
<source lang='rsplus'>
-
   `walktrap <- cluster_walktrap(CC, modularity=TRUE)`
+
   fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
-
   `edge <-  cluster_edge_betweenness(CC, modularity=TRUE)`
+
   walktrap <- cluster_walktrap(CC, modularity=TRUE)
 +
   edge <-  cluster_edge_betweenness(CC, modularity=TRUE)
 +
</source>
 +
 
 +
<source lang='rsplus'>
 +
vmin = 24
 +
vmax = 50
 +
pdm <- data.frame(Vcount=numeric(), Pcount=numeric())
 +
Modularity <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric())
 +
 
 +
j <- 0
 +
for (i in 2:length(cc))
 +
{
 +
    cc_num    <- i
 +
    CC        <- cc[[cc_num]]
 +
    nb_vertex <- vcount(CC)
 +
    if ( nb_vertex > vmin && nb_vertex <= vmax ) {
 +
        list_name <- V(CC)$name
 +
        fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
 +
        if ( max(fastgreedy$modularity) > 0.3 ) {
 +
        j <- j+1
 +
      walktrap  <- cluster_walktrap(CC, modularity=TRUE)
 +
      edge      <- cluster_edge_betweenness(CC, modularity=TRUE)
 +
       
 +
        pdm[j, 1] <- cc_num
 +
        pdm[j, 2] <- vcount(cc[[i]])
 +
        pdm[j, 3] <- count_paralogs(list_name)
 +
       
 +
        Modularity[j, 1] <- max(fastgreedy$modularity)
 +
        Modularity[j, 2] <- max(walktrap$modularity)
 +
        Modularity[j, 3] <- max(edge$modularity)
 +
       
 +
        cat("CC", cc_num, vcount(CC), Modularity[j, 1], Modularity[j, 2], Modularity[j, 3], "\n")
 +
        }
 +
    }
 +
}
 +
</source>
 +
 
 +
==Comparaison des méthodes==
 +
===Modularité===
 +
*Pour chaque CC triez les méthodes  en fonction des modularités obtenues.
 +
*Représentez graphiquement les résultats.
 +
<source lang='rsplus'>
 +
Modu_stat <- apply(Modularity, 1, function(x) rank(signif(x[1:3], digits=3), ties.method = "max"))
 +
Modu_tab <- apply(Modu_stat, 1, function(x) {
 +
  his <- hist(x,breaks=(0:3), plot=F)
 +
  his$count
 +
})
 +
barplot(Modu_tab)
 +
</source>
 +
===Nombre de communautés===
 +
 
 +
Le nombre de communautés trouvée par une méthode peut être obtenu avec '''length()'''.
 +
 
 +
<source lang='rsplus'>
 +
size[i, 1] <- length(fastgreedy)
 +
size[i, 2] <- length(walktrap)
 +
size[i, 3] <- length(edge)
 +
</source>
 +
*Pour chaque CC triez les méthodes en fonction du nombre de communautés obtenues.
 +
*Représentez graphiquement les résultats.
 +
 
 +
Vous pouvez visualiser les partitionnements obtenus avec les différences méthodes.
 +
 
 +
En entête :
 +
<source lang='rsplus'>
 +
par <- par(mar=c(1,1,1,1))
 +
layout(matrix(1:3,1,3))
 +
</source>
 +
 
 +
Dans la boucle :
 +
<source lang='rsplus'>
 +
      if ( max(fastgreedy$modularity) > 0.3 ) {
 +
      Layout = layout.fruchterman.reingold(CC)
 +
      titre <- paste("fastgreedy", round(Modularity[j, 1],2), Size[j, 1], sep=" ")
 +
      plot(fastgreedy, CC, layout=Layout, vertex.label=NA, vertex.size=3, edge.color="white", edge.width=E(CC)$weight, main=titre)
 +
 
 +
      titre <- paste("walktrap",  round(Modularity[j, 2],2), Size[j, 2], sep=" ")
 +
      plot(walktrap, CC, layout=Layout, vertex.label=NA, vertex.size=3, edge.color="white", edge.width=E(CC)$weight, main=titre)
 +
 
 +
      titre <- paste("edge",  round(Modularity[j, 3],2), Size[j, 3], sep=" ")
 +
      plot(edge, CC, layout=Layout, vertex.label=NA, vertex.size=3, edge.color="white", edge.width=E(CC)$weight, main=titre)
 +
     
 +
      cat ("Press [enter] to continue or quite")
 +
      line <- readline()
 +
      if ( line == 'quite') stop()
 +
      }
 +
</source>
 +
A la fin :
 +
<source lang='rsplus'>
 +
par <- par(mar=c(5.1,4.1,4.1,2.1))
 +
layout(1)
 +
</source>
 +
 
 +
==Application==
 +
Nous allons utiliser '''fastgreedy''' pour définir les clusters de gènes. Pour chaque communauté,
 +
<source lang='rsplus'>
 +
mem <- membership(fastgreedy)
 +
</source>
 +
renvoie la classification des protéines appartenant à la CC.
 +
<source lang='rsplus'>classes <- unique(mem)
 +
</source>
 +
donne la liste des classes trouvées et
 +
<source lang='rsplus'>
 +
class_list <- lapply(classes, function(x, y) names(y[y==x]), y=mem)
 +
</source>
 +
permet d'extraire la liste des classes associées aux protéines de la classe.
 +
 
 +
La liste ''gene_cluster_list'' permet de conserver ces listes. Le data.frame gene_classes conserve les propriétés des nouvelles classes.
 +
 
 +
Les vmin  et vmax sont bornés dans la phase de test!
 +
 
 +
<source lang='rsplus'>
 +
vmin = 12
 +
vmax = 60
 +
ccmax = length(cc)
 +
 
 +
gene_classes <- data.frame(Vcount=numeric(), Strains=numeric(), Pcount=numeric())
 +
 
 +
gene_cluster_list <- c()
 +
 
 +
cluster <- 1
 +
for (i in 2:ccmax)
 +
{
 +
cc_num    <- i
 +
CC        <- cc[[cc_num]]
 +
nb_vertex <- vcount(CC)
 +
list_name <- V(CC)$name
 +
if ( nb_vertex > vmin && nb_vertex <= vmax ) {
 +
    paralogs <- round(count_paralogs(list_name), 2)
 +
    if ( paralogs > 0 ) {
 +
      fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
 +
   
 +
  mem <- membership(fastgreedy)
 +
  classes <- unique(mem)
 +
  class_list <- lapply(classes, function(x, y) names(y[y==x]), y=mem)
 +
  for (k in classes ) {
 +
        paralogs <- round(count_paralogs(class_list[[k]]), 2)
 +
    gene_cluster_list[[cluster]] <- class_list[[k]]
 +
      #cat(cc_num, nb_vertex, "mod", round(max(fastgreedy$modularity), 3), "size", length(fastgreedy), "class", k, "paralogs", paralogs, "cluster", cluster, "\n")
 +
      all_strains <- substr(class_list[[k]],1,5)
 +
        strain_list <- unique(all_strains)
 +
 
 +
      gene_classes[cluster,1] <- length(class_list[[k]])
 +
      gene_classes[cluster,2] <- length(strain_list)
 +
      gene_classes[cluster,3] <- count_paralogs(class_list[[k]])
 +
 
 +
    cluster <- cluster+1
 +
  }
 +
  } else {
 +
    gene_cluster_list[[cluster]] <- list_name
 +
   
 +
      all_strains <- substr(list_name,1,5)
 +
      strain_list <- unique(all_strains)
 +
      gene_classes[cluster,1] <- length(list_name)
 +
      gene_classes[cluster,2] <- length(strain_list)
 +
      gene_classes[cluster,3] <- count_paralogs(list_name)
 +
 
 +
    #cat(cc_num, nb_vertex, "paralogs", paralogs, "cluster", cluster, "\n")
 +
    cluster <- cluster + 1
 +
  }
 +
}
 +
}
 +
</source>
 +
*Tracez la distribution des taux de paralogie.
 +
*Tracez la distribution du nombre de souches présents dans les clusters de gènes.
 +
 
 +
==Liens d'orthologies==
 +
Nous allons rependre l'analyse réalisée avec les résultats des BlastP All/All, mais avec des fichiers BlastP¨tabulés dans lesquels les orthologs ont été calculés (répertoire homologs).
 +
 
 +
<pre style="color:purple;white-space: pre-wrap;white-space: -moz-pre-wrap;white-space: -pre-wrap;white-space: -o-pre-wrap">
 +
*[http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/homologs.tar.gz homologs.tar.gz]
 +
</pre>
 +
 
 +
Les résultats, par paires de génomes, sont dans le format BlastP tabulé avec 6 colonnes en plus: le type de lien d'homologie, la taille des protéines Query et Hit, les scores normalisés des Query, Hit et des deux.
 +
 +
<source lang='rsplus'>
 +
blast.file <- 'homologs/YpesA-YpesB.par'
 +
 
 +
columnames <- c("Query", "Hit", "Percent.identity", "Alignment.length", "Mismatches", "Gap.openings", "Query.start", "Query.end", "Hit.start", "Hit.end", "E.value", "Bit.score", "Homology.type", "Query.length", "Hit.length", "Query.score", "Hit.score","Paire.score")
 +
 
 +
homologs <- read.table(blast.file, sep = "\t", quote = "", header = F, col.names = columnames, stringsAsFactors = F)
 +
</source>
 +
 
 +
==Extraction du graphe des orthologues 1:1==
 +
 
 +
Nous allons ne retenir que les liens du type : Homology.type == 'Iso' qui sont des orthologues 1:1.
 +
 
 +
*Relire les fichiers et ré-écrire les paires de gènes orthologues 1:1 dans le fichier "res/iso_gr".
 +
 
 +
==Traitement du graphe==
 +
 
 +
*Relire ce fichier comme un graphe.
 +
*Affichez le nombre de vertices et d'edges. 
 +
*Appliquez la fonction **simplify()** sur le graphe.
 +
*Affichez le nombre de vertices et d'edges et comparez avec le graphe initial.
 +
*Extraire les composantes connexes (CC).
 +
*Calculez le nombre de nœuds et le nombre d'arêtes de chaque CC et représentez graphiquement le résultat.
 +
*Ajoutez la courbe correspondant au nombre d'arêtes maximum d'un graphe en fonction du nombre de sommets.
 +
*Représentez la distribution de la paralogie dans les CC.
 +
*Tracez la modularité des CC en fonction du taux de paralogie.
 +
*Tracez la droite de régression *Modularity* en fonction de *Pcount*.
 +
 
 +
==Partitionnement en communautés==
 +
En plus des méthodes déjà vues, nous allons utiliser la méthode spinglass. Elle repose sur un plus grand nombre de paramètres:
 +
*`spinglass <- cluster_spinglass(CC, spins=my_spins, start.temp=start_temp, stop.temp=stop_temp, cool.fact=cool_fact, update.rule=update.rule, gamma=my_gamma)`
 +
 
 +
Nous allons fixer les paramètres suivant:
 +
 
 +
<pre>
 +
  `my_gamma <- 1`
 +
  `my_spins <- 25`
 +
  `stop_temp <- 0.1`
 +
  `start_temp <- 1`
 +
  `cool_fact <- 0.95`
 +
  `update.rule <- "config"`
 +
</pre>
 +
et nous allons réitérer spinglass 10 fois pour chaque CC. L'itération maximisant la modularité sera conservée. 
 +
<pre>
 +
  `iter <- 10`
 +
</pre>
 +
Boucle pour spinglass:
 +
 
 +
<source lang='rsplus'>
 +
  my_gamma <- 1
 +
  my_spins <- 25
 +
  stop_temp <- 0.1
 +
  start_temp <- 1
 +
  cool_fact <- 0.95
 +
  update.rule <- "config"
 +
  iter <- 10
 +
 
 +
  # test
 +
  CC <- iso_cc[[1584]]
 +
  Qiter <- array(0, c(iter))
 +
  spinglass_iter <- list()
 +
 
 +
  for ( k in 1:iter )
 +
  {
 +
  spinglass <- cluster_spinglass(CC, weights=E(CC)$weight+10, spins=my_spins,
 +
            start.temp=start_temp, stop.temp=stop_temp,
 +
            cool.fact=cool_fact, update.rule=update.rule,
 +
            gamma=my_gamma)
 +
    Qiter[k] <- modularity(spinglass)
 +
    spinglass_iter[[k]] <- spinglass
 +
  }
 +
  step <- which.max(Qiter)
 +
  membership <- membership(spinglass_iter[[step]])
 +
  modularity <- round(max(Qiter), 3)
 +
</source>
 +
-->

Current revision as of 16:26, 8 December 2021

Contents

Introduction

Nous allons réaliser une analyse de génomique comparative qui s’inspire d’un travail publié par Snipen et Liland (2015). Le but est d’identifier le core et le pan génome d’un ensemble de souches bactériennes. Le core génome est l’ensemble des gènes communs à toutes les souches. Le pan génome est l’ensemble des gènes codés par au moins une des souches (Tettelin et al., 2005). Dans ce contexte un gène est en réalité une famille de gènes ou un cluster de gènes similaires. Idéalement, une famille de gènes serait une collection de gènes orthologues. Néanmoins, comme une analyse pan génomique ne produit pas toujours des groupes de gènes orthologues, il est préférable de parler de clusters de gènes. Bien que ce concept de clusters de gènes joue un rôle central dans les analyses de génomiques comparatives, il n’y a pas de consensus sur la façon de les calculer (Kim et al., 2020)! Dans ce TP, nous allons explorer une approche basée sur la détection de communautés dans un graphe.

Snipen et Liland ont écrit un package R qui permet de répondre à cette question (micropan). Ils ont mis à disposition une étude de cas (casestudy.pdf) afin de guider les utilisateurs de ce package.

Les données

Nous allons travailler avec la bactérie Yersinia pestis une bactérie à Gram négatif du genre Yersinia. Elle est responsable de la peste. Elle a été découverte en 1894 par Alexandre Yersin, un bactériologiste franco-suisse travaillant pour l'Institut Pasteur, durant une épidémie de peste à Hong Kong, en même temps que Kitasato Shibasaburō mais séparément. Kitasato tout d'abord la baptisa Pasteurella pestis en l'honneur de Pasteur. Ce n'est que plus tard qu'elle prit son nom actuel, en hommage à Yersin.

12 souches de Yersinia pestis seront analysées. Les données sont disponible sur le serveur silico dans le répertoire enseignement/m1-bioinfo/Graphe/micropan/Ypestis. Les protéines en format FASTA sont dans le répertoire data/proteins. Les comparaisons entre paires de génomes sont réalisées à l’aide de Blast+ et une annotation des domaines Pfam des protéines est réalisée avec HMMER3. Les fichiers pré-calculés sont disponibles dans les répertoires blast et pfam. Ils sont également disponibles sous forme compressée.

Dans un premier temps nous allons télécharger my_micropan.R et les archives data et homologs.

ou sous linux:

wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/my_micropan.R
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/data.tar.gz
wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/homologs.tar.gz

Vous pouvez effectuer les téléchargements des fichiers dans une Chunk bash dans Rstudio. Les noms des protéines sont construits de la façon suivante:

  • Première lettre en majuscule : la première lettre du genre (Y pour Yersinia)
  • Les trois lettres suivantes en minuscule : les trois premières lettres de l’espèce (pes pour pestis)
  • La cinquième lettre majuscule est le code souche (A pour la souche KIM)
  • Les deux chiffres suivant se réfèrent au numéro du chromosome (01 pour le chromosome 1)
  • Un point est utilisé comme séparateur, il est suivit du nom de la protéine

Mise en œuvre

Pour la création d'un rapport en format HTML, utilisez la librairie knitr pour prédéfinir les formats des figures et les valeurs par défaut d'autres paramètres.

library(knitr)
knitr::opts_chunk$set(fig.align='center', fig.width=6, fig.height=4, fig.path='Figs/', echo=TRUE, warning=FALSE, message=FALSE, cache=TRUE)

Définir le répertoire de travail

knitr::opts_knit$set(root.dir = "/home/user/TP5/")

Chargement des fichiers

Vous pouvez effectuer les téléchargements des fichiers dans une Chunk bash dans Rstudio.

if [ ! -f my_micropan.R ];
then
  wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/my_micropan.R -nc
else
  echo skip my_micropan.R
fi
if [ ! -d data ];
then
  wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/data.tar.gz -nc
  tar -xvf data.tar.gz
else
  echo skip data
fi
if [ ! -d homologs ];
then
  wget http://silico.biotoul.fr/enseignement/m1-bioinfo/Graphe/micropan/Ypestis/homologs.tar.gz -nc
  tar -xvf homologs.tar.gz
else
  echo skip homologs
fi

Nous allons utiliser les librairies : igraph et le fichier my_micropan.R qui contient des fonctions de micropan modifiées pour prendre en compte les préfixes de nos protéines.

getwd()
list.files()
source("my_micropan.R")
library(dplyr)
library(igraph)
 
options (stringsAsFactors = FALSE)
savepar <- par()
par(las=1)
color <- "coral"

Tableau de données

Lecture du tableau décrivant les souches utilisées dans l’analyse.

genome_table_file <- "data/Ypestis.csv"
  • Utilisez la fonction read.table() pour charger le fichier dans la variable genome_table. Le fichier est tabulé avec un entête (sep = "\t" , header= TRUE).
genome_table <- read.table(file=genome_table_file, sep = "\t" , header= TRUE)
head(genome_table)

Les fichiers contenant les séquences des protéines en format FASTA sont dans le sous répertoire data/proteins. Les noms des fichiers sont dans la première colonne de genome_table.

  • Ajoutez une colonne avec le nombre de protéines dans chaque souche.

Lire chaque fichier FASTA avec la commande readLines(). Le nombre de protéines est égal au nombre de ‘>’ présents dans le fichier (utilisez grep() par exemple).

++

in_files <- c()
for (i in 1:nrow(genome_table) ) {
	# file list
	in_files[i] <- file.path("data/proteins", genome_table$File[i])
	# number of proteins
	nb_entries <- length(grep('>', readLines(in_files[i])))
	genome_table[i, 5] <- nb_entries
}
colnames(genome_table)[5] <- c('Proteome')
kable(genome_table)
  • Tracer la distribution de la taille des protéomes (avec boxplot()).

++

rainbowcols <- rainbow(6, s = 0.5)
barplot(table(table(homologs$Query)), ylim=c(0, 50), col = rainbowcols, main='', xlab="nombre d'alignements", ylab="fréquence")

Remarque : le package seqinr a été développé pour l'exploration, l'analyse et la visualisation des séquences biologiques. Il offre des fonctions pour faciliter la manipulation de fichiers en format FASTA (ex. read.fasta()).

Orthologs 1:1

Dans un premier temps, nous allons réaliser la recherche de groupes de gènes orthologues avec des fichiers BlastP¨tabulés dans lesquels les liens d'orthologies calculés ont été ajoutés.

Inspection des liens d'orthologies

La commande **readBlastTable()** de *micropan* peut être utilisée pour relire les fichiers de sortie de blast en format tabulé.

blast.file <- 'homologs/YpesA-YpesB.par'
 
columnames <- c("Query", "Hit", "Percent.identity", "Alignment.length", "Mismatches", "Gap.openings", "Query.start", "Query.end", "Hit.start", "Hit.end", "E.value", "Bit.score", "Homology.type", "Query.length", "Hit.length", "Query.score", "Hit.score","Paire.score")
homologs <- read.table(blast.file, sep = "\t", quote = "", header = F, col.names = columnames, stringsAsFactors = F)
names(homologs)

Trois colonnes ont été ajoutées au fichier de résultats de blastp: Homology.type, Query.length, Hit.length, Query.score, Hit.score, Paire.score

La première colonne donne le type d'homologie : Iso (orthologs 1:1), Ort (orthologs), BeH (Best Hit), IsP (Best BBH paralogs) and BeP (Best paralogs). Les autres colonnes renferment les longueurs des séquences et les scores normalisés par rapport à ces longueurs.

  • Combien d'alignement(s) attendez-vous par protéines?

table(homologs$Query) vous donne le nombre de fois qu'une protéine est présente dans le fichier.

  • Tracez la distribution du nombre d'alignement par protéine.
rainbowcols <- rainbow(6, s = 0.5)
barplot(table(table(homologs$Query)), ylim=c(0, 50), col = rainbowcols, main='', xlab="nombre d'alignements", ylab="fréquence")
  • Identifiez la protéine qui a le plus d'alignements et analysez les alignements obtenus.

++

max_hits <- which.max(table(homologs$Query))
subtab <- homologs[homologs$Query == names(max_hits), ]
kable(subtab %>% arrange(Query.start))
  • Est-ce que toutes les protéines de A ont un alignement dans B?

++

cat("Sur les ", genome_table[genome_table$File == "YpesA", 5], " proteines de YpesA, seules ", length(unique(homologs$Query)), " ont au moins un alignement avec YpesB.", sep="")

Extraction du graphe des orthologues 1:1

Nous allons retenir que les liens du type Homology.type == 'Iso' qui sont des orthologues 1:1.

Écriture du graphe dans le fichier "res/iso_gr".

dir.create("res", showWarnings = TRUE)
graph_file <- "res/iso_gr"
if (file.exists(graph_file)) file.remove(graph_file)
 
sum <- 0
blast_files_list <- file.path("homologs", dir("homologs"))
for( i in 1:length(blast_files_list)) {
  blast_file <- blast_files_list[i]
  cat("read blast file", blast_file, "...\n")
  blast_res <- read.table(blast_file, sep = "\t", quote = "", header = F, col.names = columnames, stringsAsFactors = F)
  blast_iso <- blast_res[blast_res$Homology.type == 'Iso', c(1,2)]
  write.table(as.data.frame(blast_iso), file=graph_file, append=TRUE, row.names=FALSE, col.names=FALSE, quote=FALSE)
  sum <- sum + nrow(blast_iso)
}
cat(sum, " rows in files\n")
  • Décrivez les différentes étapes réalisées dans votre bloc de commandes.

Traitement du graphe

Relire ce fichier comme un graphe (fonction read.graph() de igraph, avec format="ncol").

++

gr <- read.graph(file=graph_file, format="ncol")

Affichez le nombre de sommets et d’arêtes (vcount() et ecount()).

++ Le graphe est composé de `r vcount(gr)` sommets et de `r ecount(gr)` arêtes.

Appliquez la fonction simplify() sur le graphe.

++

gr_iso <- simplify(gr)

Affichez le nombre de sommets et d’arêtes du graphe simplifié.

++ Le graphe simplifié est composé de `r vcount(gr_iso)` sommets et de `r ecount(gr_iso)` arêtes.

  • Comparez le nombre de sommets et d’arêtes des deux graphes et expliquez les différences observées.
  • Quel-est le but de la fonction simplify()?

Composantes connexes

Nous allons maintenant extraire les composantes connexes (CC) du graphe à l'aide de la fonction decompose.graph() en utilisant le mode="strong".

++

iso_cc <- decompose.graph(gr_iso, mode="strong")

La liste des objets graphe sera conservée dans la variable iso_cc.

iso_cc est la liste des CC du graphe.

iso_cc[[i]]
est la ième CC.

Propriétés des composantes connexes

Calculez le nombre de nœuds et le nombre d'arêtes de chaque CC et représentez graphiquement le résultat.

Vous pouvez utiliser lapply() sur la liste de CC pour calculer le nombre de sommets et le nombre d'arêtes de chaque CC.

++

iso_cc_property <- cbind(unlist(lapply(iso_cc, vcount)), unlist(lapply(iso_cc, ecount)))
colnames(iso_cc_property) <- c("vertex", "edges")
vmax <- max(iso_cc_property[,1])
 
plot(iso_cc_property[iso_cc_property[,1] <= vmax, ], las=1, xlim=c(0, vmax), pch=20, col="coral")
  • Quel est le nombre d'arêtes maximum d'un graphe en fonction du nombre de sommets?
  • Ajoutez la courbe correspondant au nombre d'arêtes maximum d'un graphe en fonction du nombre de sommets (fonction curve()).

++

xlimit <- 22
curve(<fonction(x)>, from = 0, to = xlimit, n = 200, col="purple", add=T)
  • A quoi correspondent les zones du graphe délimitées par cette courbe et quelle est la propriété des CC localisées sur la courbe?
  • Quel est le nombre maximum de sommets pour qu'une CC soit une clique dans notre jeu de données?
  • Combien de CC de ce type sont observées dans le jeu de données?

++

table(iso_cc_property[,1], iso_cc_property[,2])
cross <- table(iso_cc_property[,1], iso_cc_property[,2])
# arr.ind	logical; should array indices be returned when x is an array?
maxidx <- which(cross == max(cross), arr.ind = TRUE)
maxrow <- rownames(cross)[maxidx[1]]
maxcol <- colnames(cross)[maxidx[2]]
#cat("Il y a ", max(cross), " CC composées de ", maxrow, " sommets et ", maxcol, " arêtes (", max(cross)/length(iso_cc)*100, "% des CC)", sep="")
  • Représentez graphiquement une clique.
iso_cc[[5]]
par exemple.
myiso_cc <- iso_cc[[5]]
plot.igraph(myiso_cc, vertex.shape="sphere", vertex.size=15, vertex.label.cex=0.8, vertex.label.dist=0, edge.color="red")

Un embellissement!

myiso_cc <- iso_cc[[5]]
local_gene_list <- substr(V(myiso_cc)$name, 5, 5)
local_strain_list <- unique(local_gene_list)
tocolor <- unlist(lapply(local_gene_list, function(x,y) grep(x, y), local_strain_list))
mycolor = rainbow(length(local_strain_list));
palette(mycolor);
plot.igraph(myiso_cc, vertex.shape="sphere", vertex.size=15, vertex.color=tocolor, vertex.label.cex=0.8, vertex.label=local_gene_list, vertex.label.dist=0, vertex.label.color="white", edge.color="red", edge.width=E(myiso_cc)$weight)
  • Décrivez les différentes étapes réalisées dans ce bloc de commandes.
  • Combien de sommets et d'arêtes possède la CC 5?

Taux de paralogie

Nous allons écrire une fonction qui calcule le taux de gènes paralogues dans une liste de gènes. Pour cela nous allons

  compter le nombre de gènes G présent dans la liste,
  en extraire le nombre de souches S. 

S'il n'y a pas de paralogue, chaque souche est représentée par un seul gène (G=S), sinon (G>S), on a plus d'un gène par souche.

Pour estimer le taux de paralogues, on divise la différence entre nombre de gènes et nombre de souches (G-S) par le nombre de gènes G.

Les fonctions à utiliser sont :

  **substr()** pour extraire le nom de souche à partir du nom de gène 
  **unique()** pour obtenir le nombre de souche. 

L'expression `V(graph)$name` permet d'obtenir la liste des sommets du graphe.

count_paralogs <- function(lst)
{
  ...
  return(paralogs)
}

++

count_paralogs <- function(lst)
{
  all_strains <- substr(lst,1,5)
  strain_list <- unique(all_strains)
  paralogs <- (length(all_strains) - length(strain_list))/length(all_strains)
  return(paralogs)
}

Distribution de la paralogie

Représentez la distribution de la paralogie dans les CC.

++

pdm1 <- data.frame(Vcount=numeric(), Pcount=numeric())
j <- 0
for (i in 1:length(iso_cc))
{
	cc_num    <- i
	CC        <- iso_cc[[cc_num]]
	nb_vertex <- vcount(CC)
 
	j <- j+1
	list_name <- V(CC)$name
 
  	pdm1[j, 1] <- vcount(CC)
	pdm1[j, 2] <- round(count_paralogs(list_name), 3)
}
hist(pdm1$Pcount, nclass=10)

Tracez le taux de paralogie des CC en fonction du nombre de sommets.

++

vmax <- max(pdm1$Vcount)
plot(pdm1[,c(1,2)], las=1, pch=20, col=color, ylim=c(0,1))
  • Quelle est le taux minimum de paralogie en fonction du nombre de protéines par CC?
  • Tracez la courbe correspondante.

++ Jusqu'à 12 protéines présentes (le nombre de souches) le taux minimum de paralogie est de 0. Au-delà, il est minimum si toutes les souches sont présentes au moins une fois.

vmax <- max(pdm1$Vcount)
plot(pdm1[,c(1,2)], las=1, pch=20, col=color, ylim=c(0,1))
curve((x-nrow(genome_table))/x, from=nrow(genome_table), to=vmax, n=200, col="purple", add=T)

Modularité des CC

Nous pouvons calculer la modularité d'un graphe avec la fonction cluster_fast_greedy() d'igraph (fastgreedy.community() suivant la version). La modularité du graphe est donnée par `max(fastgreedy$modularity)`.

++

pdm2 <- data.frame(Vcount=numeric(), Pcount=numeric(), Density=numeric(), Modularity=numeric())
j <- 0
for (i in 1:length(iso_cc))
{
	cc_num    <- i
	CC        <- iso_cc[[cc_num]]
	nb_vertex <- vcount(CC)
 
	j <- j+1
	list_name <- V(CC)$name
	fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
 
  	pdm2[j, 1] <- vcount(CC)
	pdm2[j, 2] <- count_paralogs(list_name)
	pdm2[j, 3] <- graph.density(CC,loops=FALSE)
	pdm2[j, 4] <- max(fastgreedy$modularity)
}
kable(head(pdm2))
  • Tracer la distribution de Q.

++

hist(pdm2$Modularity, nclass=10, col=color, ylim=c(0, 50))
  • Tracez la modularité des CC en fonction du taux de paralogie.

++

plot(pdm2[,c(2,4)], las=1, pch=20, col=color)
  • Ajoutez la droite de régression *Modularity* en fonction de *Pcount*.

++

cor <- lm(pdm2$Modularity ~ pdm2$Pcount)
summary(cor)
plot(pdm2[,c(2,4)], las=1, pch=20, xlim=c(0,1), ylim=c(0,1), col=color)
curve(cor$coefficients[2]*x +cor$coefficients[1], from=0.05, to=1, col="purple", add=T)
  • Commentez le résultat obtenu.

Partitionnement en communautés

Plusieurs méthodes sont disponibles dans igraph pour partitionner un graphe en communautés. Nous allons, dans un premier temps, comparer les méthodes fastgreedy, walktrap, edge betweenness et louvain. Ces méthodes sont utilisées de façon similaire (vous pouvez ajouter la méthode cluster_leiden si elle disponible dans votre version d'igraph):

  • `fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)`
  • `walktrap <- cluster_walktrap(CC, modularity=TRUE)`
  • `edge <- cluster_edge_betweenness(CC, modularity=TRUE)`
  • `louvain <- cluster_louvain(CC)`

Le nombre de communautés trouvée dans la CC j peut être obtenu avec *length(méthode)*.

  • `size[j, 1] <- length(fastgreedy)`
  • `size[j, 2] <- length(walktrap)`
  • `size[j, 3] <- length(edge)`
  • `size[j, 4] <- length(louvain)`

avec la modularité Q associée:

  • `Modularity5[j, 1] <- round(max(fastgreedy$modularity), 3)`
  • `Modularity5[j, 2] <- round(max(walktrap$modularity), 3)`
  • `Modularity5[j, 3] <- round(max(edge$modularity), 3)`
  • `Modularity5[j, 4] <- round(max(edge$modularity), 4)`

Un exemple avec fastgreedy

Un exemple simple:

stop = 100
for (cc_num in 2:stop) {
  CC <- iso_cc[[cc_num]]
  fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
  Q = round(max(fastgreedy$modularity), 3)
  cat("CC", cc_num, " modularité", Q, "\n")
}

Un code un peu plus complexe:

vmin <- 12
vmax <- max(sapply(iso_cc, vcount, simplify=TRUE))
edgecolor <- "red"
 
pdm5 <- data.frame(Vcount=numeric(), Pcount=numeric())
Modularity5 <- data.frame(fastgreedy=numeric())
Size5 <- data.frame(fastgreedy=numeric())
 
j <- 0
for (i in 2:length(iso_cc)) {
	cc_num    <- i
	CC        <- iso_cc[[cc_num]]
	nb_vertex <- vcount(CC)
	if ( nb_vertex > vmin && nb_vertex <= vmax ) {
 
		fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
		Q = round(max(fastgreedy$modularity), 3)
		if ( Q > 0.45 ) {
			j <- j+1
			list_name <- V(CC)$name      
			pdm5[j, 1] <- cc_num
			pdm5[j, 2] <- nb_vertex
			pdm5[j, 3] <- count_paralogs(list_name)
 
			Modularity5[j, 1] <- Q
			Size5[j, 1] <- length(fastgreedy)
 
			cat("CC", cc_num, vcount(CC), Modularity5[j, 1], Modularity5[j, 2], Modularity5[j, 3], Modularity5[j, 4], "\n")
 
			Layout <- layout.fruchterman.reingold(CC) 
			titre <- paste(cc_num, "fastgreedy", round(Modularity5[j, 1],2), Size5[j, 1], sep=" ")
			plot(fastgreedy, CC, layout=Layout, 
			vertex.label=NA, vertex.size=3, vertex.shape="sphere",
			edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 
			cat ("Press [enter] to continue or quit")
			line <- readline()
			if ( line == 'quit') stop("user interruption")
		}
	}
}

Réinitialiser layout

par <- par(mar=c(5.1,4.1,4.1,2.1))
layout(1)

Avec un code couleur pour les souches:

Ajouter les autres méthodes

Le principe :

stop = length(iso_cc)
for (cc_num in 2:stop) {
  CC <- iso_cc[[cc_num]]
	nb_vertex <- vcount(CC)
  fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
  Q = round(max(fastgreedy$modularity), 2)
  if ( Q > 0.45 ) {
    list_name <- V(CC)$name
    P <- round(count_paralogs(list_name), 2)
 
    walktrap <- walktrap.community(CC, modularity=TRUE)
    W <- round(max(walktrap$modularity), 2)
    edge <- edge.betweenness.community(CC, modularity=TRUE)
    E <- round(max(edge$modularity), 2)
    louvain <- cluster_louvain(CC)
    L <- round(max(louvain$modularity), 2)
    cat("CC", cc_num, nb_vertex, P, Q, W, E, L, "\n")
  }
}

l'application:

++

par(mar=c(1,1,1,1))
layout(matrix(1:4, 1, 4))
vmin <- 12
vmax <- max(sapply(iso_cc, vcount, simplify=TRUE))
edgecolor <- "red"
pdm5 <- data.frame(CC=numeric(), Vcount=numeric(), Pcount=numeric())
Modularity5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric())
Size5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric())
 
j <- 0
for (i in 2:length(iso_cc))
{
	cc_num    <- i
	CC        <- iso_cc[[cc_num]]
	nb_vertex <- vcount(CC)
	if ( nb_vertex > vmin && nb_vertex <= vmax ) {
		list_name <- V(CC)$name
		#fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
		fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
		if ( max(fastgreedy$modularity) > 0.45 ) {
			j <- j+1
			walktrap   <- cluster_walktrap(CC, modularity=TRUE)
			edge       <- cluster_edge_betweenness(CC, modularity=TRUE)
			louvain    <- cluster_louvain(CC)
 
 
			pdm5[j, 1] <- cc_num
			pdm5[j, 2] <- vcount(CC)
			pdm5[j, 3] <- count_paralogs(list_name)
 
  			Modularity5[j, 1] <- round(max(fastgreedy$modularity), 3)
  			Modularity5[j, 2] <- round(max(walktrap$modularity), 3)
  			Modularity5[j, 3] <- round(max(edge$modularity), 3)
  			Modularity5[j, 4] <- round(max(louvain$modularity), 3)
 
  			if ( min(Modularity5[j,]) < max(Modularity5[j,])) {
  				Size5[j, 1] <- length(fastgreedy)
  				Size5[j, 2] <- length(walktrap)
  				Size5[j, 3] <- length(edge)
  				Size5[j, 4] <- length(louvain)
 
 
 
 
    				#cat("CC", cc_num, vcount(CC), Modularity5[j, 1], Modularity5[j, 2], Modularity5[j, 3], "\n")
 
  				Layout = layout.fruchterman.reingold(CC) 
  				titre <- paste(cc_num, "fastgreedy", round(Modularity5[j, 1],3), Size5[j, 1], sep=" ")
  				plot(fastgreedy, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 
  				titre <- paste("walktrap",  round(Modularity5[j, 2],3), Size5[j, 2], sep=" ")
  				plot(walktrap, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 
  				titre <- paste("edge",  round(Modularity5[j, 3],3), Size5[j, 3], sep=" ")
  				plot(edge, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 
  				titre <- paste("louvain",  round(Modularity5[j, 4],3), Size5[j, 3], sep=" ")
  				plot(louvain, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color=edgecolor, edge.width=E(CC)$weight, main=titre)
 
  				cat ("Press [enter] to continue or quit")
  				line <- readline()
  				if ( line == 'quit') stop()
  			}
		}
	}
}
 
par <- par(mar=c(5.1,4.1,4.1,2.1))
layout(1)

spinglass

La méthode spinglass repose sur un plus grand nombre de paramètres:

spinglass <- cluster_spinglass(CC, spins=my_spins, start.temp=start_temp, stop.temp=stop_temp, cool.fact=cool_fact, update.rule=update.rule, gamma=my_gamma)`

Illustration avec la CC 1584

my_gamma <- 1
my_spins <- 25
stop_temp <- 0.8
start_temp <- 1
cool_fact <- 0.95
update.rule <- "config"
iter <- 100
 
# test 
CC <- iso_cc[[1584]]
Qiter <- array(0, c(iter))
spinglass_iter <- list() 
 
for ( k in 1:iter )  {
 	spinglass <- cluster_spinglass(CC, weights=E(CC)$weight+10, spins=my_spins,
 	start.temp=start_temp, stop.temp=stop_temp,
 	cool.fact=cool_fact, update.rule=update.rule, 
 	gamma=my_gamma)
 	Qiter[k] <- modularity(spinglass)
 	spinglass_iter[[k]] <- spinglass
}
step <- which.max(Qiter)
membership <- membership(spinglass_iter[[step]])
modularity <- round(max(Qiter), 3)

Distribution de Q en fonction des itérations :

plot(Qiter, ylim=c(0,1), xlab="iteration", ylab="Modularity")
hist(Qiter, col=color, xlim=c(0,1))
  • Diminuez la valeur de stop.temp (0.4 par exemple). Que pouvez-vous observer?

Assemblage des cinq méthodes

Nous allons fixer les paramètres suivant:

  `my_gamma <- 1`
  `my_spins <- 25`
  `stop_temp <- 0.8`
  `start_temp <- 1`
  `cool_fact <- 0.95`
  `update.rule <- "config"`

et nous allons réitérer spinglass 10 fois pour chaque CC. L'itération maximisant la modularité sera conservée.

  `iter <- 10`
  • Assemblez les cinq méthodes dans un seul bloc.

Principe :

my_gamma <- 1
my_spins <- 25
stop_temp <- 0.1
start_temp <- 1
cool_fact <- 0.95
update.rule <- "config"
iter <- 10
 
stop = length(iso_cc)
for (cc_num in 2:stop) {
  CC <- iso_cc[[cc_num]]
  nb_vertex <- vcount(CC)
  fastgreedy <- fastgreedy.community(CC, modularity=TRUE)
  Q = round(max(fastgreedy$modularity), 2)
  if ( Q > 0.45 ) {
    list_name <- V(CC)$name
    P <- round(count_paralogs(list_name), 2)
 
    walktrap <- walktrap.community(CC, modularity=TRUE)
    W <- round(max(walktrap$modularity), 2)
    edge <- edge.betweenness.community(CC, modularity=TRUE)
    E <- round(max(edge$modularity), 2)
    louvain <- cluster_louvain(CC)
    L <- round(max(louvain$modularity), 2)
 
    Qiter <- array(0, c(iter))
    spinglass_iter <- list()  
    for ( k in 1:iter ) {
      spinglass <- spinglass.community(CC, , spins=my_spins,
        start.temp=start_temp, stop.temp=stop_temp,			
        cool.fact=cool_fact, update.rule=update.rule, 
        gamma=my_gamma)
      Qiter[k] <- modularity(spinglass)
      spinglass_iter[[k]] <- spinglass
    }
    S <- round(max(Qiter), 2)
    if ( min(qiter) < max(qiter)) {
       cat("CC", cc_num, nb_vertex, P, Q, W, E, L, S, "\n")
    }
  }
}

l'ensemble

++

par(mar=c(1,1,1,1))
layout(matrix(1:5, 1, 5))
vmin <- 12
vmax <- max(sapply(iso_cc, vcount, simplify=TRUE))
pdm5 <- data.frame(cc_num=numeric(), Vcount=numeric(), Pcount=numeric())
Modularity5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric(), spinglass=numeric())
Size5 <- data.frame(fastgreedy=numeric(), walktrap=numeric(), edge=numeric(), louvain=numeric(), spinglass=numeric())
 
my_gamma <- 1
my_spins <- 25
stop_temp <- 0.1
start_temp <- 1
cool_fact <- 0.95
update.rule <- "config"
iter <- 10
 
j <- 0
for (i in 2:length(iso_cc))
{
	cc_num    <- i
	CC        <- iso_cc[[cc_num]]
	nb_vertex <- vcount(CC)
	if ( nb_vertex > vmin && nb_vertex <= vmax ) {
		list_name <- V(CC)$name
		fastgreedy <- cluster_fast_greedy(CC, modularity=TRUE)
		if ( max(fastgreedy$modularity) > 0.3 ) {
			j <- j+1
			walktrap   <- cluster_walktrap(CC, modularity=TRUE)
			edge       <- cluster_edge_betweenness(CC, modularity=TRUE)
			louvain    <- cluster_louvain(CC)
 
			Qiter <- array(0, c(iter))
			spinglass_iter <- list()  
			for ( k in 1:iter ) {
				spinglass <- cluster_spinglass(CC, , spins=my_spins,
				start.temp=start_temp, stop.temp=stop_temp,
				cool.fact=cool_fact, update.rule=update.rule, 
				gamma=my_gamma)
				Qiter[k] <- modularity(spinglass)
				spinglass_iter[[k]] <- spinglass
			}
			step <- which.max(Qiter)
			membership <- membership(spinglass_iter[[step]])
 
			pdm5[j, 1] <- cc_num
			pdm5[j, 2] <- vcount(CC)
			pdm5[j, 3] <- count_paralogs(list_name)
 
			Modularity5[j, 1] <- round(max(fastgreedy$modularity), 3)
			Modularity5[j, 2] <- round(max(walktrap$modularity), 3)
			Modularity5[j, 3] <- round(max(edge$modularity), 3)
			Modularity5[j, 4] <- round(max(louvain$modularity), 3)
			Modularity5[j, 5] <- round(max(Qiter), 3)
 
			Size5[j, 1] <- length(fastgreedy)
  	 	Size5[j, 2] <- length(walktrap)
			Size5[j, 3] <- length(edge)
			Size5[j, 4] <- length(edge)
			Size5[j, 5] <- length(unique(membership))
 
			#cat("CC", cc_num, vcount(CC), Modularity5[j, 1], Modularity5[j, 2], Modularity5[j, 3], Modularity5[j, 4], "\n")
      #if ( Modularity5[j, 5] > min(Modularity5[j,])) {
			  Layout = layout.fruchterman.reingold(CC) 
  			titre <- paste(cc_num, "fastgreedy", round(Modularity5[j, 1],3), Size5[j, 1], sep=" ")
  			plot(fastgreedy, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 
  			titre <- paste("walktrap",  round(Modularity5[j, 2],3), Size5[j, 2], sep=" ")
  			plot(walktrap, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 
  			titre <- paste("edge",  round(Modularity5[j, 3],3), Size5[j, 3], sep=" ")
  			plot(edge, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 
  			titre <- paste("louvain",  round(Modularity5[j, 4],3), Size5[j, 3], sep=" ")
  			plot(louvain, CC, layout=Layout, vertex.label=NA, vertex.size=3, vertex.shape="sphere", edge.color='grey', edge.width=E(CC)$weight, main=titre)
 
			  titre <- paste("spinglass",  round(Modularity5[j, 4],3), Size5[j, 4], sep=" ")
			  plot(spinglass_iter[[step]], CC, layout=Layout, vertex.label=NA, vertex.size=3, edge.color='grey', edge.width=E(CC)$weight, main=titre)
		  	cat ("Press [enter] to continue or quit")
		  	line <- readline()
		  	#if ( line == 'quit') stop()
		  #}
		}
	}
}
par <- par(mar=c(5.1,4.1,4.1,2.1))
layout(1)

Pour chaque CC triez les méthodes en fonction des modularités obtenues. Représentez graphiquement les résultats.

++

Modu_stat <- apply(Modularity5, 1, function(x) rank(signif(x[1:5], digits=5), ties.method = "max"))
 
# fréquence des différents rangs
Modu_tab <- apply(Modu_stat, 1, function(x) { 
  his <- hist(x, breaks=(0:5), plot=F)
  his$count
})
rainbowcols <- rainbow(5, s = 0.2)
barplot(Modu_tab, col=rainbowcols, ylab="frequency", ylim=c(0,25))

Pour chaque CC triez les méthodes en fonction du nombre de communautés obtenues. Représentez graphiquement les résultats.

++

Size_stat <- apply(Size5, 1, function(x) rank(signif(x[1:4], digits=5), ties.method = "max"))
 
Size_tab <- apply(Size_stat, 1, function(x) { 
  his <- hist(x,breaks=(0:4), plot=F)
  his$count
})
barplot(Size_tab)
  • Commentez les résultats.

Pour obtenir les résultats sur toutes les CC, relancez la boucle en supprimant le test:

      	cat ("Press [enter] to continue or quit")
      	line <- readline()
      	if ( line == 'quit') stop()
  • Tracez les deux plots et commentez les résultats obtenus avec les CC de taille supérieur à 12 arêtes!

End