netcdf4-wasm
v0.1.1
Published
NetCDF4 library compiled to WebAssembly with TypeScript bindings
Maintainers
Readme
netcdf4-wasm
NetCDF4 library compiled to WebAssembly with JavaScript/TypeScript bindings.
Overview
This project provides a complete WebAssembly port of the NetCDF4 C library, enabling NetCDF file operations in browser and Node.js environments. It includes:
- Complete NetCDF4 C library compiled to WASM using Emscripten
- High-level TypeScript/JavaScript API
- Support for reading and writing NetCDF4 files
- Comprehensive test suite
Installation
NPM/Yarn (Node.js and bundlers)
npm install netcdf4-wasmCDN (Browser)
<!-- UMD build (recommended for browser) -->
<script src="https://unpkg.com/netcdf4-wasm@latest/dist/netcdf4-wasm.umd.min.js"></script>
<!-- ES Module build -->
<script type="module">
import { Dataset } from "https://unpkg.com/netcdf4-wasm@latest/dist/netcdf4-wasm.esm.js";
</script>Prerequisites
For building from source, you'll need:
- Emscripten SDK
- CMake
- Make
- wget or curl
Check dependencies:
npm run check-depsInstall Emscripten locally:
npm run install-emscriptenUsage
The JavaScript API is modeled closely on the netcdf4-python API.
Basic Example
ES Modules (Node.js, bundlers)
import { Dataset } from "netcdf4-wasm";
// or: import { NetCDF4 } from 'netcdf4-wasm';
async function example() {
// Create a new NetCDF file (similar to Python netCDF4.Dataset)
const nc = await Dataset("example.nc", "w", { format: "NETCDF4" });
// or: const nc = await NetCDF4.Dataset('example.nc', 'w', { format: 'NETCDF4' });
// Create dimensions
const lat = await nc.createDimension("lat", 73);
const lon = await nc.createDimension("lon", 144);
const time = await nc.createDimension("time", null); // unlimited dimension
// Create variables
const temp = await nc.createVariable("temperature", "f4", [
"time",
"lat",
"lon",
]);
const times = await nc.createVariable("time", "f8", ["time"]);
// Set variable attributes
temp.units = "Kelvin";
temp.long_name = "surface temperature";
times.units = "hours since 0001-01-01 00:00:00.0";
times.calendar = "gregorian";
// Set global attributes
nc.setAttr("description", "bogus example script");
nc.setAttr("history", "Created " + new Date().toISOString());
nc.setAttr("source", "netCDF4-wasm example");
// Write data
const tempData = new Float64Array(73 * 144);
tempData.fill(288.0); // Fill with 288K
await temp.setValue(tempData);
// Close the file
await nc.close();
}Browser UMD (Global variable)
<script src="https://unpkg.com/netcdf4-wasm@latest/dist/netcdf4-wasm.umd.min.js"></script>
<script>
async function example() {
// Access via global NetCDF4WASM object
const { Dataset } = NetCDF4WASM;
// Create a new NetCDF file
const nc = await Dataset(new ArrayBuffer(0), "w", { format: "NETCDF4" });
// Create dimensions
const lat = await nc.createDimension("lat", 73);
const lon = await nc.createDimension("lon", 144);
const time = await nc.createDimension("time", null); // unlimited dimension
// Create variables
const temp = await nc.createVariable("temperature", "f4", [
"time",
"lat",
"lon",
]);
// Set variable attributes
temp.units = "Kelvin";
temp.long_name = "surface temperature";
// Set global attributes
nc.setAttr("description", "Created with UMD build");
// Write data
const tempData = new Float64Array(73 * 144);
tempData.fill(288.0); // Fill with 288K
await temp.setValue(tempData);
// Export as blob for download
const blob = await nc.toBlob();
await nc.close();
// Create download link
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'example.nc';
a.click();
}
</script>Reading Files
import { Dataset } from "netcdf4-wasm";
async function readExample() {
// Open existing file for reading
const nc = await Dataset("data.nc", "r");
// Access dimensions
console.log("Dimensions:", Object.keys(nc.dimensions));
console.log("Time dimension size:", nc.dimensions.time.size);
// Access variables
console.log("Variables:", Object.keys(nc.variables));
const temp = nc.variables.temperature;
// Read variable attributes
console.log("Temperature units:", temp.units);
console.log("Temperature long name:", temp.long_name);
// Read data
const data = await temp.getValue();
console.log("Temperature data shape:", data.length);
console.log("First few values:", data.slice(0, 5));
// Access global attributes
console.log("Global attributes:", nc.attrs());
console.log("Description:", nc.getAttr("description"));
await nc.close();
}Alternative Constructor (Direct Instantiation)
import { NetCDF4 } from "netcdf4-wasm";
async function directExample() {
// Direct instantiation (requires manual initialization)
const nc = new NetCDF4("example.nc", "w", { format: "NETCDF4" });
await nc.initialize();
// Use same API as above...
const lat = await nc.createDimension("lat", 10);
const temp = await nc.createVariable("temperature", "f8", ["lat"]);
await nc.close();
}Working with Groups
async function groupExample() {
const nc = await Dataset("grouped.nc", "w", { format: "NETCDF4" });
// Create a group
const forecasts = nc.createGroup("forecasts");
// Create dimensions and variables in the group
const time = await forecasts.createDimension("time", 24);
const temp = await forecasts.createVariable("temperature", "f4", ["time"]);
// Set group attributes
forecasts.setAttr("description", "Forecast data");
await nc.close();
}API Reference
The API closely follows netcdf4-python conventions for ease of use by scientists familiar with Python.
Classes
NetCDF4
Main class for NetCDF file operations, similar to netCDF4.Dataset in Python.
Constructor
new NetCDF4(filename?: string, mode?: string, options?: NetCDF4WasmOptions)Static Methods
NetCDF4.Dataset(filename: string, mode?: string, options?: object): Promise<NetCDF4>- Factory method (Python-like)
Module Functions
Dataset(filename: string, mode?: string, options?: object): Promise<NetCDF4>- Convenience function (import directly)
Properties
dimensions: {[name: string]: Dimension}- Dictionary of dimensionsvariables: {[name: string]: Variable}- Dictionary of variablesgroups: {[name: string]: Group}- Dictionary of groupsfile_format: string- File format (e.g., 'NETCDF4')filepath: string- Path to the fileisopen: boolean- Whether file is currently open
Methods
File Operations
initialize(): Promise<void>- Initialize the WASM moduleclose(): Promise<void>- Close the filesync(): Promise<void>- Flush data to disk
Structure Definition
createDimension(name: string, size: number): Promise<Dimension>- Create dimensioncreateVariable(name: string, datatype: string, dimensions: string[], options?: object): Promise<Variable>- Create variablecreateGroup(name: string): Group- Create hierarchical group
Attribute Access
setAttr(name: string, value: any): void- Set global attributegetAttr(name: string): any- Get global attributeattrs(): string[]- List all global attributes
Variable
Represents a NetCDF variable, similar to Python's Variable class.
Properties
name: string- Variable namedatatype: string- Data type ('f4', 'f8', 'i4', etc.)dimensions: string[]- Dimension namesunits: string- Units attribute (convenience property)long_name: string- Long name attribute (convenience property)standard_name: string- Standard name attribute (convenience property)
Methods
getValue(): Promise<Float64Array>- Read variable datasetValue(data: Float64Array): Promise<void>- Write variable datasetAttr(name: string, value: any): void- Set variable attributegetAttr(name: string): any- Get variable attributeattrs(): string[]- List variable attributes
Dimension
Represents a NetCDF dimension.
Properties
name: string- Dimension namesize: number- Dimension sizeisUnlimited: boolean- Whether dimension is unlimited
Methods
__len__(): number- Get dimension size (Python-like)
Constants
The NC_CONSTANTS object provides NetCDF constants:
NC_CONSTANTS.NC_NOERR; // No error
NC_CONSTANTS.NC_NOWRITE; // Read-only access
NC_CONSTANTS.NC_WRITE; // Write access
NC_CONSTANTS.NC_CLOBBER; // Overwrite existing file
NC_CONSTANTS.NC_NETCDF4; // NetCDF4 format
NC_CONSTANTS.NC_DOUBLE; // Double data type
NC_CONSTANTS.NC_UNLIMITED; // Unlimited dimensionBuilding
Install dependencies
npm installCheck build dependencies
npm run check-depsBuild the project
npm run buildThis will:
- Download and compile zlib, HDF5, and NetCDF4 C libraries
- Create the WASM module with Emscripten
- Compile TypeScript bindings
- Build multiple output formats:
- UMD build for browsers (
dist/netcdf4-wasm.umd.js) - UMD minified for production (
dist/netcdf4-wasm.umd.min.js) - ES modules for bundlers (
dist/netcdf4-wasm.esm.js) - CommonJS for Node.js (
dist/index.js)
- UMD build for browsers (
Clean build artifacts
npm run cleanTesting
Run tests:
npm testRun tests with coverage:
npm run test:coverageWatch mode:
npm run test:watchDevelopment
Project Structure
netcdf4-wasm/
├── src/ # TypeScript source code
│ ├── index.ts # Main API exports
│ ├── types.ts # Type definitions
│ ├── constants.ts # NetCDF constants
│ ├── netcdf4.ts # Main NetCDF4 class
│ ├── group.ts # Group class
│ ├── variable.ts # Variable class
│ ├── dimension.ts # Dimension class
│ ├── wasm-module.ts # WASM module loader
│ └── __tests__/ # Test files
├── scripts/ # Build scripts
│ ├── build-wasm.sh # Main WASM build script
│ ├── check-dependencies.sh
│ └── install-emscripten.sh
├── bindings/ # WASM bindings
│ ├── pre.js # Pre-run JavaScript
│ └── post.js # Post-run JavaScript
├── build/ # Build artifacts (generated)
├── dist/ # Distribution files (generated)
│ ├── index.js # CommonJS build
│ ├── netcdf4-wasm.umd.js # UMD build for browsers
│ ├── netcdf4-wasm.umd.min.js # UMD minified build
│ └── netcdf4-wasm.esm.js # ES modules build
├── rollup.config.js # Rollup bundler configuration
├── tsconfig.rollup.json # TypeScript config for Rollup
└── package.jsonContributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run the test suite
- Submit a pull request
License
MIT License - see LICENSE file for details.
NetCDF4 Documentation
For more information about NetCDF4, visit: https://docs.unidata.ucar.edu/netcdf-c/current/
Troubleshooting
WASM Module Not Found
Make sure the WASM files are properly built and accessible:
npm run build:wasmEmscripten Not Found
Install Emscripten:
npm run install-emscripten
source build/emsdk/emsdk_env.shMemory Issues
If you encounter memory-related errors, try increasing the initial memory:
const netcdf = new NetCDF4({ memoryInitialPages: 512 });