Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Convert your data

chronozarr convert SOURCE OUT writes a store from rasters that you already have. It reads one timestep at a time and encodes a few 512 by 512 cells at a time, so the files never have to fit in memory together. With package 0.4.0 the memory of the encode step still grows with the number of timesteps; the next release keeps it nearly flat (memory).

Your dataSection
A folder, a glob or an s3:// prefix of GeoTIFFs with a date in each nameFrom dated GeoTIFFs
COGs at URLs, with dates in a tableFrom a manifest of URLs
A NetCDF file or a Zarr store with a time axisFrom NetCDF or Zarr
An xarray DataArray in PythonFrom xarray
Rendered PNG framesPNG frames

Every route checks all inputs before it writes anything. Nothing is resampled or rescaled unless you ask.

From dated GeoTIFFs

Point convert at a directory, a quoted glob or an s3:// prefix. Each file name holds one date: 20240131, 2024-01-31 or 2024-01.

chronozarr convert "scenes/*.tif" my_store --dry-run   # check every file, write nothing
chronozarr convert "scenes/*.tif" my_store

The dry run runs the same discovery and checks as conversion. It prints each file with its date, the grid, the bands, the scaling, the validity rule and the expected size. A directory or s3:// prefix is not searched recursively; use a glob such as "scenes/**/*.tif" for subdirectories. Listing an S3 prefix needs the s3 extra (uv tool install --python 3.13 'chronozarr[geo,s3]==0.4.0') and uses your AWS credentials.

A date is read from a name only when the name holds exactly one. A name with no date, with several (20240215_2024-03), or two files with the same date are reported, never guessed. --date-pattern says where the date is, for example --date-pattern "ndvi_%Y%m%d". --write-manifest found.csv saves discovered files and dates as a manifest that convert reads back; it is the one output allowed with --dry-run.

Before it reads any pixels in bulk, convert checks every file for its date, grid and CRS, bands, dtype, scale, offset, units and nodata. It reports all problems at once, grouped by file, each with a suggested fix, and writes nothing:

2 problem(s) in 2 of 24 source file(s); nothing was written:

scenes/ndvi_2024-03.tif
  - has scales [0.5, 1.0]; scenes/ndvi_2024-01.tif has [1.0, 1.0]. A store holds one value per band for every timestep, so the sources must agree
    fix: if the metadata is wrong, correct it (gdal_edit.py -scale -offset -units); ...

scenes/readme_copy.tif
  - no date in the file name
    fix: name the date YYYYMMDD, YYYY-MM-DD or YYYY-MM, or pass --date-pattern ...

Files on another grid fail with a suggestion to pass --resampling, which warps them to the grid of the first file.

The store takes each band's description (its name), scale, offset and units from the files, so a Sentinel-2 file with a scale of 0.0001 gives reflectance. These must be identical in every file. A file whose bands have no description gives bands named 1, 2 and so on. To name them, write the files and dates to a manifest with --write-manifest found.csv, add a bands column such as ndvi, and convert the manifest. The store also takes the nodata value that the files declare. Files that declare none give a store with no nodata, so a stored 0 is data. --nodata 0 sets one.

From a manifest of URLs

A manifest lists the files and their dates. Use it when the dates are not in the file names, or when the files are at URLs.

uri,datetime
https://example.org/cogs/scene_a.tif,2024-01-15
https://example.org/cogs/scene_b.tif,2024-02-14
s3://my-bucket/cogs/scene_c.tif,2024-03-16T10:30:00Z
chronozarr convert manifest.csv my_store

A CSV manifest has the columns uri and datetime, and an optional bands column with names separated by ;. A JSON manifest is a list of {"uri": ..., "datetime": ...} objects. Relative paths are relative to the manifest. The target grid is the grid of the first file, unless you give --crs, --transform and --shape. Files on another grid need --resampling.

From NetCDF or Zarr

chronozarr convert model.nc my_store --variable tas
chronozarr convert data.zarr my_store --variable ndvi --crs EPSG:32618

--variable names the array to convert. Its dimensions must be time, y and x, with an optional band dimension. --dims time=NAME,y=NAME,x=NAME[,band=NAME] names them when they are not time, y, x or common aliases such as lat and lon. --crs gives the coordinate system when the file does not declare it. The CF scale_factor, add_offset and units of the variable apply to every band. --mask-var names a variable whose nonzero values mark valid pixels.

For an array that fits in memory, chronozarr encode FILE my_store --variable NAME is the shorter route.

From xarray

In a script or notebook, write a DataArray with dimensions (time, band, y, x):

import chronozarr
 
chronozarr.encode(da, "my_store", crs="EPSG:32618")

The x and y coordinates are the projected pixel centres. See How it works for a complete script, and the Python API for the options.

Band roles

The viewer offers True color, False color, NDVI, NDWI and Water when it knows which band is red, green, blue and near infrared. It recognizes the names red, green, blue and nir, and the Sentinel-2 names B02, B03, B04 and B08. For other names, set the roles:

chronozarr bands my_store                              # list bands, roles and products
chronozarr bands my_store --band-role b4=red,b8=nir    # set roles

convert and encode take --band-role too. A store without roles still opens, with the Single band product. See Band roles and the first view.

Check the store

chronozarr validate my_store
chronozarr info my_store

validate checks the store against the specification. info prints the times, bands and levels.

Next