m0ssyb00ts
m0ssyb00ts

Reputation: 53

How to convert coordinates from degree decimal minutes to decimal degrees in R?

I am trying to convert a group of 40 coordinates from degree decimal minute format into decimal degree format for latitude and longitude. I have included some coordinates here that are in my existing format:

         lat        long
1   49°46.938   76°62.082
2   49°47.957   70°22.089
3   49°48.938   69°07.043
4   49°48.936   79°72.022
5   49°48.950   73°62.060
6   49°46.749   70°92.214
7   49°47.736   73°92.223
8   49°46.707   79°52.232
9   49°47.680   80°32.123
10  49°46.678   79°02.123
11  49°47.678   79°82.123
12  49°96.694   75°32.123
13  49°97.713   70°92.091
14  49°46.555   71°72.143
15  49°47.575   72°32.143
16  49°46.472   79°62.276
17  49°47.689   79°82.664
18  49°46.622   70°22.255
19
20  49°65.681   79°74.632
21  49°46.693   73°08.656
22  49°65.682   72°09.695
23  49°47.645   72°09.703
24  49°42.673   74°55.727
25  49°43.903   73°09.750
26  49°98.762   73°83.754
27  45°43.604   70°92.869
28  49°37.202   78°03.843
29  49°38.287   79°33.709
30  49°94.308   74°44.439
31  49°94.777   79°35.404
32      
33  49°37.723   79°87.833
34  49°78.664   79°07.844
35  49°60.877   75°60.855
36  49°03.336   73°22.851
37  49°52.496   88°88.861
38  49°38.940   79°67.871
39  49°96.049   79°54.881
40  49°37.240   78°39.892

Maintaining the row order is important so I can bind these columns back into my original dataframe. For this reason, I don't want to drop the rows of blank entries.

