Converting latitude and longitude data to UTM with points from multiple UTM zones in R
UPDATE
Here is a much faster and elegant workaround using dplyr
and spTransfrom
Augmented data (60k+ rows):
test_coordinates <- data.frame(x = c(13.637398, -3.58627, -5.178889), y = c(41.30736, 40.72913, 40.17528), x_correct = c(385936, 450492, 314480), y_correct = c(4573773, 4508854, 4449488 ), zone = c(33, 30, 30), key = c(1, 2, 3), country = c("italy", "spain", "spain"))
test_coordinates = rbind(test_coordinates, test_coordinates[rep(1,60*1000),]) # simulate big data
library(dplyr)
library(sp)
get_utm <- function(x, y, zone, loc){
points = SpatialPoints(cbind(x, y), proj4string = CRS("+proj=longlat +datum=WGS84"))
points_utm = spTransform(points, CRS(paste0("+proj=utm +zone=",zone[1]," +ellps=WGS84")))
if (loc == "x") {
return(coordinates(points_utm)[,1])
} else if (loc == "y") {
return(coordinates(points_utm)[,2])
}
}
test_coordinates %<>%
mutate(zone2 = (floor((x + 180)/6) %% 60) + 1, keep = "all"
) %>%
group_by(zone2) %>%
mutate(utm_x = get_utm(x, y, zone2, loc = "x"),
utm_y = get_utm(x, y, zone2, loc = "y"))
Output (5 rows only)
test_coordinates
# A tibble: 603 × 10
# Groups: zone2 [2]
x y x_correct y_correct zone key country zone2 utm_x utm_y
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl> <dbl>
1 13.6 41.3 385936 4573773 33 1 italy 33 385936. 4573773.
2 -3.59 40.7 450492 4508854 30 2 spain 30 450492. 4508854.
3 -5.18 40.2 314480 4449488 30 3 spain 30 314480. 4449488.
4 13.6 41.3 385936 4573773 33 1 italy 33 385936. 4573773.
5 13.6 41.3 385936 4573773 33 1 italy 33 385936. 4573773.
ORIGINAL RESPONSE
Replace:
data.frame(t(sapply(converted_points,c))) #Makes this list into a dataframe
With:
test_coordinates$utm_x <- unlist(converted_points)[c(T,F)]
test_coordinates$utm_y <- unlist(converted_points)[c(F,T)]
x y x_correct y_correct zone key country utm_x utm_y
1 13.637398 41.30736 385936 4573773 33 1 italy 385935.7 4573773
2 -3.586270 40.72913 450492 4508854 30 2 spain 450492.4 4508854
3 -5.178889 40.17528 314480 4449488 30 3 spain 314479.5 4449488
Convert lat long to utm NAD83 zone 20
I got this code from an online source (don't have the reference handy):
LongLatToUTM<-function(x,y,zone){
require(sp)
xy <- data.frame(ID = 1:length(x), X = x, Y = y)
coordinates(xy) <- c("X", "Y")
proj4string(xy) <- CRS("+proj=longlat +datum=WGS84") ## for example
res <- spTransform(xy, CRS(paste("+proj=utm +zone=",zone," ellps=WGS84",sep='')))
return(as.data.frame(res))
}
Note that this is for WGS84
.
Converting latitude and longitude to UTM coordinates in pyspark
Something like this,
import pyspark.sql.functions as F
import utm
from pyspark.sql.types import *
utm_udf_x = F.udf(lambda x,y: utm.from_latlon(x,y)[0], FloatType())
utm_udf_y = F.udf(lambda x,y: utm.from_latlon(x,y)[1], FloatType())
df = df.withColumn('UTM_x',utm_udf_x(F.col('lat'), F.col('lon')))
df = df.withColumn('UTM_y',utm_udf_y(F.col('lat'), F.col('lon')))
Although I am not sure why did you write [1]
at the end.
using boost::geometry to convert from Latitude and longitude to UTM
I just spent an embarrassing amount of time looking for this (multiple hours).
It seems like everything spherical (SRS) is just ... not documented at all. Perhaps there's something broken with the documentation generator.
Regardless, several tedious searches through test code further I stumbled on a working answer.
Here's examples
- Amsterdam (UTM 629144.77 Easting 5803996.66 Northing in zone 31U)
- Barcelona (UTM 430887.56 Easting, 4581837.85 Northing, zone 31T)
With even more stumbling I found the corresponding EPSG code on https://epsg.io/?q=UTM+31N:
Live On Compiler Explorer
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/srs/epsg.hpp>
#ifdef COLIRU
#include <boost/geometry/srs/projection.hpp>
#endif
namespace bg = boost::geometry;
namespace bm = bg::model::d2;
namespace srs = bg::srs;
using LongLat = bm::point_xy<double, bg::cs::geographic<bg::degree> >;
using UTM = bm::point_xy<double/*, srs::static_epsg<3043>*/>;
constexpr LongLat Amsterdam() { return { 4.897, 52.371}; }
constexpr LongLat Barcelona() { return { 2.1734, 41.3851 }; }
void report(LongLat src, auto const& prj) {
UTM r {};
prj.forward(src, r);
std::cout << std::fixed << bg::wkt(src) << " -> " << bg::wkt(r) << "\n";
}
int main() {
#ifndef COLIRU
// dynamic projection factory too heavy on Coliru
srs::projection<> zone31 = srs::proj4("+proj=utm +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +zone=31");
report(Amsterdam(), zone31);
report(Barcelona(), zone31);
#endif
srs::projection<srs::static_epsg<3043> > epsg3043;
report(Amsterdam(), epsg3043);
report(Barcelona(), epsg3043);
}
Prints
POINT(4.897000 52.371000) -> POINT(629144.771310 5803996.656944)
POINT(2.173400 41.385100) -> POINT(430887.564331 4581837.853239)
POINT(4.897000 52.371000) -> POINT(629144.771310 5803996.656944)
POINT(2.173400 41.385100) -> POINT(430887.564331 4581837.853239)
Disclaimer:
I'm not actually convinced that the UTM
point type I defined makes much sense. I think any point type that can receive 2 coordinates will do. At least the srs::...
as the coordinate system doesn't seem to do anything - bg::convert, bg::assign and friends don't magically know how to apply the projection anyways. I think the "doxygen_z_article09" link you included is just badly out of date/not how things were eventually implemented.
Determining UTM zone (to convert) from longitude/latitude
Edit: For (non-R) code that works for all non-polar areas on earth, see here or here.
Unless you are dealing with data from a couple of exceptional areas (Svalbard and parts of Norway), this is a simple enough calculation that you might as well just do it yourself in R. Here is Wikipedia's description of how longitude relates to UTM Zone number:
The UTM system divides the surface of Earth between 80°S and 84°N latitude into 60 zones, each 6° of longitude in width. Zone 1 covers longitude 180° to 174° W; zone numbering increases eastward to zone 60 that covers longitude 174 to 180 East.
So, assuming that in your data longitudes to the west of the Prime Meridian are encoded as running from -180 to 0 degrees, here's an R-code version of the above:
long2UTM <- function(long) {
(floor((long + 180)/6) %% 60) + 1
}
# Trying it out for San Francisco, clearly in UTM Zone 10
# in the figure in the Wikipedia article linked above
SFlong <- -122.4192
long2UTM(SFlong)
# [1] 10
That expression could obviously be simplified a bit, but I think in this form the logic underlying its construction is most clear. The %% 60
bit is in there just in case some of your longitudes are greater than 180 or less than -180.
Related Topics
Apply a Function to Every Row of a Matrix or a Data Frame
How to Specify the Actual X Axis Values to Plot as X Axis Ticks in R
How to Add a Ggplot2 Subtitle with Different Size and Colour
Is There a Better Alternative Than String Manipulation to Programmatically Build Formulas
How to Convert R Markdown to HTML? I.E., What Does "Knit HTML" Do in Rstudio 0.96
How to Connect R with Access Database in 64-Bit Window
How to Calculate Combination and Permutation in R
How to Create a Marimekko/Mosaic Plot in Ggplot2
How to Change Library Location in R
Convert Named Character Vector to Data.Frame
Problems When Trying to Load a Package in R Due to Rjava
Add Empty Columns to a Dataframe with Specified Names from a Vector
Convert a Numeric Month to a Month Abbreviation
Add Error Bars to Show Standard Deviation on a Plot in R
How to Place Grobs with Annotation_Custom() at Precise Areas of the Plot Region