Search code examples
rgeolocationcoordinatesgeospatiallatitude-longitude

Package convert DMS to latitude longitude coordinates R


I have a dataframe with columns A and B listing coordinates, but they are in DMS format. I wonder if there is a simple way to convert them into Latitudes and Longitudes format with a R package.

Here is a sample of my database:

structure(list(Nom = c("Pont de Normandie", "Pont de Tancarville", 
"Pont de Saint-Nazaire", "Pont de l’Iroise", "Pont d'Aquitaine", 
"Viaduc de Millau", "Pont de Brotonne", "Viaduc du Chavanon", 
"Pont de Térénez", "Pont du Bras de la Plaine"), Portée = c("856", 
"608", "404", "400", "394", "342 (×6)", "320", "300", "285", 
"281"), Long. = c(2141, 1420, 3356, 800, 1767, 2460, 1278, 360, 
515, 305), Type = c("Haubané\nacier, béton précontraint", 
"Suspendu\nacier, béton précontraint, béton armé", "Haubané\nacier, béton précontraint", 
"Haubané\nacier, béton précontraint", "Suspendu\nacier, béton précontraint, pylônes en béton armé", 
"Haubané\nMultihaubané, 7 piles béton, tablier et pylônes caissons acier, suspension axiale", 
"Haubané\nTablier caisson béton, pylônes béton, suspension axiale", 
"Suspendu\nTablier caisson mixte acier/béton, pylônes béton, suspension axiale", 
"Haubané\nTablier courbe dalle béton, pylônes béton", "Treillis mixte acier/béton, précontrainte extérieure"
), `Voie portée
Voie franchie` = c("Autoroute A29\nRoute européenne 44\nSeine", 
"Autoroute A131\nRoute européenne 5\nN182\nSeine", "RD 213\nLoire", 
"RN 165\nRoute européenne 60\nÉlorn", "Autoroute A630\nRoute européenne 5\nRocade de Bordeaux\nGaronne", 
"Autoroute A75\nRoute européenne 11\nGorges du Tarn", "RD 490\nSeine", 
"Autoroute A89\nRoute européenne 70\nChavanon", "RD 791\nAulne", 
"RD 26\nBras de la Plaine"), Date = c("1995", "1959", "1975", 
"1994", "1967", "2004", "1977", "2000", "2011", "2001"), Localisation = c("Le Havre - Honfleur\n", 
"Tancarville - Marais-Vernier\n", "Saint-Nazaire - Saint-Brevin-les-Pins\n", 
"Plougastel-Daoulas - Le Relecq-Kerhuon\n", "Bordeaux\n", "Millau - Creissels\n", 
"Caudebec-en-Caux\n", "Merlines - Messeix\n", "Landévennec - Rosnoën\n", 
"Saint-Pierre - Entre-Deux\n"), A = c("49° 25′ 56,1″ N", 
"49° 28′ 21,6″ N", "47° 17′ 06,3″ N", "48° 23′ 18,1″ N", 
"44° 52′ 47,2″ N", "44° 04′ 48″ N", "49° 31′ 13,9″ N", 
"45° 37′ 26,5″ N", "48° 16′ 07,9″ N", "21° 16′ 35,5″ S"
), B = c("0° 16′ 26,3″ E", "0° 27′ 52,8″ E", 
"2° 10′ 13,8″ O", "4° 23′ 55,6″ O", "0° 32′ 09,7″ O", 
"3° 01′ 20,6″ E", "0° 44′ 49,8″ E", "2° 28′ 47,5″ E", 
"4° 15′ 48,2″ O", "55° 27′ 56,7″ E"), Département = c("Seine-Maritime\nCalvados", 
"Seine-Maritime\nEure", "Loire-Atlantique", "Finistère", "Gironde", 
"Aveyron", "Seine-Maritime", "Corrèze\nPuy-de-Dôme", "Finistère", 
"La Réunion")), row.names = c(NA, -10L), class = c("tbl_df", 
"tbl", "data.frame"))

Solution

  • You don't really need a package for this. A simple function should do the trick:

    dms_to_degrees <- function(dms) {
      sapply(strsplit(dms, "(° )|(' )|(″ )"), function(x) {
        sum(as.numeric(gsub(",", ".", x)[1:3]) * c(1, 1/60, 1/3600)) *
          c(1, -1, 1, -1)[match(x[4], c("N", "S", "E", "O"))]
      })
    }
    

    Which allows:

    dms_to_degrees(df$A)
    #> [1]  49.43225  49.47267  47.28508  48.38836  44.87978  44.08000
    #> [7]  49.52053  45.62403  48.26886 -21.27653
    dms_to_degrees(df$B)
    #> [1]  0.2739722  0.4646667 -2.1705000 -4.3987778 -0.5360278  3.0223889
    #> [7]  0.7471667  2.4798611 -4.2633889 55.4657500
    

    And we can confirm this by drawing a map:

    library(ggplot2)
    
    ggplot(data = map_data("world")) +
      geom_map(map = map_data("world"), aes(long, lat, map_id = region),
               fill = "#d0e890", color = "gray50") +
      geom_point(data = within(df, {lat <- dms_to_degrees(A);
                                    long <- dms_to_degrees(B)}),
                 aes(x = long, y = lat), color = 'red')
    

    enter image description here