2013-05-05 19 views
13

W igraph, po zastosowaniu algorytmu modularyzacji w celu znalezienia komunika- tów grafów, chciałbym narysować układ sieci, który wyraźnie uwidoczni odrębne społeczności i ich połączenia. Coś takiego jak "układ atrybutów grupowych" w Cytoscape: chcę pokazać członków każdej grupy/społeczności blisko siebie i zachować pewien dystans między grupami/społecznościami. Nie mogłem znaleźć żadnej funkcji w igraph dostarczającej tę funkcję po wyjęciu z pudełka. Wysyłając to pytanie, znalazłem już proste rozwiązanie w wersji d.i.y, zamierzam je opublikować jako odpowiedź. Ale zastanawiam się, czy jest jakaś lepsza możliwość, czy bardziej dopracowane rozwiązanie?Jak pogrupować układ w igraph?

Odpowiedz

4

Aby rozwinąć na sugestię Gabor, Stworzyłem tę funkcję:

weight.community=function(row,membership,weigth.within,weight.between){ 
if(as.numeric(membership[which(names(membership)==row[1])])==as.numeric(membership[which(names(membership)==row[2])])){ 
weight=weigth.within 
}else{ 
weight=weight.between 
} 
return(weight) 
} 

Wystarczy zastosować ją na wierszach macierzy krawędziach grafu (podane przez get.edgelist(your_graph)) ustawić nowe ciężary krawędź (członkostwo jest wektor członków z wyniku dowolnego algorytmu detekcji społeczność):

E(g)$weight=apply(get.edgelist(g),1,weight.community,membership,10,1) 

Następnie wystarczy użyć algorytmu układu, który akceptuje ciężary brzegowych, takich jak fruchterman.reingold jak sugeruje Gabor można dostosować argumenty wag do ob. tain wykres, który chcesz. Na przykład:

E(g)$weight=apply(get.edgelist(g),1,weight.community,membership,10,1) 
g$layout=layout.fruchterman.reingold(g,weights=E(g)$weight) 
plot(g) 

enter image description here

E(g)$weight=apply(get.edgelist(g),1,weight.community,membership,1000,1) 
g$layout=layout.fruchterman.reingold(g,weights=E(g)$weight) 
plot(g) 

enter image description here

Uwaga 1: przezroczystości/kolory krawędzi są inne parametry moich wykresach. Mam kolorowe węzły społeczności, aby pokazać, że rzeczywiście działa.

Uwaga 2: upewnij się, aby skorzystać membership(comm) i nie comm$membership, gdzie comm jest wynikiem algorytmu detekcji społeczność (np comm=leading.eigenvector.community(g)). Powodem jest to, że w pierwszym przypadku otrzymujesz wektor liczbowy z nazwami (czego chcemy), aw drugim przypadku ten sam wektor bez nazw.

Aby uzyskać consensus wielu algorytmów wykrywania społeczności, patrz: function.

3

Funkcja layout.modular zapewnia zgrupowanego układ na wykresie z wyników jakiegokolwiek sposobu wykrywania społeczność igraph:

c <- fastgreedy.community(G) 

layout.modular <- function(G,c){ 
nm <- length(levels(as.factor(c$membership))) 
gr <- 2 
while(gr^2<nm){ 
    gr <- gr+1 
} 
i <- j <- 0 
for(cc in levels(as.factor(c$membership))){ 
    F <- delete.vertices(G,c$membership!=cc) 
    F$layout <- layout.kamada.kawai(F) 
    F$layout <- layout.norm(F$layout, i,i+0.5,j,j+0.5) 
    G$layout[c$membership==cc,] <- F$layout 
    if(i==gr){ 
     i <- 0 
     if(j==gr){ 
      j <- 0 
     }else{ 
      j <- j+1 
     } 
    }else{ 
     i <- i+1 
    } 
} 
return(G$layout) 
} 

G$layout <- layout.modular(G,c) 
V(G)$color <- rainbow(length(levels(as.factor(c$membership))))[c$membership] 
plot(G) 
+1

pojawia się błąd, gdy próbuję swoją metodę. Dodałem tylko dwa wiersze powyżej kodu, aby zasymulować sieć, tj .: 'library (igraph); G <- barabasi.game (100, directed = FALSE) '. Komunikat o błędzie mówi: "Błąd w układzie G $ [członkostwo c == cc,] <- Układ F $: niepoprawna liczba indeksów na macierzy" – majom

+0

