Search code examples
rdataframenetcdf4

Coercing ncdf4 to dataframe


I'm trying to wrestle some netcdf files containing daily climate data into .csv files. This is usually a routine task but I got this set of files that seems problematic. The error occurred (see below) where I needed to convert the matrices to dataframe and I couldn't figure out what the issue is. The error doesn't occur when I'm not looping through the files. Any tips would be appreciated.

Here's my code. Sample data can be found here sample data.

library(stringr)
library(ncdf4)

fin <- list.files("D:/path/prec", pattern = ".nc$", full.names=TRUE)
fin2 <- gsub("D:/path/prec/", "", fin)
var_name =  str_replace(fin2, ".nc", "")   ## generates data file names

for(i in seq_along(fin)){
 
 prec <- nc_open(fin[i])
 
 var = ncvar_get(prec, var_name[i], collapse_degen = F)
 dim_lon <- ncvar_get(prec, "longitude")
 dim_lat <- ncvar_get(prec, "latitude")
 dim_time <- ncvar_get(prec, "time")
 
 
 coords = as.matrix(expand.grid(dim_lon, dim_lat, dim_time))
 r = data.frame(cbind(coords, var))  **this is where the problem is!**
 
 
 names(r) = c("Lon", "Lat", "Day", "Prec")
 
 i = var_name[i] ##assign name to match input name 

 write.csv(prec, file.path("D:/path/prec", paste0(i, ".csv")), row.names = FALSE)

}

Error in as.data.frame.default(x[[i]], optional = TRUE, stringsAsFactors = stringsAsFactors) : cannot coerce class ‘"ncdf4"’ to a data.frame.

Expected outcome:

 Lon     Lat     Day    Prec
-133.25 60.25   127 10.74618626
-133    60.25   127 11.28547573
-132.75 60.25   127 11.23372364
-132.5  60.25   127 11.06846809
-132.25 60.25   127 10.87025547
-132    60.25   127 9.392285347

Solution

  • Found a different approach using tidync, which solved the problem. The new approach is more efficient than my original code.

    library(stringr)
    library(tidync)
    
    fin <- list.files("D:/path/prec", pattern = ".nc$", full.names=TRUE)
    fin2 <- gsub("D:/path/prec/", "", fin)
    
    var_name =  str_replace(fin2, ".nc", "")     ## generates data file names
    
    
    for(i in seq_along(fin)) {
     
      prec <- tidync(fin[i])
      prec = prec %>%
        hyper_tibble()
      
      names(prec) = c("Prec", "Lon", "Lat", "Time")
      
      i = var_name[i]             ##assign name to match input name 
      
     write.csv(prec, file.path("D:/path/prec", paste0(i, ".csv")), row.names = FALSE)
    
    }
    
    

    Here's the output

    #    Prec        Lon    Lat       Time
    # 0.0000122     -141    69.6    284038200
    # 0.00000904    -141    69.6    284038200
    # 0.00000805    -141    69.6    284038200
    # 0.00000732    -141    69.6    284038200
    # 0.00000244    -140    69.6    284038200
    # 0.00000316    -140    69.6    284038200
    
    

    Note that the time is supposed to be in days but this is how it's presented in the source file and has nothing to do with the extraction method. Any tips for conversion would be appreciate.