Search code examples
rdictionarysubsetgreat-circle

How to connect a subset of nodes using great circles and loops with R


I have the following dataset. To summarize is a list of cities with an Id, longitude and latitude. They are also divided in projects and also they can be a central node (1) or a radial one (0). This is its structure:

> str(cities_sudoe)
'data.frame':   512 obs. of  6 variables:
 $ id     : int  1 2 3 4 5 6 7 8 9 10 ...
 $ city   : Factor w/ 146 levels " Le Passage",..: 90 59 75 44 31 87 108 146 79 79 ...
 $ project: int  1 1 1 1 1 1 1 1 2 2 ...
 $ node   : int  1 0 0 0 0 0 0 0 1 0 ...
 $ lon    : num  -1.131 0.564 -9.139 0.627 2.173 ...
 $ lat    : num  38 44.2 38.7 44.5 41.4 ...

And this is the first rows:

> cities_sudoe
     id                    city project node          lon      lat
1     1                  Murcia       1    1   -1.1306544 37.99224
2     2                Estillac       1    0    0.5641070 44.15717
3     3                  Lisboa       1    0   -9.1393366 38.72225
4     4                 Cancon        1    0    0.6267610 44.53631
5     5               Barcelona       1    0    2.1734035 41.38506
6     6             Montpellier       1    0    3.8767160 43.61077
7     7         Quinta Da Saude       1    0   -8.4359658 37.11729
8     8                Zaragoza       1    0   -0.8890853 41.64882
9     9                  Madrid       2    1   -3.7037902 40.41678
10   10                  Madrid       2    0   -3.7037902 40.41678
11   11                Zaragoza       2    0   -0.8890853 41.64882
12   12                  Lisboa       2    0   -9.1393366 38.72225
13   13                    Auch       2    0    0.5867090 43.64638
14   14                  Cuarte       3    1   -0.9331147 41.59621
15   15                  Madrid       3    0   -3.7037902 40.41678
16   16                 Sevilla       3    0   -5.9844589 37.38909
17   17                  Toledo       3    0  -83.5552120 41.66394
18   18                  Madrid       3    0   -3.7037902 40.41678
19   19                    Albi       3    0    2.1486413 43.92509
20   20                    Albi       3    0    2.1486413 43.92509
21   21                  Lisboa       3    0   -9.1393366 38.72225
22   22                  Lisboa       3    0   -9.1393366 38.72225

As you can see the first city for each project is a central node. So what I need is to connect this first central node with the rest of the cities using GREAT CIRCLES for each project. I have done the first project in the following lines of code. But what I need is a kind of LOOP that repit this process for each project:

# Plotting a simple map
library(maps)
library(sp)
library(geosphere)
xlim <- c(-13.08, 8.68)
ylim <- c(34.87, 49.50)
map("world", col="#191919", fill=TRUE, bg="#000000", lwd=0.05, xlim=xlim, ylim=ylim)
symbols(cities_sudoe$lon, cities_sudoe$lat, bg="#e2373f", fg="#ffffff", lwd=0.5, circles=rep(1, length(cities_sudoe$lon)), inches=0.05, add=TRUE)

# Connecting with great circles 1st project
# lon & lat of central node
lon1 <- cities_sudoe$lon[1]
lat1 <- cities_sudoe$lat[1]
# lon & lat of radial nodes
lon2 <- cities_sudoe$lon[2]
lat2 <- cities_sudoe$lat[2]
lon3 <- cities_sudoe$lon[3]
lat3 <- cities_sudoe$lat[3]
lon4 <- cities_sudoe$lon[4]
lat4 <- cities_sudoe$lat[4]
lon5 <- cities_sudoe$lon[5]
lat5 <- cities_sudoe$lat[5]
lon6 <- cities_sudoe$lon[6]
lat6 <- cities_sudoe$lat[6]
lon7 <- cities_sudoe$lon[7]
lat7 <- cities_sudoe$lat[7]
lon8 <- cities_sudoe$lon[8]
lat8 <- cities_sudoe$lat[8]

inter12 <- gcIntermediate(c(lon1,lat1), c(lon2,lat2), n=6, addStartEnd=TRUE)
inter13 <- gcIntermediate(c(lon1,lat1), c(lon3,lat3), n=6, addStartEnd=TRUE)
inter14 <- gcIntermediate(c(lon1,lat1), c(lon4,lat4), n=6, addStartEnd=TRUE)
inter15 <- gcIntermediate(c(lon1,lat1), c(lon5,lat5), n=6, addStartEnd=TRUE)
inter16 <- gcIntermediate(c(lon1,lat1), c(lon6,lat6), n=6, addStartEnd=TRUE)
inter17 <- gcIntermediate(c(lon1,lat1), c(lon7,lat7), n=6, addStartEnd=TRUE)
inter18 <- gcIntermediate(c(lon1,lat1), c(lon8,lat8), n=6, addStartEnd=TRUE)

lines(inter12, col="#e2373f", lwd=2)
lines(inter13, col="#e2373f", lwd=2)
lines(inter14, col="#e2373f", lwd=2)
lines(inter15, col="#e2373f", lwd=2)
lines(inter16, col="#e2373f", lwd=2)
lines(inter17, col="#e2373f", lwd=2)
lines(inter18, col="#e2373f", lwd=2)

Thanks in advance and sorry for this long post. Ramiro


Solution

  • I think this works:

    lapply(split(cities_sudoe, cities_sudoe$project), function(x) {
      node <- x[x$node == 1, c("lon", "lat")]
      for (i in 2:nrow(x)) lines(gcIntermediate(node, x[i, c("lon", "lat")]))
    })
    

    A breakdown of the different parts, for future reference...

    split(cities_sudoe, cities_sudoe$project) gives back a list of data frames where each one is a separate project

    lapply(..., function(x) {...}) applies a function to each data frame

    node <- x[x$node == 1, c("lon", "lat")] gets longitude and latitude for the project's node

    for (i in 2:nrow(x)) lines(gcIntermediate(node, x[i, c("lon", "lat")])) loops through the non-node points, and draws a great circle from the node to itself. This assumes that the node is always the first row in the project.