Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ncv documentation

Documentation for ncv 0.5.21.

ncv is a terminal-native, read-only scientific data viewer for NetCDF-4, GRIB2, and Kerchunk/VirtualiZarr reference manifests. It is designed for SSH sessions on HPC systems and ships as a single Rust binary with no native NetCDF/HDF5 runtime dependency.

The focus is fast inspection, not editing: slice a variable, inspect exact values, compare time/depth frames, and export a publication-ready view — all without leaving the terminal.

How these docs are organized

This site follows the Diátaxis framework — four quadrants for four different reader needs:

QuadrantAnswersStart here
Tutorials“Teach me the basics”Quickstart
How-To Guides“Help me do a specific task”Inspect a variable
Reference“Tell me exactly what X does”Keyboard · CLI · Environment
Explanation“Help me understand why”Data fidelity

At a glance

  • Open: ncv data.nc, ncv forecast*.grib2, or ncv s3://bucket/key
  • Navigate: ↑/↓ variables, </> time, [/] depth, {/} files
  • Style: c palette, v reverse, a/l limits, f mask, s scale, z scope
  • Analyze: Space playback, click to pin, Enter/p for plots
  • Share: e exports PNG + SVG + JSON
  • Help: ? in-app help, Ctrl-P/: command palette, q quits cleanly

Get the tool

Download from GitHub Releases or build with cargo install --path . --locked. See the Quickstart for both paths.

Source, issues, and releases live at https://github.com/bbakernoaa/ncview-rs.

Tutorials

Learning-oriented walkthroughs that teach ncv by doing. Start here if you have never run the viewer.

Quickstart: your first view in five minutes

This tutorial takes you from an empty terminal to an interactive view of a scientific variable, including a remote public-bucket dataset. By the end you will know how to install ncv, open a file, confirm you are looking at real values, and find your way around the dashboard.

What you need: a terminal on Linux (x86_64), macOS (arm64), or Windows (x86_64), and any NetCDF-4 (HDF5) or GRIB2 file — or the public example below.

1. Install the viewer

Grab the platform archive from the GitHub Releases page, unpack it, and put ncv on your PATH:

tar -xzf ncv-linux-x86_64.tar.gz
install -m 755 ncv/ncv ~/.local/bin/ncv
ncv --version
# ncv 0.5.21

On older HPC distributions with an aging glibc, use the static build ncv-linux-x86_64-musl.tar.gz instead. Every release ships a SHA256SUMS file — verify before installing on shared systems.

Option B — build from source

With Rust 1.90 or newer:

git clone https://github.com/bbakernoaa/ncview-rs.git
cd ncview-rs
cargo install --path . --locked
ncv --version

There is no native NetCDF/HDF5 runtime dependency to install.

2. Open a dataset

Point ncv at one or more files (shell globs are expanded for you):

ncv path/to/data.nc
ncv forecast*.grib2

You should land on the dashboard: a variable list on the left, the rendered field in the middle, a colorbar on the right, and a timeline/level band along the bottom. The status line shows the displayed slice’s min/max/mean and a finite count — your first fidelity check that real source values are in play.

3. Do the three things you will do most

  1. Change variable — ↑/↓ moves through the variable list.
  2. Step through time — </> moves to the previous/next time slice; Space plays the timeline (-/+ set playback speed).
  3. Get help — ? opens the keyboard/mouse reference; Ctrl-P (or :) opens a searchable command palette. Press q to quit — the terminal is always restored exactly as it was.

To start with a numeric region, give all four x/y bounds on the command line:

ncv --min-x -130 --max-x -60 --min-y 20 --max-y 55 path/to/data.nc

Inside the viewer, use Ctrl-P and choose Set view bounds to enter the same four values. Both paths work with geographic coordinates and with zero-based x/y indices when the dataset has no coordinate values. Box zoom continues to work, and changing variables returns to that variable’s global view. See the CLI reference for longitude conventions and validation details.

4. Try a remote public bucket (optional)

ncv reads explicit object locations directly, with credential-free access for public buckets:

ncv s3://noaa-gefs-pds/chem/2026/09/30/12/GEFS.chem.t12z.a2d_0p25.f000.grib2

If your environment has no cloud credentials, public buckets are read anonymously without stalling. Force the mode with NCVIEW_ANONYMOUS_ACCESS=1; any other value, including =0, leaves the choice to the automatic decision. See Access remote data for the details.

5. Know what you are looking at

  • Values are never modified: missing, fill, NaN, and infinity cells are masked by the loader and reported honestly in the statistics.
  • If the map looks like colored blocks rather than an image, you are on the portable cell fallback — one truecolor block per terminal cell, just less pretty than an image protocol. See Run over SSH.
  • e exports the current slice as PNG + SVG + JSON for slides and notebooks.

Next steps

How-To Guides

Task-oriented recipes: each guide solves one concrete problem.

Inspect a variable

Goal: read exact values, understand coordinates, and inspect a specific point of a dataset slice.

Open and select files

ncv data.nc                      # single file
ncv run*.nc                      # shell glob (expanded by ncv itself too)
ncv a.nc b.nc c.nc               # explicit list; { and } switch files

Source files are opened read-only and never modified.

Move through variables and slices

Do thisPress
Previous / next variable↑ / ↓ (or click the sidebar list)
Previous / next time slice← / →, or < / >
Previous / next depth slice[ / ] (or the level bar)
Search all plottable variables/
Run any action by nameCtrl-P or :

Read the status bar

