I am trying to plot a netCDF (.nc) file in R using ggplot to create a map. The data I'm using can be found (ESGF MetaGrid with variable "pr", frequency "mon" and source ID "EC-Earth3" File --> pr_Amon_EC-Earth3_historical_r1i1p1f1_gr_199801-199812)
I want to find out how to zoom in and add a title? Please help! I am so close!
Can I manipulate this to put it in ggplot to give me more tools?
Essentially, the goal is: to take a slice of the data (such as time = 1 is January) and have a U.S. and a global map of the differences in precipitation for that dataset.
I don't know if it will help but you should be able to read netcdf file using sf package. This will ease data manipulation. ggplot2 offers a geom_sf function that could help too.
Otherwise, every spatial graph package would work I guess.
Check out the stars package for manipulating spatiotemporal arrays. Within stars is the geom_stars function that allows for rasters to play nice with ggplot2.
Once you have a stars object in your environment, you can add layers to your ggplot in the same way you'd work with non-spatial data. Importantly, you'll need to make sure the layers have the same coordinate reference system.
In pseudocode (I can't find your data set):
library(sf)
library(ggplot2)
library(stars)
library(dplyr)
stars_object <- raster::raster("your_data_set.nc") %>% st_as_stars()
sf_object <- sf::st_read("second_data_set.shp")
#Make sure they have the same CRS
sf::st_crs(stars_object) <- sf::st_crs(sf_object)
#Crop to bounding box (insert coordinates in ...)
bb <- sf::st_bbox(xmin = ..., xmax = ..., ymin = ..., ymax = ...)
stars_object <- stars_object[bb]
#plot
ggplot()+
geom_stars(data = stars_object) +
geom_sf(data = sf_object)
Subsetting stars objects by layer is pretty straightforward if you follow the vignettes starting here.
Thanks! Any netcdf file will work from cmip6, they are all 4 dimensional.
I'm trying your code but I don't know how to put in the shapefile for the sf_object.
I'm not quite sure - I'm able to download and load the countries shapefile into my environment. Are you sure that you're specifying the correct (and full) file path?
Hmm, I was able to get the shapefile but when I map it, it looks like this. Do you know what's going on? Also, is there a way to just have the lines for the countries?
You can use the raster::rotate() function to convert your data from the 0-360 to -180-180 longitude scale prior to turning it into a stars object. You should then be able to plot the two data sets on the same scale via ggplot2.
My guess is that the mismatch in longitude scaling is what's preventing you from cropping the data set in your previous comment. Your precipitation raster starts at 0 ° longitude on the -180-180 scale
Check out the documentation by entering ?raster::rotate() to see examples of how to use the function. raster::rotate() just takes a raster as an argument, so in your case it'd probably look like this:
#load the raster
r <- raster::raster("your_file.nc")
#rotate the raster
r_rotated <- raster::rotate(r)
I'll try that. it's giving me an error "Error: must request at least one colour from a hue palette" and I can't find any solutions on google. I tried giving ggplot different colors but none of them are working. Any idea?
It looks like this post addresses the error you're reporting. What variables are being mapped to color or fill in the ggplot function? They may be empty or full of NAs.
I can't help you without being able to reproduce your error - try making a reprex if you can. I suggest including a link to a dataset on 0-360 longitude scale that leads to the same error.
Okay, I am having issues getting this to work. I looked at the other forum but it's just saying that my data is now messed up and full of NAs
I'm using EC-Earth GCM (under experiment id) for precipitation ("pr" under variable) variable for monthly (under frequency), year 2050 from the cmip6 website but any netcdf file would work (https://esgf-node.llnl.gov/search/cmip6/)
I got the shape file from the ArcGIS website.
> library(ncdf4)
> library(sf)
> library(ggplot2)
> library(stars)
> library(dplyr)
> library(maps)
> library(sp)
> library(maptools)
> library(raster)
>
>
> #attempt to rotate from 0-360 to -180 to 180 lon
> r <- raster::raster(file.choose())
#open pr_Amon_EC-Earth3_ssp370_r1i1p1f1_gr_205001-205012.nc
> r1 <- raster::rotate(r)
>
> print(r1)
class : RasterLayer
dimensions : 256, 512, 131072 (nrow, ncol, ncell)
resolution : 0.703125, 0.7016692 (x, y)
extent : -180, 180, -89.81366, 89.81366 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84
source : memory
names : Precipitation
values : -1.745207e-25, 0.000460271 (min, max)
z-value : 2050-01-16
>
> stars_object <- raster::raster(r1) %>% st_as_stars()
> sf_object <- sf::st_read(file.choose())
#open Countries_WGS84.shp
Reading layer `Countries_WGS84' from data source `/Users/8kk/Desktop/RStudio Projects/NetCDF Mapping/Countries_WGS84/Countries_WGS84.shp' using driver `ESRI Shapefile'
Simple feature collection with 251 features and 2 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -180 ymin: -90 xmax: 180 ymax: 83.6236
epsg (SRID): 4326
proj4string: +proj=longlat +datum=WGS84 +no_defs
>
> #Make sure they have the same CRS
> sf::st_crs(stars_object) <- sf::st_crs(sf_object)
>
> ggplot()+
+ geom_stars(data = stars_object) +
+ geom_sf(data = sf_object) # + aes(color = values)
**Error: Must request at least one colour from a hue palette.**
> str (stars_object)
List of 1
$ layer: logi [1:512, 1:256] NA NA NA NA NA NA ...
- attr(*, "dimensions")=List of 2
..$ x:List of 7
.. ..$ from : num 1
.. ..$ to : int 512
.. ..$ offset: num -180
.. ..$ delta : num 0.703
.. ..$ refsys: chr "+proj=longlat +datum=WGS84 +no_defs"
.. ..$ point : logi NA
.. ..$ values: NULL
.. ..- attr(*, "class")= chr "dimension"
..$ y:List of 7
.. ..$ from : num 1
.. ..$ to : int 256
.. ..$ offset: num 89.8
.. ..$ delta : num -0.702
.. ..$ refsys: chr "+proj=longlat +datum=WGS84 +no_defs"
.. ..$ point : logi NA
.. ..$ values: NULL
.. ..- attr(*, "class")= chr "dimension"
..- attr(*, "raster")=List of 3
.. ..$ affine : num [1:2] 0 0
.. ..$ dimensions : chr [1:2] "x" "y"
.. ..$ curvilinear: logi FALSE
.. ..- attr(*, "class")= chr "stars_raster"
..- attr(*, "class")= chr "dimensions"
- attr(*, "class")= chr "stars"