Otrzymuję również podobny błąd. – imbenzene

+0

Niestety, dzieje się tak, ponieważ 'G $ layout' to' NULL'. Jeśli wypełnisz ją dowolną macierzą o odpowiednich wymiarach lub po prostu z układem 'G $ <- layout.fruchterman.reingold (G)', to kod działa dobrze. – deeenes

2

Jednym rozwiązaniem jest ustawienie grubości krawędzi wykresu, na podstawie modułowości. Ustaw krawędzie wewnątrz modułu na pewną dużą masę, a krawędzie między modułami na niewielką wagę. Następnie zadzwoń pod numer layout.fruchterman.reingold() lub dowolny algorytm obsługujący grubości krawędzi.

Być może trzeba trochę pogodzić z rzeczywistymi wartościami ciężaru, ponieważ zależy to od wykresu.

+0

Cześć Gabor, czy mógłbyś rzucić okiem na ten powiązany [wątek] (http://stackoverflow.com/questions/31432176/potential-issue-with-new-igraph-layout-algorithms-r). Z góry dziękuję. – Antoine

5

Inspirowane na sugestię Antoine, stworzyłem tę funkcję:

edge.weights <- function(community, network, weight.within = 100, weight.between = 1) { 
bridges <- crossing(communities = community, graph = network) 
weights <- ifelse(test = bridges, yes = weight.between, no = weight.within) 
return(weights) 
} 

Funkcja robi to samo; po prostu umieść swój obiekt społecznościowy w slocie społeczności, a twój wykres w sieci. Zostawiłam weight.between = 1 i dostroiłam wartość weight.within.

następnie przenieść ciężar do gniazda weight w węzłach:

E(graph)$weight <- edge.weights(community, graph) 

Wreszcie użyć algorytmu układu, który wykorzystuje ciężary jak layout_with_fr (nową nazwą fruchterman.reingold w igraph 1.0.1).

Korzystam z sieci karate klubu Zachary jako przykładu.

library(igraph) 
library(igraphdata) 
#I load the network 
data(karate) 
#for reproducible purposes 
set.seed(23548723) 
karateLayout <- layout_with_fr(karate) 
par(mar = c(0,0,2,0)) 
plot(karate, vertex.size = 10, vertex.color = "steelblue4", edge.width = 1, 
vertex.label = NA, edge.color = "darkgrey", layout = karateLayout, 
main = "Zachary's karate club network") 

enter image description here

wykryć społeczności poprzez optymalizację wielopoziomowego modularność z cluster_louvain funkcję:

Communitykarate <- cluster_louvain(karate) 

Kolejnym jest to osobiste preferencje ciągu domyślne:

prettyColors <- c("turquoise4", "azure4", "olivedrab","deeppink4") 
communityColors <- prettyColors[membership(Communitykarate)] 

Wykres ze społecznościami wyróżnione poprzez kolory to:

plot(x = Communitykarate, y = karate, edge.width = 1, vertex.size = 10, 
vertex.label = NA, mark.groups = NULL, layout = karateLayout, col = communityColors, 
main = "Communities in Zachary's karate club network", 
edge.color = c("darkgrey","tomato2")crossing(Communitykarate, karate) + 1]) 

enter image description here

Teraz sens dlaczego to pytanie istnieje.

E(karate)$weight <- edge.weights(Communitykarate, karate) 
# I use the original layout as a base for the new one 
karateLayoutA <- layout_with_fr(karate, karateLayout) 
# the graph with the nodes grouped 
plot(x = Communitykarate, y = karate, edge.width = 1, vertex.size = 10, 
mark.groups = NULL, layout = karateLayoutA, vertex.label = NA, col = communityColors, 
c("darkgrey","tomato2")[crossing(Communitykarate, karate) + 1], 
main = "Communities in Zachary's karate club network (grouped)") 

enter image description here

Jeśli spróbujesz z większą wagę będzie trzeba mieć:

E(karate)$weight <- edge.weights(Communitykarate, karate, weight.within = 1000) 
karateLayoutB <- layout_with_fr(karate, karateLayout) 
plot(x = Communitykarate, y = karate, edge.width = 1, vertex.size = 10, 
mark.groups = NULL, layout = karateLayoutB, vertex.label = NA, col = communityColors, 
c("darkgrey","tomato2")[crossing(Communitykarate, karate) + 1], 
main = "Communities in Zachary's karate club network (grouped)") 

enter image description here

Powiązane problemy