The status line reports, for the displayed slice:

  • the active variable name (subgroup variables appear qualified, e.g. physics/temperature),
  • min / max / mean and a finite count — non-finite values are counted but never averaged into the statistics,
  • the active time label and depth label when the axes exist.

Hover the mouse anywhere on the map to see that cell’s latitude, longitude, and source value. On files without recognizable coordinate variables the readout falls back to source indices — it says so explicitly rather than inventing coordinates.

Pin a point and inspect its history

  1. Click a map cell — it gets a ◆ marker.
  2. Press Enter to open its time-series plot, or p for the plot chooser: t time series, d scatter, h histogram, k CDF, u vertical profile.
  3. Hover other points and press m to add them to the same plot for multi-trace comparison.

Curvilinear and projected grids

Files with 2-D latitude/longitude fields render in projected mode. Press g to switch between logical and projected grid. In projected mode the pixel → coordinate lookup is nearest-coordinate; the status bar discloses the approximation and keeps the original source indices visible. See Data fidelity for what this does and does not guarantee.

Style the map

Goal: get a publication-worthy view — choose a colormap, set data limits, mask values, pick a scale mode, and add geographic context.

Choose and tune a colormap

TaskDo this
Cycle built-in palettesc or the sidebar palette button
Reverse the palettev
Add custom .ncmap filesput them in the working directory, or set NCVIEW_COLORMAPS=/path/to/maps (NCVIEW_LIB_DIR and NCVIEWBASE are also searched, including share/ncview/colormaps)

Built-ins: Viridis, Plasma, Turbo, Inferno, Magma, Cividis, Cool, Warm, Cubehelix, Spectral. Malformed .ncmap files are ignored at startup, so a bad file can never break the viewer.

Set data limits

TaskDo this
Automatic limits from the displayed slicea
Type exact min/maxl — type into a field, Tab switches fields, Enter applies, Esc cancels
Mask everything outside a rangef
Linear ↔ logarithmic color scales
Scale scope: current-slice vs unzoomed-globalz or the sidebar scale-scope button
Reset zoomr

Manual limits always take precedence over either automatic mode. _FillValue and missing values stay masked automatically regardless of your settings.

Zoom and pan

  • Drag across the map to zoom to a rectangle.
  • Drag a zoomed map to pan, or use Shift+arrows.
  • Shift-drag while already zoomed zooms again inside the current view.
  • r returns to the full map.

Zooming changes which values the current-slice automatic limits see; switch the scope to global with z if you want colors to stay stable while zooming.

Geographic backdrop

Press b to layer a D3-inspired ocean, graticule, and filled Natural Earth land backdrop beneath the raster. Valid data composites on top; fill/missing cells reveal the geography. It is a presentation aid only — it never changes data values or replaces a dataset-provided land/sea mask.

Select coastline detail with NCVIEW_LAND_DETAIL=auto|110m|50m|10m (110m is the fast default once enabled; the overlay starts disabled so first render stays light).

Export the result

Press e to write the current variable/time/depth slice as PNG + SVG + JSON. See Compare and export.

Navigate time, depth, and files

Goal: move through the fourth dimension efficiently — animate time, seek vertical levels, and switch between open datasets.

Step and play the time axis

TaskDo this
Previous / next time slice← / → or < / >
Play / pause the timelineSpace, or click the Play/Pause button
Playback speed- / + or the labeled speed controls on the timeline
Seek to a dateclick or drag the timeline gauge
Switch active file{ / } (the header shows “opened file N/M”)

When several files form one collection, the timeline spans all of them and file switching keeps you on the corresponding time slot of the new file.

Seek vertical levels

For variables with a depth/level axis, a full-width Level bar sits above the time bar showing index/N plus the CF level label (falling back to the dimension name when the file has none):

  • Click or drag the level bar to seek.
  • Scroll over it to step one level.
  • [ / ] step levels from anywhere.
  • Tab focuses the sidebar Level list; ↑/↓ move the cursor, Enter applies it, Tab/Esc leave focus.

Two-dimensional variables hide the level bar entirely — no dead controls.

Zoom to a region

Drag across the map to zoom to a rectangle. To enter numeric bounds, open the command palette with Ctrl-P or :, search for Set view bounds, and enter minimum and maximum x/y values. Tab moves between fields; Enter applies; Esc cancels. The existing box zoom and pan controls remain available.

For geographic axes, longitude accepts signed degrees or 0..360, and latitude must be within -90..90. The viewer maps coordinate endpoints to the smallest source-index range containing the samples. Other axes use their one-dimensional coordinate values when available, or inclusive zero-based indices when they are dimension-only. Invalid or non-overlapping bounds leave the accepted view unchanged. Curvilinear grids use a row/column envelope and disclose that approximation in the status line.

Selecting a different variable returns to that variable’s global view, since its coordinate system and domain may differ. The zoom for a dataset is still remembered between launches; explicit CLI bounds override the restored zoom. See the CLI reference for startup examples.

Session restore

ncv remembers your last view (variable, slice, limits) per dataset and restores it on the next launch. To start clean:

ncv --no-restore data.nc

The session directory can be relocated with NCVIEW_SESSION_DIR (useful on shared HPC head nodes). See Environment reference.

Access remote data

Goal: open NetCDF-4 or GRIB2 objects stored in S3, GCS, or Azure Blob without downloading them first.

Accepted location forms

ncv s3://bucket/key
ncv gs://bucket/key
ncv az://container/key
ncv abfs://container@account.dfs.core.windows.net/key   # and abfss://

The terminal starts immediately; remote metadata and range reads happen on a loader thread, so the UI never blocks on the network.

Credentials

