2015-06-04 22 views
5

W pakiecie igraph R, staram się wykreślić sieć społeczną za pomocą współrzędnych szerokości/długości geograficznej jako układu wykresu.Używanie współrzędnych geograficznych jako współrzędnych wierzchołków w pakiecie igraph r

Wyobraźmy sobie ten prosty przykład: sieć z 4 węzłów, z których znane jest położenie geograficzne oraz połączeń:

df<-data.frame("from" = c("Bob", "Klaus", "Edith", "Liu"), "to"= c("Edith", "Edith", "Bob", "Klaus")) 

Tutaj masz meta-dane dla węzłów, tak że Bob mieszka w Nowym Jorku, Klaus w Berlinie, w Paryżu i Edith Liu w Pekinie:

meta <- data.frame("name"=c("Bob", "Klaus", "Edith", "Liu"), "lon"=c(-74.00714, 13.37699, 2.34120, 116.40708), "lat"=c(40.71455, 52.51607, 48.85693, 39.90469)) 

Wykonujemy g przedmiotem igraph ...

g <- graph.data.frame(df, directed=T, vertices=meta) 

... i definiujemy jako nasz układ współrzędnych długość/szerokość

lo <- layout.norm(as.matrix(meta[,2:3])) 
plot.igraph(g, layout=lo) 

Jeżeli Państwo uruchomić ten przykład z tych (Real) współrzędnych geograficznych, zobaczysz, że jest „względnie” dokładne w poczucie, że lokalizacje są względem siebie właściwe. Jeśli jednak wykreślę wiele współrzędnych takich jak ta, mapa kartezjańska świata wygląda "rozciągnięta".

Czy istnieje sposób, w jaki mogę naprawdę wykreślić moje węzły na mapie świata, tak aby współrzędne były w 100% poprawne i mogę zobaczyć połączenia między moimi węzłami? Naprawdę chcę nadal używać pakietu igraph, ponieważ oferuje wiele funkcji, które mogą być potrzebne później, gdy chcę analizować połączenia między węzłami.

+0

Czy rozważałeś wykonanie ramki danych z węzłów igraph, a następnie narysowanie ich na mapie za pomocą podsystemu ggplot? – hrbrmstr

+0

Zgodnie z sugestią @ hrbrmstr, tworzy to mapę świata, ale nakładanie się lub integrowanie krawędzi i zdolności do rysowania jest poza mną. wymagają (mapy) kraje <- map_data ("świat") kraje <- podzbiór (kraje, region! = "Antarktyda") ggplot (meta, aes (x = lon, y = lat)) + geom_point (kształt = 22, wypełnienie = "czerwony", rozmiar = 6) + geom_polygon (dane = kraje, aes (x = długi, y = lat, grupa = grupa), col = "grey30", wypełnienie = "przezroczysty", lwd = 0) – lawyeR

+2

Musisz wywołać tutaj 'igraph :: plot()' z parametrem 'rescale = FALSE', w przeciwnym razie przeskaluje współrzędne wzdłuż obu wymiarów na' [-1; 1] 'interval. – deeenes

Odpowiedz

6

Jednym z elementów rozwiązania jest bez wątpienia parametr rescale = FALSE do igraph::plot(), co zasugerowałem w komentarzu. OP zapytał, dlaczego ey ma z tego pustą fabułę? Dzieje się tak, ponieważ obszar kreślenia jest nadal ograniczony do przedziału [-1; 1] wzdłuż osi x i y. To ustawienie domyślne to igraph::plot(). Musimy więc podać parametry: xlim = c(-180, 180) i ylim = c(-90, 90). To już daje prawidłowe pozycjonowanie. Jeśli jednak naszym celem jest stworzenie postaci z mapą świata, być może najlepiej jest napisać wykres na urządzeniu SVG cairo. Wtedy będziemy mogli umieścić mapę za wykresem w dowolnym edytorze SVG (np. Inkscape jest świetnym rozwiązaniem), a my nadal możemy dowolnie skalować i edytować wykres i etykiety. Aby to zrobić, trzeba ustawić inne parametry, ale to już jest o proporcjach i estetyce. Oto kod I wykorzystywane do produkcji wyjście SVG:

#!/usr/bin/Rscript 

require(igraph) 
require(Cairo) 

df <- data.frame("from" = c("Bob", "Klaus", "Edith", "Liu"), 
    "to" = c("Edith", "Edith", "Bob", "Klaus")) 

meta <- data.frame("name" = c("Bob", "Klaus", "Edith", "Liu"), 
    "lon" = c(-74.00714, 13.37699, 2.34120, 116.40708), 
    "lat" = c(40.71455, 52.51607, 48.85693, 39.90469)) 

g <- graph.data.frame(df, directed = TRUE, vertices = meta) 

lo <- layout.norm(as.matrix(meta[,2:3])) 

dpi = 1.0 
Cairo(file = 'map-graph.svg', type = "svg", 
    units = "in", 
    width = 4/dpi, 
    height = 2/dpi, 
    dpi = dpi) 

plot.igraph(g, 
    layout = lo, 
    xlim = c(-180, 180), 
    ylim = c(-90, 90), 
    rescale = FALSE, 
    edge.curved = TRUE, 
    edge.arrow.size = 10/dpi, 
    edge.arrow.width = 0.5/dpi, 
    vertex.label.dist = 50/dpi, 
    vertex.label.degree = 90/dpi, 
    vertex.size = 200/dpi, 
    vertex.label.cex = 21/dpi, 
    vertex.frame.color = NA, 
    vertex.label.color = '#FFFF00', 
    edge.color = '#FFFFFF', 
    vertex.label.family = 'sans-serif', 
    edge.width = 16/dpi) 

dev.off() 

Gdy SVG produkowane przez igraph wygląda dobrze, możemy go otworzyć w Inkscape. Następnie zaimportuj (Ctrl+i) mapę w przypadku, gdy jest to pixmap; lub otwórz, jeśli jest to grafika wektorowa (np. PDF, SVG). Ręcznie przeskaluj i umieść mapę, aby ustawić taką samą skalę jak wykres w SVG (tj. Do momentu, w którym punkty znajdą się we właściwym miejscu) - w celu proporcjonalnego skalowania, przytrzymaj Ctrl w Inkscape. Oto wynik tej metody:

enter image description here

(Mapa obrazu jest udostępniona dla niekomercyjnego użytku publicznego przez Wikimedia Commons).

Myślę, że igraph jest w stanie wyprodukować takie liczby, ale nie jest to główny cel tego oprogramowania, więc ma swoje ograniczenia. W pewnym momencie możesz rozważyć użycie jakiegoś oprogramowania Geographic Information System (GIS), zaprojektowanego dokładnie tak, by robić takie rzeczy. Nie mam z tym żadnego doświadczenia, ale prawdopodobnie warto się przyjrzeć.

+0

To jest idealne. Świetne rozwiązanie. Bardzo przydatna była również sugestia świetnych kręgów (http://flowingdata.com/2011/05/11/how-to-map-connections-with-great-circles/), aby wizualnie zrobić to, czego potrzebowałem. – willemr