简体   繁体   中英

(lat, lon) WKT coordinates do not reproject well with st_transform

I am having some issues importing a file with wkt multipoint features with SRID 4326, for which the coordinates are in order (lat, lon):

>st_crs(4326) 
Coordinate Reference System:
  User input: EPSG:4326 
  wkt:
GEOGCRS["WGS 84",
DATUM["World Geodetic System 1984",
    ELLIPSOID["WGS 84",6378137,298.257223563,
        LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
    ANGLEUNIT["degree",0.0174532925199433]],
CS[ellipsoidal,2],
    AXIS["geodetic latitude (Lat)",north,
        ORDER[1],
        ANGLEUNIT["degree",0.0174532925199433]],
    AXIS["geodetic longitude (Lon)",east,
        ORDER[2],
        ANGLEUNIT["degree",0.0174532925199433]],
USAGE[
    SCOPE["Horizontal component of 3D system."],
    AREA["World."],
    BBOX[-90,-180,90,180]],
ID["EPSG",4326]]

So I "load" and assign the crs as follows (just one row shown for reproducible example, but this will be hundreds of lines

tst <- data.frame(ID = "Test", 
       SRIDTrail = 4326, 
       Trail = "MULTIPOINT (52.86 -8.00, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98,
                            52.89 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98,
                            52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.97)")

tst_sf <- tst %>% 
  st_as_sf(wkt = "Trail") %>% 
  st_set_crs(4326)

Now, let's download the world map from the naturalearth package, and check its CRS:

library(rnaturalearth)
world <- ne_countries(scale = "medium", returnclass = "sf")
st_crs(world)

which gives

Coordinate Reference System:
  User input: +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
  wkt:
BOUNDCRS[
    SOURCECRS[
        GEOGCRS["unknown",
        DATUM["World Geodetic System 1984",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]],
            ID["EPSG",6326]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8901]],
        CS[ellipsoidal,2],
            AXIS["longitude",east,
                ORDER[1],
                ANGLEUNIT["degree",0.0174532925199433,
                    ID["EPSG",9122]]],
            AXIS["latitude",north,
                ORDER[2],
                ANGLEUNIT["degree",0.0174532925199433,
                    ID["EPSG",9122]]]]],
TARGETCRS[
    GEOGCRS["WGS 84",
        DATUM["World Geodetic System 1984",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        CS[ellipsoidal,2],
            AXIS["latitude",north,
                ORDER[1],
                ANGLEUNIT["degree",0.0174532925199433]],
            AXIS["longitude",east,
                ORDER[2],
                ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4326]]],
ABRIDGEDTRANSFORMATION["Transformation from unknown to WGS84",
    METHOD["Geocentric translations (geog2D domain)",
        ID["EPSG",9603]],
    PARAMETER["X-axis translation",0,
        ID["EPSG",8605]],
    PARAMETER["Y-axis translation",0,
        ID["EPSG",8606]],
    PARAMETER["Z-axis translation",0,
        ID["EPSG",8607]]]]

which states that the first axis corresponds to longitude, not latitude. So, first thing I try (because it'll be faster) is to transform my data to the same projection of the world map, and then plot them both:

tst_sf2 <- tst_sf %>% st_transform(st_crs(world))
ggplot(tst_sf2) + 
  geom_sf(data = world) +
  geom_sf(col = "red") + 
  theme_bw() 

This has not worked, as the point that was supposed to be in Ireland is plotted in the Indian ocean, the location with the "swapped" coordinates, that is, lat -8, lon 53). 在此处输入图片说明

Let's try the other way round, transform the world map, and not the wtk.

world2 <- world %>% st_transform(st_crs(tst_sf))
ggplot(tst_sf) + 
  geom_sf(data = world2) +
  geom_sf(col = "red") + 
  theme_bw() 

This still does not work: 在此处输入图片说明

So, my questions are:

(1) Is there any EPSG code I can use that could make R understand the coordinates in the WKT file are swapped with respect to what is expected (I don't mean to enter into the discussion of which order should it be, just to fix it!)

(2) In case that's not possible, how can I change the order of the coordinates, taking into account there will be hundreds of rows and not all multipoints features will be the same length.

Please find another solution that takes advantage of the argument authority_compliant = st_axis_order(FALSE/TRUE) of the sf_project() function.

  • Your data
# The map
world <- ne_countries(scale = "medium", returnclass = "sf")

# Your point(s)
tst <- data.frame(ID = "Test",
                  SRIDTrail = 4326,
                  Trail = "MULTIPOINT (52.86 -8.00, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.89 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.97)")

tst_sf <- tst %>% 
  st_as_sf(wkt = "Trail", crs = 4326) # please, note that I lightened your code a little bit here.
  • Code
# set the new geometry (i.e. lon-lat instead of lat-long)
RightOrder <- sf_project(from = st_crs(tst_sf), 
                         to = st_crs(world), 
                         matrix(unlist(tst_sf$Trail), 
                                nrow = lapply(tst_sf$Trail, length)[[1]]/2, 
                                ncol = 2), 
                         authority_compliant = st_axis_order(TRUE)) %>% # the argument that allows to choose the order of the axes: lat-lon (FALSE) and lon-lat (TRUE) 
  as.data.frame() %>% 
  setNames(., c("lon", "lat")) %>% 
  st_as_sf(coords = c("lon", "lat"), crs = 4326) %>% 
  st_cast("MULTIPOINT") %>% 
  st_union()

# drop the previous geometry and add the new one
tst_sf <- tst_sf %>%
  st_drop_geometry() %>%
  st_sf(.,RightOrder)

# visualize the result
ggplot(tst_sf) + 
  geom_sf(data = world) +
  geom_sf(col = "red") + 
  theme_bw() 
  • Result

在此处输入图片说明

Here is a brute force method, not the most efficient but it seems to work.

tst <- data.frame(ID = "Test", 
                  SRIDTrail = 4326, 
                  Trail = "MULTIPOINT (52.86 -8.00, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.89 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.98, 52.85 -7.97)")

tst_sf <- tst %>% st_as_sf(wkt = "Trail") %>% st_set_crs(4326)

#get the latitude & longitude
coordinates <- unlist(tst_sf$Trail)
lat <- coordinates [1:(length(coordinates)/2)]
lon <- coordinates [(length(coordinates)/2+1):length(coordinates)]

#rearrange the columns
#convert back into MULTIPOINT and 
tst_sf$Trail <-sfheaders::sfc_multipoint( matrix(c(lon, lat), ncol=2, byrow=FALSE) )
#redefine the CRS
tst_sf <- tst_sf %>% 
   st_as_sf(wkt = "Trail") %>% 
   st_set_crs(4326)

library(rnaturalearth)
world <- ne_countries(country = 'ireland', scale = "medium", returnclass = "sf")
#st_crs(world)
tst_sf2 <- tst_sf %>% st_transform(st_crs(world))
ggplot(tst_sf2) + 
   geom_sf(data = world) +
   geom_sf(col = "red") + 
   theme_bw() 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM