Creating, modifying, and reading netCDF data is easy in Python.
There are several netCDF Python modules available.
We will use Jeff Whitaker's netcdf4 package.
import netCDF4 # Note: upper and lower case matter!
import numpy as np
Now let's create a new, empty netCDF file named 'data/new.nc', opened for writing ...
ncfile = netCDF4.Dataset('data/new.nc','w')
print "-- Created file"
-- Created file
The ncfile object we created is a container for dimensions, variables, and attributes. Let's add some of those. Every dimension has a name and a length.
lat_dim = ncfile.createDimension('lat', 5) # latitude axis
lon_dim = ncfile.createDimension('lon', 7) # longitude axis
time_dim = ncfile.createDimension('time', 0) # unlimited axis
print "-- Created dimensions"
-- Created dimensions
Setting the dimension length to 0 or None makes it unlimited, so it can grow.
Now let's add some variables and store some data in them.
A variable has a name, a type, a shape, and some data values. The shape of a variable is specified by a tuple of dimension names. A variable may also have some named attributes, such as 'units'.
The type of a variable may be specified by a string, such as 'f4' for 4-byte float. Alternatively, it may be specified as a numpy type, such as float32.
# Define two variables with the same names as dimensions,
# a conventional way to define "coordinate variables".
lat = ncfile.createVariable('lat', 'f4', ('lat',))
lat.units = 'degrees_north'
lat.standard_name = 'latitude'
lon = ncfile.createVariable('lon', 'f4', ('lon',))
lon.units = 'degrees_east'
lon.standard_name = 'longitude'
# Define a 3D variable to hold the data
mslp = ncfile.createVariable('mslp','f4',('time','lat','lon'))
mslp.units = 'hPa' # hecto-Pascals also known as millibars
mslp.standard_name = 'air_pressure_at_sea_level'
print "-- Created variables with attributes"
-- Created variables with attributes
The netCDF4 module provides some useful pre-defined Python attributes for netCDF variables, such as dimensions, shape, dtype, ndim.
print "-- Some pre-defined attributes for variable mslp:"
print "mslp.dimensions:", mslp.dimensions
print "mslp.shape:", mslp.shape
print "mslp.type:", mslp.dtype
print "mslp.ndim:", mslp.ndim
-- Some pre-defined attributes for variable mslp: mslp.dimensions: (u'time', u'lat', u'lon') mslp.shape: (0, 5, 7) mslp.type: float32 mslp.ndim: 3
If you don't need variable properties separately, you can print all the info at once:
print mslp
<type 'netCDF4.Variable'> float32 mslp(time, lat, lon) units: hPa standard_name: air_pressure_at_sea_level unlimited dimensions: time current shape = (0, 5, 7)
So far, we don't have any actual data in the file. Let's:
mslp
to that array to store data for 3 timesntimes = 3
nlats = len(lat_dim)
nlons = len(lon_dim)
# Write latitudes, longitudes.
# Note: the ":" is necessary in these "write" statements
lat0, lon0, step = (20.0, 75.0, 10.0)
lat[:] = np.arange(lat0, lat0+nlats*step, step) # 20, 30, ..., 60
lon[:] = np.arange(lon0, lon0+nlons*step, step) # 75, ..., 135
# create a 3D array of integers, ntimes by nlats by nlons
data_arr = (np.arange(ntimes*nlats*nlons)+850).reshape(ntimes,nlats,nlons)
# Write the data. This writes the whole 3D netCDF variable all at once.
mslp[:,:,:] = data_arr # Appends data along unlimited dimension
print "-- Wrote data, mslp.shape is now ", mslp.shape
-- Wrote data, mslp.shape is now (3, 5, 7)
Let's add another time slice:
# create a random 2D array of floats, nlats by nlons in [850., 1100)
from numpy.random import uniform
data_slice = uniform(low=870,high=1085,size=(nlats, nlons))
mslp[3,:,:] = data_slice # Appends the 4th time slice
print "-- Wrote more data, mslp.shape is now ", mslp.shape
-- Wrote more data, mslp.shape is now (4, 5, 7)
It's important to close a netCDF file you opened for writing:
ncfile.close()
print "-- File closed successfully"
-- File closed successfully
The ncdump
tool provides a text representation of the contents of a netCDF dataset, in the CDL notation. You can run command-line programs, such as ncdump
, in iPython by using '!' first:
!ncdump data/new.nc
netcdf new { dimensions: lat = 5 ; lon = 7 ; time = UNLIMITED ; // (4 currently) variables: float lat(lat) ; lat:units = "degrees_north" ; lat:standard_name = "latitude" ; float lon(lon) ; lon:units = "degrees_east" ; lon:standard_name = "longitude" ; float mslp(time, lat, lon) ; mslp:units = "hPa" ; mslp:standard_name = "air_pressure_at_sea_level" ; data: lat = 20, 30, 40, 50, 60 ; lon = 75, 85, 95, 105, 115, 125, 135 ; mslp = 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 1047.216, 979.6005, 991.3537, 956.3278, 986.5375, 960.1299, 922.8538, 926.1583, 1076.592, 910.5492, 938.5563, 1079.488, 984.0167, 909.8796, 896.697, 1049.94, 934.3764, 945.8491, 879.4117, 1081.525, 954.6262, 911.2933, 920.6139, 958.7702, 971.0795, 1063.604, 910.8762, 917.3784, 1043.719, 926.6383, 982.0197, 875.2462, 1080.647, 1037.896, 1055.849 ; }