rectangular_array_write_read/
rectangular_array_write_read.rs

1#![allow(missing_docs)]
2
3use std::sync::Arc;
4use zarrs::{
5    array::chunk_grid::RectangularChunkGridConfiguration,
6    storage::{
7        storage_adapter::usage_log::UsageLogStorageAdapter, ReadableWritableListableStorage,
8    },
9};
10use zarrs_metadata::v3::MetadataV3;
11
12fn rectangular_array_write_read() -> Result<(), Box<dyn std::error::Error>> {
13    use rayon::prelude::{IntoParallelIterator, ParallelIterator};
14    use zarrs::{
15        array::{codec, DataType, ZARR_NAN_F32},
16        array_subset::ArraySubset,
17        node::Node,
18        storage::store,
19    };
20
21    // Create a store
22    // let path = tempfile::TempDir::new()?;
23    // let mut store: ReadableWritableListableStorage =
24    //     Arc::new(zarrs::filesystem::FilesystemStore::new(path.path())?);
25    let mut store: ReadableWritableListableStorage = Arc::new(store::MemoryStore::new());
26    if let Some(arg1) = std::env::args().collect::<Vec<_>>().get(1) {
27        if arg1 == "--usage-log" {
28            let log_writer = Arc::new(std::sync::Mutex::new(
29                // std::io::BufWriter::new(
30                std::io::stdout(),
31                //    )
32            ));
33            store = Arc::new(UsageLogStorageAdapter::new(store, log_writer, || {
34                chrono::Utc::now().format("[%T%.3f] ").to_string()
35            }));
36        }
37    }
38
39    // Create the root group
40    zarrs::group::GroupBuilder::new()
41        .build(store.clone(), "/")?
42        .store_metadata()?;
43
44    // Create a group with attributes
45    let group_path = "/group";
46    let mut group = zarrs::group::GroupBuilder::new().build(store.clone(), group_path)?;
47    group
48        .attributes_mut()
49        .insert("foo".into(), serde_json::Value::String("bar".into()));
50    group.store_metadata()?;
51
52    println!(
53        "The group metadata is:\n{}\n",
54        group.metadata().to_string_pretty()
55    );
56
57    // Create an array
58    let array_path = "/group/array";
59    let array = zarrs::array::ArrayBuilder::new(
60        vec![8, 8], // array shape
61        MetadataV3::new_with_configuration(
62            "rectangular",
63            RectangularChunkGridConfiguration {
64                chunk_shape: vec![[1, 2, 3, 2].try_into()?, 4.try_into()?], // chunk sizes
65            },
66        ),
67        DataType::Float32,
68        ZARR_NAN_F32,
69    )
70    .bytes_to_bytes_codecs(vec![
71        #[cfg(feature = "gzip")]
72        Arc::new(codec::GzipCodec::new(5)?),
73    ])
74    .dimension_names(["y", "x"].into())
75    // .storage_transformers(vec![].into())
76    .build(store.clone(), array_path)?;
77
78    // Write array metadata to store
79    array.store_metadata()?;
80
81    // Write some chunks (in parallel)
82    (0..4).into_par_iter().try_for_each(|i| {
83        let chunk_grid = array.chunk_grid();
84        let chunk_indices = vec![i, 0];
85        if let Some(chunk_shape) = chunk_grid.chunk_shape(&chunk_indices)? {
86            let chunk_array = ndarray::ArrayD::<f32>::from_elem(
87                chunk_shape
88                    .iter()
89                    .map(|u| u.get() as usize)
90                    .collect::<Vec<_>>(),
91                i as f32,
92            );
93            array.store_chunk_ndarray(&chunk_indices, chunk_array)
94        } else {
95            Err(zarrs::array::ArrayError::InvalidChunkGridIndicesError(
96                chunk_indices.to_vec(),
97            ))
98        }
99    })?;
100
101    println!(
102        "The array metadata is:\n{}\n",
103        array.metadata().to_string_pretty()
104    );
105
106    // Write a subset spanning multiple chunks, including updating chunks already written
107    array.store_array_subset_ndarray(
108        &[3, 3], // start
109        ndarray::ArrayD::<f32>::from_shape_vec(
110            vec![3, 3],
111            vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9],
112        )?,
113    )?;
114
115    // Store elements directly, in this case set the 7th column to 123.0
116    array.store_array_subset_elements::<f32>(
117        &ArraySubset::new_with_ranges(&[0..8, 6..7]),
118        &[123.0; 8],
119    )?;
120
121    // Store elements directly in a chunk, in this case set the last row of the bottom right chunk
122    array.store_chunk_subset_elements::<f32>(
123        // chunk indices
124        &[3, 1],
125        // subset within chunk
126        &ArraySubset::new_with_ranges(&[1..2, 0..4]),
127        &[-4.0; 4],
128    )?;
129
130    // Read the whole array
131    let data_all = array.retrieve_array_subset_ndarray::<f32>(&array.subset_all())?;
132    println!("The whole array is:\n{data_all}\n");
133
134    // Read a chunk back from the store
135    let chunk_indices = vec![1, 0];
136    let data_chunk = array.retrieve_chunk_ndarray::<f32>(&chunk_indices)?;
137    println!("Chunk [1,0] is:\n{data_chunk}\n");
138
139    // Read the central 4x2 subset of the array
140    let subset_4x2 = ArraySubset::new_with_ranges(&[2..6, 3..5]); // the center 4x2 region
141    let data_4x2 = array.retrieve_array_subset_ndarray::<f32>(&subset_4x2)?;
142    println!("The middle 4x2 subset is:\n{data_4x2}\n");
143
144    // Show the hierarchy
145    let node = Node::open(&store, "/").unwrap();
146    let tree = node.hierarchy_tree();
147    println!("The Zarr hierarchy tree is:\n{tree}");
148
149    Ok(())
150}
151
152fn main() {
153    if let Err(err) = rectangular_array_write_read() {
154        println!("{:?}", err);
155    }
156}