Converting Geo Coordinates from Degree to Decimal

Converting geo coordinates from degree to decimal

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

How to recalculate latitude and decimal minutes to decimal degrees when values are numeric?

I simply implemented your calculation mentioned in the post to have the conversion on complete dataframe. Hope this helps!

df <- read.table(text="lat        long
5542.780 1204.000
5540.463 1005.425
5639.760 958.420", header=T, sep="")
df

df_converted <- sapply(df, function(x)
as.numeric(gsub("(.*)(\\d{2}\\.\\d+)", "\\1", formatC(as.numeric(x),format='f',digits=3,flag='0'))) +
(as.numeric(gsub("(.*)(\\d{2}\\.\\d+)", "\\2", formatC(as.numeric(x),format='f',digits=3,flag='0')))/ 60))
df_converted

Output is:

          lat      long
[1,] 55.71300 12.066667
[2,] 55.67438 10.090417
[3,] 56.66267 9.973667

Convert DMS coordinates to decimal degrees in R

You are right! To tell you the truth, I didn't notice this problem.
To get around this, here is a solution with the use of the package measurements:

REPREX:

install.packages("measurements") 
library(measurements)

lat <- conv_unit('21 11 24.32', from = "deg_min_sec", to = "dec_deg")
long <- conv_unit('104 38 26.88' , from = "deg_min_sec", to = "dec_deg")

print(c(lat, long))
#> [1] "21.1900888888889" "104.6408"

Created on 2021-10-07 by the reprex package (v2.0.1)



Edit from OP

This can also be solved by adding 'N' or 'S' to latitude and 'E' or 'W' to longitude.

# Add character to lat & long strings
> lat_d <- char2dms(paste0(lat,'N'), chd='d', chm='m', chs='s') %>% as.numeric()
> lng_d <- char2dms(paste0(lng,'W'), chd='d', chm='m', chs='s') %>% as.numeric()
> print(c(lat_d, lng_d))
[1] 21.19009 -104.64080

Converting coordinates from degree with unconventional format to decimal degree

You can use the following custom function (I am assuming N, S, W, E. Not sure what O means in longitude):

angle2dec <- function(angle) {
angle <- as.character(angle)
angle <- ifelse(grepl("S|W", angle), paste0("-", angle), angle)
angle <- trimws(gsub("[^- +.0-9]", "", angle))
x <- do.call(rbind, strsplit(angle, split=' '))
x <- apply(x, 1L, function(y) {
y <- as.numeric(y)
(abs(y[1]) + y[2]/60 + y[3]/3600) * sign(y[1])
})
return(x)
}

Applying on the data:

df1[] <- lapply(df1, angle2dec)

df1
#> Latitud Longitud
#> 1 -40.42388 3.712197
#> 2 40.42156 -3.682283

Plotting:

library(ggplot2)

ggplot(df1, aes(x = Longitud, y = Latitud)) +
geom_point()


Slightly Modified Data to Show for Different Hemispheres:

df1 <- structure(list(Latitud = c("40<U+623C><U+3E61> 25' 25.98'' S", 
"40<U+623C><U+3E61> 25' 17.63'' N"),
Longitud = c("3<U+623C><U+3E61> 42' 43.91'' E",
"3<U+623C><U+3E61> 40' 56.22'' W")),
class = c("tbl_df", "tbl", "data.frame"),
row.names = c(NA, -2L))

In reference to Converting geo coordinates from degree to decimal .

Converting pandas data frame with degree minute second (DMS) coordinates to decimal degrees

Basing my answer on a function from SO you can do it like this:

Interestingly this answer is also 2x as fast as MaxU and Amis answer for a dataset with +500 rows. My bet is that the bottleneck is str.extract(). But something is clearly strange.

import pandas as pd
import re

#https://stackoverflow.com/questions/33997361
def dms2dd(s):
# example: s = """0°51'56.29"S"""
degrees, minutes, seconds, direction = re.split('[°\'"]+', s)
dd = float(degrees) + float(minutes)/60 + float(seconds)/(60*60);
if direction in ('S','W'):
dd*= -1
return dd

df = pd.DataFrame({'CPO': {0: 'Raya', 1: 'Raya'},
'Latitude': {0: '0°51\'56.29"S', 1: '1°23\'39.29"S'},
'Longitude': {0: '101°26\'46.29"E', 1: '101°35\'30.45"E'},
'PKO': {0: 'X', 1: 'X'},
'ParentCompany': {0: 'Incasi', 1: 'Incasi'}})

df['Latitude'] = df['Latitude'].apply(dms2dd)
df['Longitude'] = df['Longitude'].apply(dms2dd)

printing df returns:

    CPO   Latitude   Longitude PKO ParentCompany
0 Raya -0.865636 101.446192 X Incasi
1 Raya -1.394247 101.591792 X Incasi

Update: To correct your mistake you could do something in the lines of:

m = df['Latitude'].str[-2] != '"'
df.loc[m, 'Latitude'] = df.loc[m, 'Latitude'].str[:-1] + '"' + df.loc[m, 'Latitude'].str[-1]

Full example:

import re

s1 = """0°51'56.29"S"""
s2 = """0°51'56.29S"""

df = pd.Series((s1,s2)).to_frame(name='Latitude')

m = df['Latitude'].str[-2] != '"'
df.loc[m, 'Latitude'] = df.loc[m, 'Latitude'].str[:-1] + '"' + df.loc[m, 'Latitude'].str[-1]

print(df)

Converting projected coordinates into decimals

You can repeat your previous steps, but switch the projections in proj4string and spTransform.

library(rgdal)

data_old <- data
coordinates(data_old) <- c("Longitude", "Latitude")
proj4string(data_old) <- CRS("+init=epsg:4326")
data_old <- spTransform(data_old, CRS("+init=epsg:5321"))
data_old <- as.data.frame(data_old)

# ID Longitude Latitude
# 1 1 451077.2 7117021
# 2 1 451037.6 7116991
# 3 1 451051.2 7116956

Then, you can just switch the projection in your code to revert back to the original coordinates.

data_new <- data_old
coordinates(data_new) <- c("Longitude", "Latitude")
proj4string(data_new) <- CRS("+init=epsg:5321")
data_new <- spTransform(data_new, CRS("+init=epsg:4326"))
data_new <- as.data.frame(data_new)

Output

  ID Longitude Latitude
1 1 -93.2552 58.0879
2 1 -93.2558 58.0876
3 1 -93.2555 58.0873

Another option using tidyverse and sf could be:

library(tidyverse)
library(sf)

data_old %>%
st_as_sf(coords = c("Longitude", "Latitude"), dim = "XY") %>%
st_set_crs(5321) %>%
st_transform(4326) %>%
as.data.frame() %>%
extract(geometry,
c('Longitude', 'Latitude'),
'\\((.*), (.*)\\)',
convert = TRUE)

Data

data <-
structure(
list(
ID = c(1, 1, 1),
Longitude = c(-93.2552,-93.2558,-93.2555),
Latitude = c(58.0879, 58.0876, 58.0873)
),
class = "data.frame",
row.names = c(NA,-3L)
)


Related Topics



Leave a reply



Submit