I am trying to write a Numpy array to a netcdf file which will ultimately be read into ArcGIS 10.2 as a raster file with time dimension. When ArcGIS reads in my current file it is not setting the man, min, and missing values properly so I am assuming I need to set theses when I create my NetCDF file. However, I am having trouble figureing out how to set these variable attributes when creating the file. Here is my current code.
import numpy as n
from scipy.io import netcdf
def gis_netcdf(data,arr,filename):
f=netcdf.netcdf_file(outfile+filename,'w')
f.history='Downscaled CMIP5 data which has been averaged over all'\
'models and decadaly averaged'
f.createDimension('time',9)
f.createDimension('lat',len(data['lat']))
f.createDimension('lon',len(data['lon']))
time=f.createVariable('time',int,('time',))
lat=f.createVariable('lat',float,('lat',))
lon=f.createVariable('lon',float,('lon',))
fog=f.createVariable('fog',float,('time','lat','lon',))
#attributes I need set:
# 'missing_value':1e20
# 'valid_min':n.min(arr[arr<500])
# 'valid_max':n.max(arr[arr<500])
time[:]=n.arange(2010,2091,10)
time.units='decades since 1950'
lat[:]=data['lat']
lat.units='Degrees North'
lon[:]=data['lon']
lon.units='Degrees East'
fog[:]=arr
fog.units='Change in Hours'
f.close
*****Attempt at Solution which was posted**********
I added the following lines to my above code:
fog.missing_value=1e20
fog.valid_min=n.min(arr[arr<500])
fog.valid_max=n.max(arr[arr<500])
and it did not work. This is my ncdump output
netcdf pixel_model_fog85 {
dimensions:
time = 9 ;
lat = 20 ;
lon = 18 ;
variables:
double lat(lat) ;
lat:units = "Degrees North" ;
double lon(lon) ;
lon:units = "Degrees East" ;
double fog(time, lat, lon) ;
fog:units = "Change in Hours" ;
long time(time) ;
time:units = "decades since 1950" ;
// global attributes:
:history = "Downscaled CMIP5 data which has been averaged over all models and decadaly averaged" ;
data:
lat = 36.3125, 36.4375, 36.5625, 36.6875, 36.8125, 36.9375, 37.0625,
37.1875, 37.3125, 37.4375, 37.5625, 37.6875, 37.8125, 37.9375, 38.0625,
38.1875, 38.3125, 38.4375, 38.5625, 38.6875 ;
You just define them in a similar fashion as you've already done for the units
attribute.
fog.missing_value = 1e20
fog.valid_min = [whatever value this should be]
-- EDIT --
Here is a full sample script that is working fine on my end. Note that I define all attributes in a single section before populating any data to the variables. I also use the data type shortcuts, like 'i' and 'f4', during the variable defining. While this works, I do recommend switching from the Scipy netCDF package to python-netCDF4.
import numpy as np
from scipy.io.netcdf import netcdf_file
# Define some dummy data
time_arr = range(10)
lat_arr = np.array([30.5, 40., 40.5])
lon_arr = np.array([200., 203., 206.])
ntim, nlat, nlon = len(time_arr), len(lat_arr), len(lon_arr)
fog_arr = np.random.randn(ntim,nlat,nlon)
# Write out data to a new netCDF file with some attributes
filename = netcdf_file('./tmp_netcdf.nc', 'w')
# Dimensions
filename.createDimension('time', ntim)
filename.createDimension('lat', nlat)
filename.createDimension('lon', nlon)
# Variables
time = filename.createVariable('time', 'i', ('time',))
lat = filename.createVariable('lat', 'f4', ('lat',))
lon = filename.createVariable('lon', 'f4', ('lon',))
fog = filename.createVariable('fog', 'f4', ('time', 'lat', 'lon',))
# Attributes
time.units = 'decades since 1950'
lat.units = 'degrees north'
lon.units = 'degrees east'
fog.units = 'change in hours'
fog.missing_val = 1e20
fog.valid_min = np.min(fog_arr)
# Populate the variables with data
time[:] = time_arr
lat[:] = lat_arr
lon[:] = lon_arr
fog[:,:,:] = fog_arr[:,:,:]
filename.close()
Checking with ncdump:
>>> ncdump -h tmp_netcdf.nc
netcdf tmp_netcdf {
dimensions:
time = 10 ;
lat = 3 ;
lon = 3 ;
variables:
float fog(time, lat, lon) ;
fog:units = "change in hours" ;
fog:valid_min = -2.33124982071635 ;
fog:missing_val = 1.e+20f ;
int time(time) ;
time:units = "decades since 1950" ;
float lat(lat) ;
lat:units = "degrees north" ;
float lon(lon) ;
lon:units = "degrees east" ;
}