Ambient provider configuration is used when present (AWS_*, GOOGLE_*, AZURE_*). Secrets are never accepted in arguments and never persisted.

Public buckets without credentials

On a laptop or any host with no cloud credentials, ncv detects that the instance metadata service is unreachable and reads public buckets (for example s3://noaa-gefs-pds/...) with anonymous, credential-free access instead of stalling on metadata-token retries.

WantDo this
Force anonymous modeNCVIEW_ANONYMOUS_ACCESS=1
Keep the automatic decisionUnset it, or set any non-truthy value such as 0

See Remote access explanation for why the metadata probe matters.

GRIB2 over the network

Remote GRIB2 objects use bounded HEAD/range requests, plus an optional colocated .idx sidecar when available. A large unindexed GRIB2 object is refused rather than silently downloaded in full — add the .idx sidecar (or generate a reference manifest, see Generate a GRIB2 manifest).

Remote NetCDF-4

Objects up to 64 MiB use a bounded fallback byte reader. Larger objects use a bounded metadata window and source-backed HDF5 range reads for chunk indexes, compressed chunks, masks, coordinates, and selected rows — for these larger objects, the whole object is never materialized. Unsupported HDF5 layouts fail with an actionable diagnostic rather than a partial view.

Run over SSH

Goal: get the best map rendering on a remote HPC or cloud session, and know the portable fallback when graphics protocols are unavailable.

It just works (usually)

Connect with SSH and run ncv as usual. ncv detects the terminal’s image capability after entering the session and uses Kitty, Sixel, or iTerm2 graphics when available. The header always reports the active renderer:

Kitty truecolor · Sixel truecolor · iTerm2 truecolor · cell fallback

No X11 forwarding, native NetCDF/HDF5 runtime, or Chafa installation is needed.

The cell fallback is always available

If your terminal (or a multiplexer) supports no image protocol, ncv renders the map with its own cell rasterizer: one truecolor background block per terminal cell. It is fully functional — hover, click, zoom, and export all work. Capability enhancement never becomes capability lockout.

Force a protocol when probing is blocked

tmux and some multiplexers swallow the capability query. Tell ncv what to use:

NCVIEW_IMAGE_PROTOCOL=kitty  ncv data.nc
NCVIEW_IMAGE_PROTOCOL=sixel  ncv data.nc
NCVIEW_IMAGE_PROTOCOL=iterm2 ncv data.nc
NCVIEW_IMAGE_PROTOCOL=cells  ncv data.nc   # conservative, works everywhere

A conservative SSH launch that always renders:

NCVIEW_IMAGE_PROTOCOL=cells ncv data.nc

Open directly to a bounded region

You can set the initial extent in an SSH command without interacting with the terminal first. Pass all four bounds together; geographic datasets accept signed longitude or 0..360 longitude and latitude from -90..90:

ncv --min-x 0 --max-x 60 --min-y 20 --max-y 65 forecast.nc

The command also works for dimension-only data, where bounds are inclusive, zero-based x/y cell indices. In the interactive viewer, Set view bounds in the command palette provides the same entry fields alongside the existing box zoom. Invalid or non-overlapping bounds keep the current view intact. See the CLI reference for coordinate and error behavior.

Terminal-specific protocols

Some terminals or terminal versions have protocol-specific limitations. Set NCVIEW_IMAGE_PROTOCOL to the protocol you want to use; ncv honors an explicit setting as given. Use NCVIEW_IMAGE_PROTOCOL=cells for the portable fallback.

Keep scientific cells crisp

By default the map is nearest-neighbor upsampled so zoomed scientific cells stay sharp. To allow interpolation:

NCVIEW_SCIENTIFIC_RENDERING=0 NCVIEW_IMAGE_FILTER=lanczos3 ncv data.nc

(Then i cycles filters interactively. See Terminal protocols explanation.)

Generate a GRIB2 reference manifest

Goal: turn a GRIB2 file and its NOAA-style .idx sidecar into a deterministic Kerchunk-compatible reference JSON that tools like VirtualiZarr (or ncv itself) can open as a virtual dataset.

The command

ncv manifest \
  --format kerchunk \
  --input forecast.grib2 \
  --idx forecast.grib2.idx \
  --output forecast.refs.json \
  --strict
FlagMeaning
--formatkerchunk or virtualizarr (the VirtualiZarr Kerchunk-parser profile)
--inputGRIB2 source object
--idxmatching .idx sidecar
--outputdestination manifest JSON
--source-uriURI to embed in byte-range references instead of the local path (use this when the manifest will point at a remote object)
--stricttreat warnings and mismatches as errors

What the manifest preserves

The manifest keeps raw GRIB2 table codes and the full Section 4 product payload, so fields that share a display short name (for example aerosol AOTK) remain independently selectable by species, particle-size interval, wavelength, and product-template context. Opening the manifest later shows each species as its own variable.

Use it

ncv forecast.refs.json        # open the virtual dataset directly — no download
ncv s3://bucket/forecast.refs.json   # or pair it with the remote source object

Reference manifests describe byte ranges — they never copy or modify the source GRIB2 data.

Table inventory

The pinned NOAA/NCEP GRIB2 table inventory and its update policy live in tools/grib2_tables/README.md in the repository.

Compare and export

Goal: see the difference between two datasets, and export a slice for a presentation or notebook.

Difference mode

Compare two files — or two sets of files — side by side:

ncv --diff control.nc experiment.nc
ncv --diff first="run1*.nc" second="run2*.nc"

actionable error otherwise. For multiple files on each side, use the explicit first= (or 1=) and second= (or 2=) prefixes to keep the two sets clear. Without prefixes, the first file is side one and all remaining files are side two. Diff mode needs at least one file on each side and reports an actionable error otherwise.

Export the current view

Press e to write the current variable/time/depth slice as three artifacts:

FileUse it for
PNGdirect insertion into slides/reports — map, colorbar, and tick marks on a 16:9 canvas
SVGeditable text and full metadata; scales to any size
JSON sidecarmachine-readable CF/COARDS names, units, limits, and slice coordinates

Tune the export

WantSet
Output directoryNCVIEW_EXPORT_DIR=/path
Opaque white canvasNCVIEW_EXPORT_BACKGROUND=white (default is transparent)
Light text for dark slidesNCVIEW_EXPORT_TEXT=light
Custom SVG fontNCVIEW_EXPORT_FONT="Iosevka Nerd Font, sans-serif"

PNG exports always use the embedded font so they stay deterministic on machines without your chosen font installed.

Derive variables with formulas

Goal: compute new fields from the variables you already have — differences between runs, unit conversions, wind speed, time-mean maps — and view or export them like any other variable. The feature follows the VERDI formula editor: every dataset you open gets a number, and NAME[n] refers to variable NAME in dataset n.

Open several datasets at once

List every file on the command line (globs work, quoted or not). The order sets the dataset numbers used in formulas:

ncv base.nc sensitivity.nc          # [1] = base.nc, [2] = sensitivity.nc
ncv "run_*.nc"                      # numbered in sorted order
ncv s3://bucket/a.nc local/b.nc     # remote and local sources mix freely

The formula editor lists the numbered datasets at the top, so you never have to remember the order.

Use the formula editor

  1. Press = (or open the command palette with : and choose Open formula editor).
  2. Type an expression, for example O3[1] - O3[2].
  3. Press Enter. The result is added to the variable list and displayed immediately; time, depth, zoom, plots, and export (e) all work on it.
KeyIn the formula editor
any charactertype into the formula
Backspacedelete the last character
Enteradd the formula (or replace the one with the same name) and plot it
↑ / ↓recall a formula defined earlier into the input line
Deleteremove the recalled formula
Escclose the editor (the draft is kept)

Give a result a short name with name = expression; otherwise the expression text itself is the variable name:

dO3 = O3[1] - O3[2]
wspd = sqrt(U^2 + V^2)
T_C = T - 273.15

Formula language

CategorySyntaxNotes
Arithmetic+ - * /usual precedence; parentheses group
Exponent^ or **right-associative: 2^3^2 = 2^9; -x^2 = -(x^2)
Trigonometrysin(x) cos(x) tan(x)radians
Logarithm / exponentiallog(x) (natural; alias ln), log10(x), exp(x)
Othersqrt(x), abs(x)
Time aggregationmean(x) sum(x) min(x) max(x)per grid cell, over every time step
Layer aggregationlayer_mean(x) layer_sum(x) layer_min(x) layer_max(x)per grid cell, over every vertical level
VariablesNAMEthe dataset currently on screen
Dataset variablesNAME[n]dataset n (1-based)
Quoted names"air-temp" or 'air temp'names with characters other than letters, digits, _, .
Numbers2, 0.5, 1.5e-3

Aggregations can be combined with everything else, e.g. the anomaly from the time mean is T - mean(T), and the column-mean difference between two runs is layer_mean(O3[1]) - layer_mean(O3[2]).

How results are shaped

  • The result takes the grid and dimensions of the first variable in the formula; all other grids must have the same 2-D shape.
  • A time aggregation removes the time axis when nothing outside it varies in time (mean(T) is a single map; T - mean(T) still has every time step). Layer aggregations do the same for the vertical axis.
  • A variable without a time (or vertical) axis is reused for every step, so a static field such as area can multiply a time-varying one.
  • Variables whose time lengths differ (other than 1) are rejected rather than silently misaligned.

Missing values and domain errors

  • A cell that is missing, fill, or out of the valid range in any input is missing in the result.
  • Aggregations skip missing samples; a cell with no valid sample is missing.
  • Values produced by the arithmetic itself, like log of a negative number or division by zero, are kept as NaN / ±Inf and shown with the usual non-finite diagnostics, so domain errors are never hidden.

Which dataset owns a formula

  • A formula that uses any unqualified NAME is evaluated for each dataset: in a time collection, T * 2 doubles every file.
  • A formula in which every reference has [n] is attached only to the first referenced dataset, so it appears once in the timeline. Selecting it switches to that dataset automatically.

Pass formulas on the command line

--formula (repeatable) preloads formulas and selects the first one. The VERDI spelling -formula is accepted too:

ncv --formula "dO3 = O3[1] - O3[2]" base.nc sensitivity.nc
ncv -formula "mean(PM25)" -formula "max(PM25)" cmaq_*.nc

Generate images without the terminal UI (batch mode)

Add --batch to evaluate every --formula and write the same PNG, SVG, and JSON files as the e key, then exit — useful in scripts, cron jobs, and HPC batch queues:

ncv --batch --export-dir plots \
    --formula "dO3 = O3[1] - O3[2]" \
    --formula "avg = mean(O3[1])" \
    --time 12 --level 0 \
    base.nc sensitivity.nc
FlagDefaultPurpose
--batchoffexport instead of opening the terminal UI
--export-dir <DIR>NCVIEW_EXPORT_DIR or .output directory
--time <INDEX>0zero-based time step to export
--level <INDEX>0zero-based vertical level to export

Each written PNG path is printed on its own line. File names follow <dataset>_<formula>_t<time>_z<level>.{png,svg,json}; the export environment variables in Compare and export apply. A parse error, an unknown variable, or an out-of-range index stops the run with exit status 2 and a message naming the formula.

Reference

Information-oriented lookup: complete, accurate, and nothing else.

Keyboard & mouse reference

Every interactive control, in one table. This mirrors the in-app help (?).

Keyboard

KeyAction
q / Escquit (Esc closes a dialog first)
↑ / ↓previous / next variable
← / →previous / next time slice
< / >previous / next time slice
Spaceplay / pause the timeline
- / +decrease / increase playback speed
{ / }previous / next file
[ / ]previous / next depth slice
, / .select previous / next extra dimension
; / 'previous / next index in selected dimension
Tabfocus the sidebar level list (Tab/Esc leave it); in dialogs/plot chooser it switches field/axis
Shift+arrowspan the zoomed map
copen colormap chooser with a focused preview
vreverse the active colormap; in the chooser, reverse the focused preview
icycle interpolation (set NCVIEW_SCIENTIFIC_RENDERING=0 to unlock)
eexport current slice (PNG + SVG + JSON)
=formula editor — derive variables such as O3[1]-O3[2] or mean(T)
aautomatic limits
ledit min/max limits
fmask data outside a range
stoggle linear/log color scale
ztoggle current/global color scale
rreset zoom to the full view
Rreset variable settings and view
glogical / projected grid
btoggle filled land/ocean map backdrop
Enteropen pinned-point plot menu
popen plot chooser
t / d / hplot chooser: time series / scatter / histogram
k / uplot chooser: CDF / vertical profile
madd/remove the hovered point from the plot selection
Ctrl-P / :command palette — search actions, Enter to run
/browse and search all plottable variables
?open/close this help

Limits dialog

Type numbers directly, Tab switches between min and max fields, Enter applies, Esc cancels.

Set view bounds dialog

Open the command palette with Ctrl-P / :, search for Set view bounds, then enter minimum and maximum x and y values. Tab moves between the four fields, Enter applies the bounds, and Esc cancels. Geographic axes accept signed longitude or 0..360 longitude and latitude from -90..90. Other axes use their coordinate values when available, or inclusive zero-based indices. Unphysical or non-overlapping bounds are reported without replacing the current view. For curvilinear grids, the status line notes that the region is represented by a row/column envelope. Map dragging continues to provide box zoom.

Mouse

GestureAction
Move over maphover row/col/value readout in the status bar
Click mappin a point (◆), then Enter or p for plot choices
Hover + maccumulate multiple points for multi-trace plots
Clicksidebar buttons, variables, timeline play/pause, speed controls
Click / drag the level barseek the vertical level
Wheel over the sidebarscroll the level or variable list
Drag mapzoom to a rectangle; drag a zoomed map to pan
Shift+dragzoom again while already zoomed
Right-click or ?close this help

Command-line reference

ncv [OPTIONS] [DATASET]... [COMMAND]

Options

FlagValuesPurpose
--diff—Enable difference mode between two files or two sets of files
--first <PATTERN>path/globFirst file or glob pattern for diff mode
--second <PATTERN>path/globSecond file or glob pattern for diff mode
--formula <EXPR>expressionAdd a derived variable (repeatable); NAME[n] reads dataset n. -formula is accepted as a VERDI-style alias
--batch—Evaluate every --formula and export PNG/SVG/JSON without opening the terminal UI
--export-dir <DIR>pathOutput directory for --batch (default NCVIEW_EXPORT_DIR or .)
--time <INDEX>integerZero-based time step exported by --batch (default 0)
--level <INDEX>integerZero-based vertical level exported by --batch (default 0)
--no-restore—Do not restore previous session state for the dataset(s)
--grid <PATH>pathMPAS mesh/coordinate file supplying latCell/lonCell or latVertex/lonVertex when the dataset has none
--min-x <X>numberMinimum x coordinate or zero-based x index for the initial view
--max-x <X>numberMaximum x coordinate or zero-based x index for the initial view
--min-y <Y>numberMinimum y coordinate or zero-based y index for the initial view
--max-y <Y>numberMaximum y coordinate or zero-based y index for the initial view
-h, --help—Print help
-V, --version—Print version

Positional arguments

[DATASET]... — one or more NetCDF-4 or GRIB2 datasets to inspect. Shell globs are supported (expanded by ncv itself, so quoting patterns works on any shell). With --diff, inputs are split into two sets: use first=/1= and second=/2= prefixes, or --first/--second, or simply list the first set followed by the second.

Subcommand: ncv manifest

Create a Kerchunk-compatible GRIB2 reference manifest from a .idx sidecar.

FlagValuesPurpose
--formatkerchunk | virtualizarrOutput profile; virtualizarr emits a VirtualiZarr-consumable Kerchunk profile
--inputpath/URIGRIB2 source object
--idxpathMatching NOAA-style .idx sidecar
--outputpathManifest destination JSON
--source-uriURIURI to place in byte-range references instead of the local source path
--strict—Treat warnings and mismatches as errors
ncv manifest --format kerchunk --input forecast.grib2 --idx forecast.grib2.idx \
  --output forecast.refs.json --strict

Examples

ncv data.nc                                  # open one file
ncv run*.grib2                               # open a collection
ncv --diff control.nc experiment.nc          # two-file difference mode
ncv --diff first="a*.nc" second="b*.nc"      # set-vs-set difference mode
ncv --no-restore data.nc                     # ignore saved session state
ncv s3://noaa-gefs-pds/...f000.grib2         # remote public bucket
ncv --min-x -130 --max-x -60 --min-y 20 --max-y 55 data.nc
ncv --min-x 0 --max-x 100 --min-y 20 --max-y 80 image-only.nc
ncv --formula "d = O3[1]-O3[2]" a.nc b.nc    # cross-file formula in the UI
ncv --batch --export-dir out --formula "mean(O3)" a.nc  # headless export

Supply all four bounds together. Geographic axes use coordinate values; longitude input accepts either signed degrees (-180..180) or 0..360, and latitude must be between -90 and 90. The viewer maps the inclusive endpoints to the smallest source-index rectangle containing those coordinate samples. Other axes use their one-dimensional coordinate values when available, and inclusive, zero-based cell indices when no coordinate values are available. Reversed, non-finite, out-of-domain, or non-overlapping bounds produce an error.

Explicit CLI bounds take precedence over a zoom restored from the saved session. Without CLI bounds, the usual restored view is preserved. Use r or the command palette’s Reset zoom action to return to the selected variable’s global view. For curvilinear grids the requested geographic rectangle is approximated by its smallest row/column envelope; the status line reports this. See Derive variables with formulas for the formula language.

Environment reference

Runtime configuration is done with environment variables. Set them before launching ncv.

VariableValuesDefaultPurpose
NCVIEW_THREADSintegermin(CPUs, 8)Parallel rasterization threads (RAYON_NUM_THREADS is also honored). The conservative default avoids hogging HPC head-node resources.
NCVIEW_IMAGE_PROTOCOLkitty, sixel, iterm2, cellsauto-detectedOverride graphics capability detection. Auto-detection identifies iTerm2 from environment hints; Kitty and Sixel are selected only through this override or a positive capability match. An explicit setting is honored as given.
NCVIEW_SCIENTIFIC_RENDERING1 / 01 (locked)Keep nearest-neighbor scientific rendering, or allow interpolation (0).
NCVIEW_IMAGE_FILTERnearest, lanczos3, catmull-rom, triangle, gaussiannearestImage filter when scientific rendering is unlocked.
NCVIEW_CELL_PIXEL_SIZEWxH pixels, e.g. 10x20from the terminalTerminal cell size used to size graphics images and map mouse clicks. Set it when the terminal does not report usable pixel dimensions (common over SSH); known 640x480 placeholders and reports under 4x8 pixels per cell are ignored, and 10x20 is assumed.
NCVIEW_ANONYMOUS_ACCESStruthy (1, true, yes, on, y)autoForce credential-free access for public S3/GCS/Azure objects. Any other value, including 0, leaves the automatic decision in charge rather than forcing signed access. Auto mode uses ambient credentials if present, otherwise a cached metadata-endpoint probe, and selects anonymous access when neither yields credentials.
NCVIEW_LAND_DETAIL110m, 50m, 10m, auto110mCoastline resolution after enabling the b backdrop; auto selects by zoom level.
NCVIEW_UG_INTERMEDIATE_SPACING_DEGdegrees, 0 < x <= 900.25Cell size of the regular latitude/longitude grid that unstructured-grid fields (currently MPAS) are regridded onto. Smaller values sharpen the map but cost more per read.
NCVIEW_COLORMAPSdirectory—Extra directory of .ncmap files for the palette catalog.
NCVIEW_LIB_DIRdirectory—Also searched for colormaps, including share/ncview/colormaps.
NCVIEWBASEdirectory—Also searched for colormaps, including share/ncview/colormaps.
NCVIEW_EXPORT_DIRdirectorycurrent directoryWhere e writes exports.
NCVIEW_EXPORT_BACKGROUNDtransparent, whitetransparentExport canvas background.
NCVIEW_EXPORT_TEXTdark, lightdarkExport text/border color (light for dark slides).
NCVIEW_EXPORT_FONTfont listFira Code, monospaceSVG export font selection (PNG always uses the embedded font).
NCVIEW_SESSION_DIRdirectoryplatform defaultWhere per-dataset session state is stored.

Notes

  • Secrets are never read from arguments; cloud credentials come from ambient provider configuration (AWS_*, GOOGLE_*, AZURE_*).
  • NCVIEW_IMAGE_FILTER and i-cycling only take effect when NCVIEW_SCIENTIFIC_RENDERING=0; the default preserves exact scientific cells.
  • Malformed .ncmap files discovered via any colormap path are ignored at startup rather than causing an error.

Supported formats and environments

Inputs ncv opens

InputFormsNotes
NetCDF-4 (HDF5).nc, .nc4, .hdf5-magic NetCDF-4Local and remote; subgroups appear as qualified names (physics/temperature)
GRIB2.grib, .grib2, .grb, .grb2, GRIB-magic detectionLocal and remote; remote objects use .idx sidecars or bounded range reads
Kerchunk / VirtualiZarr reference manifests.jsonVirtual datasets describing byte ranges; never copies or modifies source data
Remote object locationss3://, gs://, az://, abfs[s]://See Access remote data

Inputs ncv rejects (on purpose)

InputBehavior
NetCDF-3Rejected before terminal entry with an actionable diagnostic
Arbitrary HDF5 (non-NetCDF-4)Rejected with an actionable diagnostic
Large unindexed remote GRIB2Refused rather than silently downloaded in full

Rejection happens before the TUI starts, so your terminal is never left in a modified state.

Platforms

Release archives are published for:

OSArchitecture
Linuxx86_64 (glibc) and x86_64 musl (static, for older distributions)
macOSarm64
Windowsx86_64

Each release ships a SHA256SUMS file. The binary is pure Rust with no native NetCDF/HDF5 runtime dependency.

Terminals and SSH

  • Image protocols: Kitty, Sixel, iTerm2 (auto-detected after terminal entry; overridable with NCVIEW_IMAGE_PROTOCOL).
  • Portable fallback: ncv’s own cell rasterizer — one truecolor background block per terminal cell — always functional, including over OpenSSH and tmux.
  • Explicit NCVIEW_IMAGE_PROTOCOL settings are honored as given on all terminals; the portable cell renderer remains available with NCVIEW_IMAGE_PROTOCOL=cells.
  • No X11 forwarding required.

Data safety

All datasets are opened read-only. Source files are never modified. Missing, fill, NaN, and infinity values are preserved and masked honestly — see Data fidelity.

Library API reference

ncview-rs exposes its internals as a Rust library (ncview-rs) alongside the ncv binary. The full, always-current API documentation is generated from the code’s own rustdoc comments and published with this site under the api/ section.

  • Crate: ncview-rs (MIT OR Apache-2.0)
  • Minimum Rust: 1.90 (edition 2024)
  • Public surface: #![deny(unsafe_code)] — the whole crate is safe Rust

Module map

ModuleResponsibility
dataRead-only dataset and slice abstractions: NetCDF-4/HDF5, GRIB2 (local and remote), coordinates, diff, formula-derived variables (data::formula::FormulaSource), reference manifests, virtual datasets
storageProvider-neutral remote object access: locations (s3://, gs://, az://, abfs[s]://), range cache, typed operations, session state. All network work lives behind this module and its background runtime
renderColor normalization and terminal raster rendering: palettes, land mask, map background, image-protocol selection, viewport-bounded rasterization
uiRatatui view composition: dashboard, canvas, colorbar, sidebar, level bar, timeline, charts, help, popups, layout
eventsTerminal event and session handling: keyboard input, mouse, terminal enter/restore lifecycle
analysisScientific analysis and coordinate-mapping primitives: mapping, projection, time series, equation-editor formula parsing and evaluation (analysis::formula)
appApplication state: view model, generation counters, variable/palette/limits state, decoded working-set bounds
exportFile exporters for the current scientific view (PNG, SVG, JSON sidecar)
errorNcvError — actionable errors carrying file/variable/dimension/capability context

Reading the generated docs

The api/ section of this site is rebuilt automatically whenever the code changes, so signatures, doc comments, and trait implementations always match the source at that commit. It includes:

  • every public type, function, and method with its rustdoc,
  • the NcvError variants and their messages,
  • module-level overviews (the table above comes from them).

For behavior contracts, the narrative pages are the entry point:

Explanation

Understanding-oriented discussion: how ncv works and why it behaves the way it does.

Why the values can be trusted

ncv is a scientific viewer first and a visualization tool second. Its core correctness rule is source-value fidelity: every displayed value, coordinate, limit, axis, and index is traceable to the source dataset, and presentation never silently alters data.

Missing, fill, NaN, and infinity

  • NetCDF _FillValue and missing-value attributes are applied by the data loader; masked cells are never painted as if they were data.
  • Non-finite floating-point values (NaN, +Inf, -Inf) are preserved — they are never coerced to zero, dropped from counting, or averaged into statistics. The status bar’s min/max/mean cover finite values only, and the finite count tells you how much of the slice was real data.
  • The f data mask keeps only values between chosen bounds, but automatic fill/missing masking stays active regardless — masking is additive, never a way to make invalid values look valid.

Coordinates and indices

  • Coordinate variables are read from dataset metadata, including 2-D curvilinear latitude/longitude fields.
  • When a file has no usable coordinate variable, the hover readout falls back to source indices and says so, rather than inventing plausible coordinates. Grouped (subgroup) coordinate fields currently use the same honest fallback while retaining the variable’s data and metadata.
  • Pinned-point time series and plots use the original source indices, so a click always identifies the exact source cell.

Where approximation is allowed — and how it is disclosed

Rendering and projection MAY approximate spatial presentation. The places they do are always labeled:

  1. Curvilinear lat/lon: 2-D coordinate planes are read and used to report each cell’s latitude/longitude, but pixels map to source cells by index, so a cell’s value and readout are always the exact source cell. Nearest-lat/lon projection helpers (ProjectionIndex, projected_lookup) exist in the library but are not yet wired into the display; the g grid-mode toggle records a preference that no renderer consumes yet.
  2. Viewport-bounded aggregation: when a slice is larger than the terminal canvas, source cells are reduced into display bins before color mapping. This bounds memory to the visible area — it changes how densely values are drawn, not their values. Nearest-neighbor is the default so scientific cells stay exact at any zoom; interpolation (NCVIEW_SCIENTIFIC_RENDERING=0 plus a filter) is opt-in and clearly a display choice.

The coastline backdrop (b) is likewise presentation-only: it never changes data values and never replaces a dataset-provided land/sea mask.

Limits and scaling honesty

  • Automatic limits follow the displayed slice (current-scope) or the full unzoomed range (global-scope) — the mode is visible, switchable (z), and both are computed from actual data.
  • Manual limits always win over automatic modes.
  • Log scaling is only applied when meaningful; the scale mode is reported in the UI.

Read-only by construction

Datasets are opened read-only. Reference manifests (Kerchunk/VirtualiZarr) describe byte ranges of the original files; opening one never copies or mutates the source. Exports write new files and leave sources untouched.

How ncv chooses a terminal renderer

The map is a true-color image, but terminals speak different graphics languages. ncv selects the best one automatically — and guarantees a usable view when none exists.

Capability detection, carefully

After entering the terminal session, the viewer settles on one of four renderers — Kitty, Sixel, iTerm2, or the cell fallback. Capability detection is deliberately conservative: querying capabilities over SSH or through multiplexers can hang for seconds while waiting for escape-sequence responses, so ncv avoids the blocking query path. Instead it derives the choice from the observed window size and environment hints. Those hints can only identify iTerm2 automatically; Kitty and Sixel are used when you request them explicitly with NCVIEW_IMAGE_PROTOCOL, and the user can override anything it gets wrong.

The header always reports the active renderer (Kitty truecolor, Sixel truecolor, iTerm2 truecolor, cell fallback, or cells (graphics unavailable) after a protocol encoding failure), so you never have to guess what is actually being used.

The fallback is a first-class mode

If no image protocol is available — plain OpenSSH, tmux with passthrough disabled, an older terminal — ncv renders the map with its own cell rasterizer: one truecolor background block per terminal cell. Everything still works: hover readouts, clicking, zoom, export. The project rule is capability enhancement must never become capability lockout: the fanciest protocol is never required for any workflow.

Explicit protocol selection

NCVIEW_IMAGE_PROTOCOL is honored as given, even when the terminal may not support that protocol correctly. To force the portable renderer, set NCVIEW_IMAGE_PROTOCOL=cells.

  • iTerm2 uses its own protocol rather than Kitty/Sixel.
  • tmux and other multiplexers may swallow capability queries; set NCVIEW_IMAGE_PROTOCOL explicitly to bypass capability detection for the protocol choice.

Scaling choices

By default the image is nearest-neighbor upsampled so a zoomed scientific cell remains one crisp cell — the pixels you see correspond to source values. Interpolation filters (Lanczos, Catmull-Rom, triangle, Gaussian) are available only after unlocking scientific rendering (NCVIEW_SCIENTIFIC_RENDERING=0), making it explicit when a display is smoothing data rather than showing it.

How remote access works without downloading files

ncv opens S3, GCS, and Azure Blob objects by byte-range reading — it fetches only the metadata and data slices you actually look at.

Range reads, not downloads

A NetCDF-4/HDF5 file stores its structure in headers and its data in chunks scattered through the file. ncv reads:

  1. a bounded metadata window (growing only to 64 MiB) to find variable definitions, chunk indexes, and coordinates, then
  2. targeted range requests for the compressed chunks inside your view.

Objects larger than 64 MiB are never materialized in full. Objects up to 64 MiB use a simpler bounded fallback reader that loads the whole (small) object into memory in one range read. Unsupported HDF5 layouts and non-unit-stride contiguous hyperslabs fail explicitly with an actionable diagnostic instead of showing a partial or wrong view — the same fidelity rule as local files.

GRIB2 over the network follows the same principle with HEAD/range requests, optionally guided by a colocated NOAA-style .idx sidecar that maps records to byte ranges. A large unindexed GRIB2 object is refused rather than silently downloaded in full. Reference manifests (ncv manifest ...) are the portable alternative: they record the byte ranges as JSON so any Kerchunk-compatible tool gets the same map.

Why public buckets used to hang (and the metadata probe)

Cloud SDKs normally look for credentials in ambient configuration, then ask the instance metadata service (a link-local endpoint, e.g. 169.254.169.254) for a role token. On a laptop that endpoint does not exist — and without care, every object request retries the token lookup for minutes, making public buckets appear broken.

ncv now probes the metadata endpoint once per process (a cached TCP connect with an 800 ms budget for each candidate endpoint; custom endpoints set through AWS_EC2_METADATA_SERVICE_ENDPOINT, GCE_METADATA_HOST or GCE_METADATA_IP, MSI_ENDPOINT, or IDENTITY_ENDPOINT are probed too). When there are no ambient credentials and no reachable metadata service, it uses anonymous, credential-free access — the correct mode for public research buckets such as s3://noaa-gefs-pds. Provider-internal retries are bounded (three retries, ten seconds total) and each ncv range request adds its own bound of three attempts with a 30-second per-request timeout and 100 ms to 2 s exponential backoff, so a genuinely misconfigured private bucket fails fast with a clear error.

Force the behavior with NCVIEW_ANONYMOUS_ACCESS=1 to always use anonymous access. Any other value, including 0, leaves the automatic decision (ambient credentials, then the metadata probe) in charge — it does not force signed access. The probe and open happen on a background loader thread, so the terminal UI starts before the network does any work.

Credentials and safety

  • Credentials come only from ambient provider configuration (AWS_*, GOOGLE_*, AZURE_*); secrets are never accepted in command-line arguments and never persisted.
  • Remote sources are read-only, exactly like local ones.
sequenceDiagram
    autonumber
    participant UI as Terminal UI
    participant Loader as Background loader
    participant Store as Object store
    participant Cloud as S3 or GCS or Azure
    UI->>Loader: open s3 bucket key
    Loader->>Store: build provider store
    Store->>Store: decide anonymous or signed
    Loader->>Store: HEAD object
    Store->>Cloud: bounded HEAD request
    Cloud-->>Store: object size and etag
    Loader->>Store: read magic bytes range
    Store->>Cloud: range read
    Cloud-->>Store: first bytes
    Loader->>Store: read metadata window
    Store->>Cloud: bounded range reads
    Cloud-->>Store: header bytes plus chunk index
    UI->>Loader: request slice for current view
    Loader->>Store: read visible chunk ranges
    Store->>Cloud: bounded range reads
    Cloud-->>Store: compressed chunks
    Loader-->>UI: decoded slice with source values intact