Basic R tools to deal with ROMS and make maps.

First, load up some packages and find out the variables in the file, extract one out, get the X-Y coordinates for this data and find the boundary in the real world for the model.

roms_path <- file.path(getOption("default.datadir"), "data_local/acecrc.org.au/ROMS/mertz_sample/mer_his_1992_01.nc")
library(angstroms)    ## devtools::install_github("mdsumner/angstroms")
library(ncdump)       ## devtools::install_github("r-gris/ncdump")
library(tabularaster) ## devtools::install_github("r-gris/tabularaster")
library(rworldmap)
ncd <- NetCDF(roms_path)
ncd$variable$name
 [1] "Cs_w"    "h"       "lat_rho" "lat_u"   "lat_v"   "lon_rho" "lon_u"   "lon_v"   "u"       "v"       "w"      

Let’s choose u, and read the first available XY-slice, also read the grid’s coordinates and derive the boundary.

vname <- "u"
dd <- romsdata(roms_path, varname = vname, slice = c(1, 1), transpose = TRUE)
plot(dd)  ## this is pure 0-dimX, 0-dimY index space
longlat <- romscoords(roms_path, transpose = TRUE)
contour(longlat[[1]], add = TRUE, lty = 2)
contour(longlat[[2]], add = TRUE, lty = 2)

bound <- boundary(longlat)
projection(bound) <- "+init=epsg:4326"
extent(bound)
class       : Extent 
xmin        : 135.7893 
xmax        : 158.0496 
ymin        : -69.41263 
ymax        : -62.72635 

Now, plot this region in the “real world”, but first choose a local map projection.

pbound <- spTransform(bound, "+proj=lcc +lat_0=-65 +lat_1=-72 +lat_2=-60 +lon_0=147 +ellps=WGS84 +no_defs")
plot(pbound)
data(countriesLow)
w <- spTransform(countriesLow, projection(pbound))
plot(w, add = TRUE)
library(rgdal)
op <- par(xpd = NA)
llgridlines(pbound)
par(op)

# lon_grat <- rasterToContour(longlat[[1]]); projection(lon_grat) <- "+init=epsg:4326"
# lat_grat <- rasterToContour(longlat[[2]]); projection(lat_grat) <- "+init=epsg:4326"
# plot(spTransform(lon_grat, projection(pbound)), add = TRUE, lty = 2)
# plot(spTransform(lat_grat, projection(pbound)), add = TRUE, lty = 2)
library(leaflet)
set_crs <- function(x, value) {
  projection(x) <- value
  x
}
epsg3857 <- "+init=epsg:3857 +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null
+no_defs"
dd1 <- dd
set_ext <- function(x) setExtent(x, extent(c(xmin(x), xmax(x), ymin(x), ymax(x)) * 10))
get_slice <- function(i = 1) {
  r <- romsdata(roms_path, varname = vname, slice = c(i, 1), transpose = TRUE)
  set_ext(set_crs(dd, epsg3857))
}
leaflet() %>% addRasterImage(get_slice())
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Inf
## what dims does our var have?
dm <- ncd$variable %>% filter(name == "u") %>% select(id) %>% inner_join(ncd$vardim) %>% inner_join(ncd$dimension, c("dimids" = "id"))
Joining, by = "id"
dm
## choose s_rho 
zd <- "s_rho"
zn <- (dm %>% filter(name == zd))$len
library(crosstalk)
library(leaflet)
library(DT)
# Wrap data frame in SharedData
sd <- SharedData$new(data.frame(depth = seq_len(zn)))
# Create a filter input
filter_select("depth", "Depth", sd,  "depth", multiple = FALSE)

# Use SharedData like a dataframe with Crosstalk-enabled widgets
bscols(
  leaflet() %>% addRasterImage(get_slice(sd$selection()$depth)),
  datatable(sd, extensions="Scroller", style="bootstrap", class="compact", width="100%",
            options=list(deferRender=TRUE, scrollY=300, scroller=TRUE))
)
Error in .getReactiveEnvironment()$currentContext() : 
  Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
