Converting geo coordinates from degree to decimal

I want to convert my geographic coordinates from degrees to decimals, my data are as follows:

         lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281

I have this code but I can not see why it is does not work:

convert<-function(coord){
tmp1=strsplit(coord,"°")
tmp2=strsplit(tmp1[[1]][2],"\\.")
dec=c(as.numeric(tmp1[[1]][1]),as.numeric(tmp2[[1]]))
return(dec[1]+dec[2]/60+dec[3]/3600) 
} 
don_convert=don1
for(i in 1:nrow(don1)){don_convert[i,2]=convert(as.character(don1[i,2]));              don_convert[i,3]=convert(as.character(don1[i,3]))}

The convert function works but the code where I am asking the loop to do the job for me does not work.

Any suggestion is apperciated.


Solution 1:

Use the measurements package from CRAN which has a unit conversion function already so you don't need to make your own:

x = read.table(text = "
   lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281",
header = TRUE, stringsAsFactors = FALSE)

Once your data.frame is set up then:

# change the degree symbol to a space
x$lat = gsub('°', ' ', x$lat)
x$long = gsub('°', ' ', x$long)

# convert from decimal minutes to decimal degrees
x$lat = measurements::conv_unit(x$lat, from = 'deg_dec_min', to = 'dec_deg')
x$long = measurements::conv_unit(x$long, from = 'deg_dec_min', to = 'dec_deg')

Resulting in the end product:

                    lat             long
105252 30.4210666666667 9.02218333333333
105253         30.65395 8.18018333333333
105255 31.6293333333333 8.10066666666667
105258          31.6865 8.10928333333333
105259         31.68715 8.11036666666667
105260 31.6481833333333 8.10468333333333

Solution 2:

Try using the char2dms function in the sp library. It has other functions that will additionally do decimal conversion.

library("sp")
?char2dms

Solution 3:

A bit of vectorization and matrix manipulation will make your function much simpler:

x <- read.table(text="
       lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281",
                header=TRUE, stringsAsFactors=FALSE)

x

The function itself makes use of:

  • strsplit() with the regex pattern "[°\\.]" - this does the string split in one step
  • sapply to loop over the vector

Try this:

convert<-function(x){
  z <- sapply((strsplit(x, "[°\\.]")), as.numeric)
  z[1, ] + z[2, ]/60 + z[3, ]/3600
} 

Try it:

convert(x$long)
[1] 9.108611 8.391944 8.111111 8.254722 8.272778 8.178056

Disclaimer: I didn't check your math. Use at your own discretion.

Solution 4:

Thanks for answers by @Gord Stephen and @CephBirk. Sure helped me out. I thought I'd just mention that I also found that measurements::conv_unit doesn't deal with "E/W" "N/S" entries, it requires positive/negative degrees. My coordinates comes as character strings "1 1 1W" and needs to first be converted to "-1 1 1".
I thought I'd share my solution for that.

df <- c("1 1 1E", "1 1 1W", "2 2 2N","2 2 2S")  
measurements::conv_unit(df, from = 'deg_min_sec', to = 'dec_deg')
[1] "1.01694444444444" NA                 NA                 NA  
Warning message:
In split(as.numeric(unlist(strsplit(x, " "))) * c(3600, 60, 1),  :
  NAs introduced by coercion

ewns <- ifelse( str_extract(df,"\\(?[EWNS,.]+\\)?") %in% c("E","N"),"+","-")
dms <- str_sub(df,1,str_length(df)-1)
df2 <- paste0(ewns,dms)

df_dec <- measurements::conv_unit(df2, 
                                  from = 'deg_min_sec', 
                                  to = 'dec_deg'))
df_dec
[1] "1.01694444444444"  "-1.01694444444444" "2.03388888888889"  "-2.03388888888889"
as.numeric(df_dec)
[1]  1.016944 -1.016944  2.033889 -2.033889

Solution 5:

Have a look at the command degree in the package OSMscale.