So far I have tried applying the conv_unit function from the measurements package, and that will work but only until row 19 for converting the latitude coordinates. It will then produce the warning message "data length is not a multiple of split variable", which I assume explains why the conversion stops after row 19 (although I'm not sure ). The longitude coordinates won't convert at all, and I will receive the following error message: "Error: 'conv_units' is not an exported object from 'namespace:measurements'."

I am trying to avoid doing the conversions by hand to reduce calculation errors, and so was hoping to find a function to help me. It seems like the measurements package is the ticket, but I can't seem to work through these issues.

How can I convert ALL of my lat/long coordinates into decimal degree format from their current degree decimal minute format?

Upvotes: 3

Views: 2592

Answers (3)

Marcos
Marcos

Reputation: 51

I found the great package parzer (https://github.com/ropensci/parzer) that solves all these kind of issues

lat = c("49°46.938", "49°47.957", "49°48.938", "49°48.936", "49°48.950", "49°46.749", "49°47.736", "49°46.707", "49°47.680", "49°46.678", "49°47.678", "49°96.694", "49°97.713", "49°46.555", "49°47.575", "49°46.472", "49°47.689", "49°46.622", "", "49°65.681", "49°46.693", "49°65.682", "49°47.645", "49°42.673", "49°43.903", "49°98.762", "45°43.604", "49°37.202", "49°38.287", "49°94.308", "49°94.777", "", "49°37.723", "49°78.664", "49°60.877", "49°03.336", "49°52.496", "49°38.940", "49°96.049", "49°37.240")
long = c("76°62.082", "70°22.089", "69°07.043", "79°72.022", "73°62.060", "70°92.214", "73°92.223", "79°52.232", "80°32.123", "79°02.123", "79°82.123", "75°32.123", "70°92.091", "71°72.143", "72°32.143", "79°62.276", "79°82.664", "70°22.255", "", "79°74.632", "73°08.656", "72°09.695", "72°09.703", "74°55.727", "73°09.750", "73°83.754", "70°92.869", "78°03.843", "79°33.709", "74°44.439", "79°35.404", "", "79°87.833", "79°07.844", "75°60.855", "73°22.851", "88°88.861", "79°67.871", "79°54.881", "78°39.892")


parzer::parse_lon_lat(lon = long, lat = lat)
# lon      lat
# 1  77.03470 49.78230
# 2  70.36815 49.79928
# 3  69.11739 49.81563
# 4  80.20036 49.81560
# 5  74.03433 49.81583
# 6  71.53690 49.77915
# 7  74.53705 49.79560
# 8  79.87054 49.77845
# 9  80.53539 49.79467
# 10 79.03539 49.77797
# 11 80.36871 49.79463
# 12 75.53539 50.61157
# 13 71.53485 50.62855
# 14 72.20238 49.77592
# 15 72.53571 49.79292
# 16 80.03793 49.77453
# 17 80.37773 49.79482
# 18 70.37092 49.77703
# 19      NaN      NaN
# 20 80.24387 50.09468
# 21 73.14426 49.77822
# 22 72.16158 50.09470
# 23 72.16172 49.79408
# 24 74.92878 49.71122
# 25 73.16250 49.73172
# 26 74.39590 50.64603
# 27 71.54781 45.72673
# 28 78.06405 49.62003
# 29 79.56181 49.63811
# 30 74.74065 50.57180
# 31 79.59007 50.57962
# 32      NaN      NaN
# 33 80.46388 49.62872
# 34 79.13073 50.31107
# 35 76.01425 50.01462
# 36 73.38085 49.05560
# 37 89.48102 49.87494
# 38 80.13118 49.64900
# 39 79.91468 50.60081
# 40 78.66486 49.62067
# Warning messages:
#   1: In base::.Call(...) : no digits detected, got:   
#   2: In base::.Call(...) : no digits detected, got:   
#   3: In base::.Call(...) : no digits detected, got:   
#   4: In base::.Call(...) : no digits detected, got:  

Upvotes: 4

m0ssyb00ts
m0ssyb00ts

Reputation: 53

It turns out that the measurements package works, but it requires that you modify the input coordinates into a particular format (i.e., with the units separated by a space). The reason the package wasn't initially working for me is because I didn't have my input in the correct format!

df$column <- measurements::conv_unit(df$column, from = 'deg_dec_min', to = 'dec_deg') # convert lat column from degrees and decimal minutes into decimal degrees

Upvotes: 1

jay.sf
jay.sf

Reputation: 73702

You may do that pretty easily, since R is vectorized. Just divide the relevant substrings by 60 with a small function in an sapply.

f <- function(x) as.double(substr(x, 1, 2)) + as.double(substring(x, 3)) / 60

sapply(d, f)
#            lat     long
#  [1,] 49.78230 77.03470
#  [2,] 49.79928 70.36815
#  [3,] 49.81563 69.11738
#  [4,] 49.81560 80.20037
#  [5,] 49.81583 74.03433
#  [6,] 49.77915 71.53690
#  [7,] 49.79560 74.53705
#  [8,] 49.77845 79.87053
#  [9,] 49.79467 80.53538
# [10,] 49.77797 79.03538
# [11,] 49.79463 80.36872
# [12,] 50.61157 75.53538
# [13,] 50.62855 71.53485
# [14,] 49.77592 72.20238
# [15,] 49.79292 72.53572
# [16,] 49.77453 80.03793
# [17,] 49.79482 80.37773
# [18,] 49.77703 70.37092
# [19,]       NA       NA
# [20,] 50.09468 80.24387
# [21,] 49.77822 73.14427
# [22,] 50.09470 72.16158
# [23,] 49.79408 72.16172
# [24,] 49.71122 74.92878
# [25,] 49.73172 73.16250
# [26,] 50.64603 74.39590
# [27,] 45.72673 71.54782
# [28,] 49.62003 78.06405
# [29,] 49.63812 79.56182
# [30,] 50.57180 74.74065
# [31,] 50.57962 79.59007
# [32,]       NA       NA
# [33,] 49.62872 80.46388
# [34,] 50.31107 79.13073
# [35,] 50.01462 76.01425
# [36,] 49.05560 73.38085
# [37,] 49.87493 89.48102
# [38,] 49.64900 80.13118
# [39,] 50.60082 79.91468
# [40,] 49.62067 78.66487

Data:

d <- structure(list(lat = c(4946.938, 4947.957, 4948.938, 4948.936, 
4948.95, 4946.749, 4947.736, 4946.707, 4947.68, 4946.678, 4947.678, 
4996.694, 4997.713, 4946.555, 4947.575, 4946.472, 4947.689, 4946.622, 
NA, 4965.681, 4946.693, 4965.682, 4947.645, 4942.673, 4943.903, 
4998.762, 4543.604, 4937.202, 4938.287, 4994.308, 4994.777, NA, 
4937.723, 4978.664, 4960.877, 4903.336, 4952.496, 4938.94, 4996.049, 
4937.24), long = c(7662.082, 7022.089, 6907.043, 7972.022, 7362.06, 
7092.214, 7392.223, 7952.232, 8032.123, 7902.123, 7982.123, 7532.123, 
7092.091, 7172.143, 7232.143, 7962.276, 7982.664, 7022.255, NA, 
7974.632, 7308.656, 7209.695, 7209.703, 7455.727, 7309.75, 7383.754, 
7092.869, 7803.843, 7933.709, 7444.439, 7935.404, NA, 7987.833, 
7907.844, 7560.855, 7322.851, 8888.861, 7967.871, 7954.881, 7839.892
)), class = "data.frame", row.names = c("1", "2", "3", "4", "5", 
"6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", 
"17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", 
"28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", 
"39", "40"))

Upvotes: 3

Related Questions