LS0tCnRpdGxlOiAiUk9NUyBtYXBwaW5nIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpCYXNpYyBSIHRvb2xzIHRvIGRlYWwgd2l0aCBST01TIGFuZCBtYWtlIG1hcHMuIAoKRmlyc3QsIGxvYWQgdXAgc29tZSBwYWNrYWdlcyBhbmQgZmluZCBvdXQgdGhlIHZhcmlhYmxlcyBpbiB0aGUgZmlsZSwgZXh0cmFjdCBvbmUgb3V0LCBnZXQgdGhlIFgtWSBjb29yZGluYXRlcyBmb3IgdGhpcyBkYXRhIGFuZCBmaW5kIHRoZSBib3VuZGFyeSBpbiB0aGUgcmVhbCB3b3JsZCBmb3IgdGhlIG1vZGVsLiAKCgpgYGB7cn0Kcm9tc19wYXRoIDwtIGZpbGUucGF0aChnZXRPcHRpb24oImRlZmF1bHQuZGF0YWRpciIpLCAiZGF0YV9sb2NhbC9hY2VjcmMub3JnLmF1L1JPTVMvbWVydHpfc2FtcGxlL21lcl9oaXNfMTk5Ml8wMS5uYyIpCmxpYnJhcnkoYW5nc3Ryb21zKSAgICAjIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIm1kc3VtbmVyL2FuZ3N0cm9tcyIpCmxpYnJhcnkobmNkdW1wKSAgICAgICAjIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInItZ3Jpcy9uY2R1bXAiKQpsaWJyYXJ5KHRhYnVsYXJhc3RlcikgIyMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyLWdyaXMvdGFidWxhcmFzdGVyIikKbGlicmFyeShyd29ybGRtYXApCm5jZCA8LSBOZXRDREYocm9tc19wYXRoKQoKbmNkJHZhcmlhYmxlJG5hbWUKCmBgYAoKTGV0J3MgY2hvb3NlIGB1YCwgYW5kIHJlYWQgdGhlIGZpcnN0IGF2YWlsYWJsZSBYWS1zbGljZSwgYWxzbyByZWFkIHRoZSBncmlkJ3MgY29vcmRpbmF0ZXMgYW5kIGRlcml2ZSB0aGUgYm91bmRhcnkuIAoKYGBge3J9Cgp2bmFtZSA8LSAidSIKZGQgPC0gcm9tc2RhdGEocm9tc19wYXRoLCB2YXJuYW1lID0gdm5hbWUsIHNsaWNlID0gYygxLCAxKSwgdHJhbnNwb3NlID0gVFJVRSkKcGxvdChkZCkgICMjIHRoaXMgaXMgcHVyZSAwLWRpbVgsIDAtZGltWSBpbmRleCBzcGFjZQpsb25nbGF0IDwtIHJvbXNjb29yZHMocm9tc19wYXRoLCB0cmFuc3Bvc2UgPSBUUlVFKQpjb250b3VyKGxvbmdsYXRbWzFdXSwgYWRkID0gVFJVRSwgbHR5ID0gMikKY29udG91cihsb25nbGF0W1syXV0sIGFkZCA9IFRSVUUsIGx0eSA9IDIpCmJvdW5kIDwtIGJvdW5kYXJ5KGxvbmdsYXQpCnByb2plY3Rpb24oYm91bmQpIDwtICIraW5pdD1lcHNnOjQzMjYiCmV4dGVudChib3VuZCkKYGBgCgoKTm93LCBwbG90IHRoaXMgcmVnaW9uIGluIHRoZSAicmVhbCB3b3JsZCIsIGJ1dCBmaXJzdCBjaG9vc2UgYSBsb2NhbCBtYXAgcHJvamVjdGlvbi4gCgpgYGB7cn0KcGJvdW5kIDwtIHNwVHJhbnNmb3JtKGJvdW5kLCAiK3Byb2o9bGNjICtsYXRfMD0tNjUgK2xhdF8xPS03MiArbGF0XzI9LTYwICtsb25fMD0xNDcgK2VsbHBzPVdHUzg0ICtub19kZWZzIikKcGxvdChwYm91bmQpCmRhdGEoY291bnRyaWVzTG93KQp3IDwtIHNwVHJhbnNmb3JtKGNvdW50cmllc0xvdywgcHJvamVjdGlvbihwYm91bmQpKQpwbG90KHcsIGFkZCA9IFRSVUUpCmxpYnJhcnkocmdkYWwpCm9wIDwtIHBhcih4cGQgPSBOQSkKbGxncmlkbGluZXMocGJvdW5kKQpwYXIob3ApCiMgbG9uX2dyYXQgPC0gcmFzdGVyVG9Db250b3VyKGxvbmdsYXRbWzFdXSk7IHByb2plY3Rpb24obG9uX2dyYXQpIDwtICIraW5pdD1lcHNnOjQzMjYiCiMgbGF0X2dyYXQgPC0gcmFzdGVyVG9Db250b3VyKGxvbmdsYXRbWzJdXSk7IHByb2plY3Rpb24obGF0X2dyYXQpIDwtICIraW5pdD1lcHNnOjQzMjYiCiMgcGxvdChzcFRyYW5zZm9ybShsb25fZ3JhdCwgcHJvamVjdGlvbihwYm91bmQpKSwgYWRkID0gVFJVRSwgbHR5ID0gMikKIyBwbG90KHNwVHJhbnNmb3JtKGxhdF9ncmF0LCBwcm9qZWN0aW9uKHBib3VuZCkpLCBhZGQgPSBUUlVFLCBsdHkgPSAyKQpgYGAKCgpgYGB7cn0KbGlicmFyeShsZWFmbGV0KQpzZXRfY3JzIDwtIGZ1bmN0aW9uKHgsIHZhbHVlKSB7CiAgcHJvamVjdGlvbih4KSA8LSB2YWx1ZQogIHgKfQplcHNnMzg1NyA8LSAiK2luaXQ9ZXBzZzozODU3ICtwcm9qPW1lcmMgK2E9NjM3ODEzNyArYj02Mzc4MTM3ICtsYXRfdHM9MC4wICtsb25fMD0wLjAgK3hfMD0wLjAgK3lfMD0wICtrPTEuMCArdW5pdHM9bSArbmFkZ3JpZHM9QG51bGwKK25vX2RlZnMiCmRkMSA8LSBkZApzZXRfZXh0IDwtIGZ1bmN0aW9uKHgpIHNldEV4dGVudCh4LCBleHRlbnQoYyh4bWluKHgpLCB4bWF4KHgpLCB5bWluKHgpLCB5bWF4KHgpKSAqIDEwKSkKCmdldF9zbGljZSA8LSBmdW5jdGlvbihpID0gMSkgewogIHIgPC0gcm9tc2RhdGEocm9tc19wYXRoLCB2YXJuYW1lID0gdm5hbWUsIHNsaWNlID0gYyhpLCAxKSwgdHJhbnNwb3NlID0gVFJVRSkKICBzZXRfZXh0KHNldF9jcnMoZGQsIGVwc2czODU3KSkKfQpsZWFmbGV0KCkgJT4lIGFkZFJhc3RlckltYWdlKGdldF9zbGljZSgpKQoKYGBgCgoKYGBge3J9CiMjIHdoYXQgZGltcyBkb2VzIG91ciB2YXIgaGF2ZT8KZG0gPC0gbmNkJHZhcmlhYmxlICU+JSBmaWx0ZXIobmFtZSA9PSAidSIpICU+JSBzZWxlY3QoaWQpICU+JSBpbm5lcl9qb2luKG5jZCR2YXJkaW0pICU+JSBpbm5lcl9qb2luKG5jZCRkaW1lbnNpb24sIGMoImRpbWlkcyIgPSAiaWQiKSkKZG0KCiMjIGNob29zZSBzX3JobyAKemQgPC0gInNfcmhvIgp6biA8LSAoZG0gJT4lIGZpbHRlcihuYW1lID09IHpkKSkkbGVuCgoKYGBgCg==