Classic NetCDF and CF grid reader

August 21, 2026 ยท View on GitHub

Quick Answer

Import geoNetCdfReader from purejsimage/geo/readers/netcdf to open CDF-1 or CDF-2 files that describe a regular rectilinear CF grid. The reader works with browser File sources, in-memory sources, local ImageSource adapters, and HttpRangeSource. It keeps time, vertical, band-like, ensemble, and custom dimensions selectable. It does not support CDF-5, HDF5-backed NetCDF4, curvilinear grids, or irregular coordinate lookup.

import { createScientificFileContext } from "purejsimage/scientific/browser";
import { geoNetCdfReader } from "purejsimage/geo/readers/netcdf";

const document = await geoNetCdfReader.open(createScientificFileContext(file));
const dataset = await document.openDataset(document.datasets[0].id);

Container scope

The parser reads classic NetCDF XDR metadata and selected variable regions. It supports:

  • CDF-1 classic containers;
  • CDF-2 containers with safe 64-bit offsets;
  • dimensions, variables, global attributes, and variable attributes;
  • fixed variables and interleaved record variables;
  • signed byte, signed 16-bit and 32-bit integer, 32-bit and 64-bit float data;
  • character attributes used by CF metadata;
  • four-byte header and data alignment;
  • cancellation and configurable limits for every admitted count, name, attribute, coordinate, read, and output allocation.

Metadata parsing uses exact field reads by default. Reading the header does not scan the variable payload. CF discovery reads only the bounded one-dimensional coordinate variables needed to decide whether a candidate grid is regular. An HttpRangeSource may fetch its configured cache blocks around those exact reads, but it does not fetch the complete object unless the object fits in those bounded blocks.

CDF-5 produces an explicit unsupported-version error. HDF5-backed NetCDF4 has a different container format and is outside this reader. Streaming files whose record count is still marked indeterminate are also unsupported.

CF subset

The reader recognizes coordinate variables and the coordinates, standard_name, long_name, units, axis, positive, and grid_mapping attributes. It preserves _FillValue, missing_value, valid_min, valid_max, valid_range, scale_factor, and add_offset evidence. NaN fill values are represented as the JSON-safe string "NaN" in the Geo descriptor.

Returned tiles contain the native stored sample values and sample type. Scale and offset remain on the band descriptor so an application can choose when to apply packed-value conversion. The reader does not silently convert or copy a complete source variable during dataset creation.

Time coordinates preserve their units, including bounded unit since timestamp strings. The recognized calendar names are standard, gregorian, proleptic_gregorian, julian, noleap, 365_day, all_leap, 366_day, and 360_day. Other calendar names remain in evidence and produce a typed warning. The reader does not turn time coordinates into JavaScript dates.

Grid rules

A published dataset needs distinct one-dimensional X and Y coordinate variables. Both coordinate arrays must be finite and regularly spaced. Decreasing X or Y coordinates are valid. The default regularity test accepts an absolute error of 1e-12 or a relative error of 1e-9 times the largest of one, the coordinate step, and the expected coordinate value. Applications can lower these tolerances with createGeoNetCdfReader().

CF coordinate values locate pixel centers, so normalized grids use pixel-is-point. The pixel-to-world affine is [xStep, 0, firstX, 0, yStep, firstY]. No north-up direction is assumed. Bounds are calculated by the shared Geo contract from transformed pixel coordinates.

Irregular one-dimensional coordinates are detected but not fitted to an affine. The document keeps their variable names and a netcdf-irregular-rectilinear-grid diagnostic. Two-dimensional latitude and longitude coordinates are detected as curvilinear and produce netcdf-curvilinear-grid. Neither case is exposed as an inaccurate affine dataset. A future Geo coordinate-lookup contract can add those grids without changing the classic container parser.

Grid mappings

The public cfGridMappings registry recognizes these metadata names:

  • latitude_longitude;
  • transverse_mercator;
  • lambert_conformal_conic;
  • polar_stereographic;
  • mercator;
  • albers_conical_equal_area;
  • rotated_latitude_longitude.

All bounded grid-mapping attributes remain in format evidence. WKT in crs_wkt or spatial_ref is preserved, and a directly stated authority can be identified from that WKT. An unknown mapping produces netcdf-unsupported-grid-mapping rather than an invented CRS.

This registry interprets metadata only. It does not execute a coordinate transformation. Cross-CRS work still uses the caller-supplied GeoCoordinateTransformer contract from purejsimage/geo.

Dataset and read behavior

Each suitable data variable becomes its own GeoRasterDataset. Variables are not combined because their shapes happen to match. Source dimension order is preserved. A view fixes every non-spatial dimension and chooses a bounded X/Y region. Record variables use the same selection model and read only their selected records and rows.

The document metadata lists all bounded container variables, attributes, candidate decisions, and typed diagnostics. Unsupported irregular or curvilinear candidates can therefore be inspected even when the document publishes no affine dataset.

Region reads are row-oriented and bounded by maxRegionBytes, maxRegionValues, and maxReadOperations. Cancellation is checked during metadata parsing, coordinate reads, record iteration, and selected-region reads. The source lifecycle remains owned by the caller-provided scientific context.