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
R Command for Setting Working Directory to Source File Location in Rstudio
Sending Email in R via Outlook
Shiny: Differencebetween Observeevent and Eventreactive
How to Detect the Right Encoding for Read.Csv
Ggplot2: Facet_Wrap Strip Color Based on Variable in Data Set
Create Dynamic Number of Input Elements with R/Shiny
Extract Every Nth Element of a Vector
Operator == Inconsistent in Logical Columns in Data.Table
Remove Ids That Occur X Times R
How to Generate All Possible Combinations of Vectors Without Caring for Order
How to Count the Frequency of a String for Each Row in R
Floating Point Less-Than-Equal Comparisons After Addition and Substraction
How to Access the Last Value in a Vector
Changing Font Size and Direction of Axes Text in Ggplot2
Remove All of X Axis Labels in Ggplot
What's the Difference Between '1L' and '1'