Expand description
N-dimensional dataset input and output through the ndarray crate.
The ndarray feature adds ergonomic, rank-generic dataset I/O on top of the ndarray crate, so multi-dimensional data round-trips without manually flattening it or tracking shapes. Shape and datatype are taken directly from the array you pass in.
A runnable example lives at examples/ndarray_io.rs. Run it with:
$ cargo run --example ndarray_io --features ndarray§Enabling the feature
This page’s API is gated behind the ndarray feature, which is off by default. Enable it in Cargo.toml:
[dependencies]
hdf5-pure = { version = "0.46", features = ["ndarray"] }The crate depends on ndarray with a deliberately permissive version requirement, >=0.16, <0.18, so your project’s existing ndarray unifies with the one this crate uses, and cargo builds a single copy. Cargo features has the full list of optional features.
§Writing arrays
DatasetBuilder::with_ndarray(&arr) sets a dataset’s data, shape, and datatype from a single array. The dataset’s rank and dimensions come from the array’s shape and its on-disk datatype from the element type, making it the N-dimensional counterpart of the flat with_*_data methods covered in Writing files.
use hdf5_pure::FileBuilder;
use ndarray::{array, Array2};
let a: Array2<f64> = array![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
let mut fb = FileBuilder::new();
fb.create_dataset("m").with_ndarray(&a); // shape [2, 3], f64
let bytes = fb.finish()?;The array can be of any rank, and both owned arrays and views are accepted by reference (e.g. &Array2<f64> or &arr.view()).
§Memory order and non-standard layouts
HDF5 stores dataset elements in row-major (C) order, which is also ndarray’s default layout, so in the common case a write is a flat copy with no transpose. Inputs that are not in standard layout (transposed, Fortran-order, or strided views) are repacked once into row-major order on write, and standard-layout inputs are used without copying. Either way, what you read back matches the logical array you passed in.
use hdf5_pure::{File, FileBuilder};
use ndarray::{array, Array2};
let m: Array2<f64> = array![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
let mut fb = FileBuilder::new();
fb.create_dataset("mt").with_ndarray(&m.t()); // transposed view
let file = File::from_bytes(fb.finish()?)?;
let transposed: Array2<f64> = file.dataset("mt")?.read_array()?;
assert_eq!(transposed, m.t());§Reading arrays
There are two read methods, distinguished by how the rank is determined.
| Method | Returns | Rank known at | Use when |
|---|---|---|---|
read_array::<T, D>() | Array<T, D> | compile time | the dimensionality is fixed (usually inferred from the binding) |
read_array_dyn::<T>() | ArrayD<T> | runtime | the rank is only known at runtime |
read_array infers the dimensionality D from the binding’s type, so a call site reads naturally as let m: Array2<f64> = ds.read_array()?;. If the dataset’s runtime rank does not match D, it returns Error::Shape. Reach for read_array_dyn in that case.
use hdf5_pure::File;
use ndarray::{Array2, ArrayD};
let file = File::open(&path)?;
// Statically known rank: inferred from the binding type.
let m: Array2<f64> = file.dataset("m")?.read_array()?;
// Rank only known at runtime.
let dynamic: ArrayD<f64> = file.dataset("m")?.read_array_dyn()?;
println!("runtime rank: {}", dynamic.ndim());For both methods, T is the type you want the elements delivered as, not an assertion about the stored datatype. The bytes are coerced into T using the same rules as the scalar reads described in Reading files and Generic element I/O, so the conversion can be lossy (reading an f64 dataset as i32 truncates). Pick T to match the stored type when you need an exact, lossless read.
§Chaining chunking and compression
with_ndarray returns the builder, so chunking and compression chain just like they do for the flat write methods. This is the natural way to write a large array compressed:
use hdf5_pure::FileBuilder;
use ndarray::Array2;
let a = Array2::<f64>::zeros((1024, 1024));
let mut fb = FileBuilder::new();
fb.create_dataset("big")
.with_ndarray(&a)
.with_chunks(&[64, 64])
.with_deflate(6);
let bytes = fb.finish()?;See Compression and filters for the full set of available filters and how to combine them.