10

The longitude in CMIP5 future climate data is in 0 - 360 degree. How can I convert it to -180 - 180 degree using the raster package?

I tried with shift(r0,-180) and shift(r0,-360). It does not work. Any help will be appreciated. r0 here is a raster.

David Arenburg
  • 91,361
  • 17
  • 137
  • 196
user1617676
  • 361
  • 1
  • 3
  • 12

3 Answers3

20

Try rotate(). Its help page even mentions its utility with the type of data you're dealing with:

Rotate a Raster* object that has x coordinates (longitude) from 0 to 360, to standard coordinates between -180 and 180 degrees. Longitude between 0 and 360 is frequently used in data from global climate models.

Here's a simple reproducible example to show what it does:

library(raster)
r <- raster(matrix(1:100, ncol=10), 0, 360, -90, 90, crs="+proj=merc")
r2 <- rotate(r)
r2
# class       : RasterLayer 
# dimensions  : 10, 10, 100  (nrow, ncol, ncell)
# resolution  : 36, 18  (x, y)
# extent      : -180, 180, -90, 90  (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=merc 
# data source : in memory
# names       : layer 
# values      : 1, 100  (min, max)
Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
  • 1
    1+ It's really RTM, but sometimes the cognitive task is interesting. When your answer appeared I was holding my thumbs and forefinger in a circle, alternately opening them between the thumbs and then between the forefingers, and mentally figuring out what sort of remapping was needed to bring the opposite "180's" back together properly. – IRTFM Sep 08 '14 at 19:42
  • @BondedDust -- I think the function needed to capture that remapping is `((long + 180) %% 360) - 180`. Its only (ultimately inconsequential) infelicity is that it remaps to 180 to -180... – Josh O'Brien Sep 08 '14 at 20:22
  • Right, modulo operations do define a mathematical ring. – IRTFM Sep 08 '14 at 20:26
  • Out of curiosity, is there a function to 'unrotate' or rotate from standard coordinates (-180 to 180) BACK to 0-to-360? I am a fish biologist trying to hack my way through global climate models in R, so I don't know if this is even an operation that is useful, but I noticed that when you run 'rotate(r2)' using r2 from your code above, the extent becomes (-36 to 180). Thanks! – Poquontchn Mar 27 '20 at 00:52
  • 1
    @Poquontchn This seems to do the trick: `r3 <- shift(rotate(shift(r2, dx=180)), dx=180)`. Then, with the exception of the `@data@names` slot, `r3` is identical to the original raster. (To confirm that, do `r3@data@names <- r@data@names; identical(r3, r)`.) – Josh O'Brien Mar 27 '20 at 02:08
  • @JoshO'Brien That does it, thanks! Another amateur question (and I can post it as its own question if you think it might be warranted); can an object of class SpatialPointsDataFrame be switched between one longitude system (-180to180) and the other (0to360)? I solved my issue by converting coordinates in my csv before coercing to SPDF, but was wondering if there is a more efficient way to convert them within an existing SPDF. Thanks again! – Poquontchn Mar 27 '20 at 07:11
  • 1
    @Poquontchn If you actually want to change the values of your coordinates, you could recompute the x-coordinates using the formula I included in my comment above, from 2014. Usually better would be to just reproject when you are ready to plot the data. Most projections (e.g. [here](https://proj.org/operations/projections/eqc.html)) include a `"+lon_0="` flag that you can use to set the central meridian. So, for example, if you've got a `SpatialPoints` object `cities`, you could project to that projection with a central meridian of 180 by doing `spTransform(cities, CRS("+proj=eqc +lon_0=180"))` – Josh O'Brien Mar 27 '20 at 17:48
5

It's pretty simple:

ifelse(r0 > 180, -360 + r0, r0)
Señor O
  • 17,049
  • 2
  • 45
  • 47
  • I'm not your downvote, but 179 and 181 are two degrees apart in the original, so they should probably map to 179 and -179 after the transform. I think you want `-360 + r0`. – Gregor Thomas Sep 08 '14 at 18:26
  • Sorry, I forgot to mention that r0 is a raster file. so, the ifelse function does not work in this case. – user1617676 Sep 08 '14 at 18:33
2

This is kind of a hack and there's probably a much easier way to do that in raster, but here is an option. First, you need to create a matrix from your raster object, then modify some longitude values (only the ones that are > 180) and switch back to a raster. The marmap package can do the back and forth switching for you:

# Switching from a raster to a matrix of class 'bathy'
library(marmap)
temp <- as.bathy(r0)
summary(temp)

# Changing the relevant longitude
names <- as.numeric(row.names(temp))
names[names > 180] <- names[names > 180] - 360

# Renaming the longitudes and switching back from a 'bathy' object to a raster
rownames(temp) <- names
r0.modified <- as.raster(temp)
Benoit
  • 1,154
  • 8
  • 11