briatte / ggnetwork

Geoms to plot networks with ggplot2
https://briatte.github.io/ggnetwork/
146 stars 28 forks source link

Provide an option to avoid rescaling for geographic network layout #48

Closed Edouard-Legoupil closed 5 years ago

Edouard-Legoupil commented 5 years ago

Referencing this question on stackoverflow: https://stackoverflow.com/questions/49695218/ggnetwork-how-to-set-geographic-information-on-the-vertex -

you can supply coordinates of nodes as matrix. But it uses scale function, and original values got lost, only relative positions kept. So need to undo the scaling, or modify source to bypass scaling. It's in somewhere near line 130 of R/fortify.network.R

Maybe this capacity could be made as an option in the ggnetwork function?

This would allow to plot directly a graph using geographic coordinates without twisting the code...

briatte commented 5 years ago

Thank you for making the suggestion and linking to the SO question.

I'll be adding an option to bypass scaling to the next version.

I took a look at your repos -- very interesting material!

briatte commented 5 years ago

Fixed. Here's an example that uses the development version of ggnetwork (install with devtools or remotes):

library(dplyr)
library(network)
library(nycflights13)
library(ggmap)
library(ggnetwork)
library(ggplot2)

# edges: flights
e <- select(flights, origin, dest) %>%
  group_by(origin, dest) %>%
  tally %>% 
  filter(origin != dest, n > 2500) %>%  # no self-loops + thinning
  filter(origin %in% airports$faa, dest %in% airports$faa) # lose SJU

# weighted directed network
n <- network::network(select(e, origin, dest), directed = TRUE)
set.edge.attribute(n, "weight", e$n) # weight = number of flights

# nodes: airports
y <- filter(airports, faa %in% e$origin | faa %in% e$dest) %>% 
  select(faa, lat, lon)

# sanity check (no missing airports)
stopifnot(nrow(y) == network.size(n))

# named geo coordinate vectors...
lat <- y$lat
names(lat) <- y$faa
lon <- y$lon
names(lon) <- y$faa
# ... as a (x, y) coordinate matrix
geo <- cbind(lon[ network.vertex.names(n) ], lat[ network.vertex.names(n) ])

# geographic network
g <- ggnetwork(n, layout = geo, scale = FALSE) %>% 
  rename(lon = x, lat = y)

# map background
map <- ggmap::get_map(c(left = min(geo[, 1]), bottom = min(geo[, 2]), right = max(geo[, 1]), top = max(geo[, 2])))
# map + network plot
ggmap::ggmap(map) +
  geom_point(data = g, aes(lon, lat)) +
  geom_edges(data = g, aes(lon, lat, xend = xend, yend = yend)) +
  geom_nodelabel(data = g, aes(label = vertex.names))

ggsave("map_example.png")

map_example

Edouard-Legoupil commented 5 years ago

Thanks - Merci!

Edouard-Legoupil commented 5 years ago

I tried to add:

geom_edges(data = g, aes(lon, lat, xend = xend, yend = yend), curvature = 0.01)

and got

Warning message:
geom_curve is not implemented for non-linear coordinates 

Woudl be very nice to have this....

Edouard-Legoupil commented 5 years ago

Found out that the issue is linked with ggmap: https://stackoverflow.com/questions/36501227/draw-curved-lines-in-ggmap-geom-curve-not-working

briatte commented 5 years ago

It looks like the SO question you link to has a valid answer!

Otherwise, you'll have to try (slightly) more complicated code with geom_sf, which should work fine.