A modern, ncview-like visual browser for netCDF files, written in C++ for the X Window System. It renders with Cairo/Pango for anti-aliased text and smooth, perceptually-uniform colormaps, reads data through the netCDF C library, and uses udunits2 for unit formatting and calendar/time-axis decoding.
It is a self-contained native X11 application — it relies only on the X server (Xlib), with no GTK/Qt/Motif toolkit.
- Sidebar listing every displayable (≥1-D numeric) variable with its long name
and units. Supporting variables (cell bounds such as
time_bnds, auxiliary coordinates, grid mappings, and coordinate variables such asdepth/lev) are detected, dimmed, and sorted to the end; the initial selection is always a real data field. The list scrolls (mouse wheel or a draggable scrollbar) and a hover tooltip shows the full name and units when an entry is truncated. - Reads any format the netCDF C library exposes: classic/64-bit, netCDF-4/HDF5,
and — when the library is built with NCzarr — Zarr stores (local
.zarrdirectories and remote/S3 URLs). See Usage. - 2-D field rendering of the last two dimensions, aspect-ratio preserved.
- 1-D variables are shown as a line plot filling the main window (the same chart as the time-series window), with a calendar/numeric x-axis.
- Zoom & pan: drag a rectangle over the plot to zoom into that region (the coastline overlay and hover readout follow); right-click to reset. When zoomed, pan with the scrollbars along the plot edges, or with the mouse wheel (vertical, Shift+wheel for horizontal). The zoom persists across animation frames.
- Sliders for every extra dimension (e.g. level); the time axis is detected via udunits and labelled with calendar dates instead of raw numbers. Playback controls (first / previous / play / next) sit to the left of the time slider.
- Animation along the time (or first extra) dimension: play/pause, step, speed.
- Built-in colormaps: sequential perceptual (viridis, inferno, plasma, magma,
cividis, thermal, ocean), white/light-centred diverging ones for anomalies
(coolwarm, RdYlBu, BrBG, PuOr, seismic), and grayscale. Chosen from a
dropdown with gradient swatches (the colormap button), or cycled with
c; the reverse button above the colour scale flips any palette's direction. - Colorbar with tick labels. The value range starts fixed, derived from a
quick global min/max scan of the variable (sub-sampled for large files) so the
colour scale is stable across time steps. The min and max are editable: click
a colorbar bound field and type a new value (Enter applies, Esc cancels). The
fixed button above the colour scale toggles between this fixed global
range and per-slice auto. The symmetric button (below it) makes the scale
symmetric around zero —
[-M, +M]withM = max(|min|, |max|)— which centres diverging fields (e.g. anomalies) on zero. - Missing/fill values are rendered white.
- The window opens at a default size whose plot canvas matches a global longitude/latitude grid (360 × 180, a 2:1 map); it is freely resizable.
- Coastlines overlay (Natural Earth 110m) for longitude/latitude fields,
auto-detected from coordinate units and enabled by default; handles 0–360°
and −180–180° longitude conventions. Toggle with the coast button or
l. - Country-borders overlay (Natural Earth 110m), drawn as dashed lines for
longitude/latitude fields; off by default. Toggle with the borders button or
b. - Map projections for longitude/latitude fields: equirectangular (default),
Mollweide, Hammer and Gall-Peters (equal-area), Mercator, and Robinson. Cycle
with the projection button or
p; the field is reprojected and the coast/border overlays follow. Zoom/hover apply in the equirectangular view. - Pointer hover readout: data value (with its unit) and the coordinate-variable position, plus a crosshair.
- Time-series window: click a grid cell in the plot to open a line chart of that cell's series along the time axis, at the currently selected vertical level (and other fixed dimensions). The x-axis uses udunits calendar dates, the current frame is highlighted, and the unit is shown in the title. For large (high-resolution / vertically resolved) variables the extraction can be slow, so a "please wait" popup is shown while it runs.
- Metadata window: a second, scrollable window listing the file's dimensions, global attributes, and every variable with its full attribute set (an ncdump-style header), colour-coded and monospaced. The text is selectable with the mouse and copied to the PRIMARY and CLIPBOARD selections (middle-click paste or Ctrl+V into other applications).
- Uniformly sized toolbar buttons, each with a hover tooltip describing its action. The toolbar file name is ellipsized when it does not fit; hovering over a truncated name shows the complete file name (without the folder path).
- Units are shown verbatim as written in the file's
unitsattribute (factor order preserved, e.g.kg m-2). udunits is still used for time-axis decoding for standard/gregorian/proleptic calendars, with arithmetic fallbacks for the CF360_day,noleap/365_dayandall_leap/366_daycalendars. - A terminal notice is printed while the global min/max range of a large variable is being scanned (this runs before the window is mapped at start-up).
- CF packing is unpacked on read: stored values are converted to physical units
via
scale_factor/add_offset, so the field, the value range and the colour scale are all in physical units (fill values are detected before unpacking). _FillValue/missing_valueare rendered white.
| Action | Key / mouse |
|---|---|
| Play / pause | Space or the ▶ button |
| First time step | Home or the ⏮ button |
| Step time | ← / → or the ◀ / ▶ buttons |
| Change variable | ↑ / ↓ or click in the sidebar |
| Scroll variable list | wheel over the sidebar or drag its scrollbar |
| Choose colormap | the colormap button (dropdown); c cycles |
| Flip Y (N↕S) | f or the flip button |
| Auto/fixed range | a or the fixed button (above the colour scale) |
| Symmetric scale | s or the symmetric button |
| Reverse colours | r or the reverse button |
| Edit min / max | click a colorbar bound field, type, Enter |
| Coastlines overlay | l or the coast button (geographic data) |
| Country borders | b or the borders button (geographic data) |
| Map projection | p or the projection button (geographic data) |
| Metadata window | m / i or the ⓘ metadata button |
| Select metadata text | drag in the metadata window (copies to clipboard) |
| Long attributes | soft-wrap to the window width; resize to reflow |
| Animation speed | + / - or scroll wheel |
| Move a dimension | drag the slider |
| Inspect a cell | hover the plot |
| Cell time series | click a cell in the plot |
| Zoom into region | drag a rectangle over the plot |
| Pan (when zoomed) | wheel / Shift+wheel, or drag the plot scrollbars |
| Reset zoom | right-click the plot |
| Quit | q or Esc |
A C++17 compiler, CMake ≥ 3.16, and pkg-config are needed, plus the
development (-dev / -devel) packages for the libraries below. The GUI
libraries are located through pkg-config; netCDF and udunits2 are linked
directly.
| Library | pkg-config module |
Purpose |
|---|---|---|
| X11 (Xlib) | x11 |
native window + event loop |
| Cairo | cairo |
2-D rendering |
| Cairo XLib surface | cairo-xlib |
drawing onto the X window |
| Pango + Cairo | pangocairo |
anti-aliased text layout |
| libxml2 | libxml-2.0 |
fontconfig dependency (resolved explicitly) |
| netCDF C library | (linked as netcdf) |
reading netCDF files |
| udunits2 | (linked as udunits2) |
unit formatting, calendar/time decoding |
Install them with your package manager:
# Debian / Ubuntu
sudo apt install build-essential cmake pkg-config \
libx11-dev libcairo2-dev libpango1.0-dev libxml2-dev \
libnetcdf-dev libudunits2-dev
# Fedora / RHEL
sudo dnf install gcc-c++ cmake pkgconf-pkg-config \
libX11-devel cairo-devel pango-devel libxml2-devel \
netcdf-devel udunits2-devel
# macOS (Homebrew; X11 via XQuartz)
brew install cmake pkg-config cairo pango libxml2 netcdf udunits(libcairo2-dev / cairo-devel provides both the cairo and cairo-xlib
modules; libpango1.0-dev / pango-devel provides pangocairo.)
If netCDF and udunits2 are installed under a non-standard prefix (the common
case on HPC systems), point the build at it with -DHPC_PREFIX=/path/to/prefix;
this is the HPC_PREFIX cache variable in CMakeLists.txt.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -jThe runtime library path and udunits XML location are baked into the binary via rpath / a built-in default, so no environment setup is normally required. If the udunits database is moved, point to it with:
export UDUNITS2_XML_PATH="$PREFIX/share/udunits/udunits2.xml"where $PREFIX is your netCDF/udunits install prefix.
./build/ncvista FILE.nc
./build/ncvista --version # print the version and exitIf the netCDF library was built with NCzarr support (nc-config --has-nczarr
reports yes), Zarr datasets can be opened too:
./build/ncvista data.zarr # local store, by path
./build/ncvista 'file:///abs/path/data.zarr#mode=nczarr,file' # explicit URL
./build/ncvista 's3://bucket/key#mode=nczarr,s3' # remote (needs libcurl)A plain .zarr directory path is automatically opened as an NCzarr file
store; the full file://…#mode=nczarr,… URL form is also accepted, as is any
other URL the library understands (e.g. s3://, zip).
A test file generator is included:
PREFIX=/path/to/prefix # your netCDF/udunits install prefix
gcc gen_test.c -I"$PREFIX/include" -L"$PREFIX/lib" \
-Wl,-rpath,"$PREFIX/lib" -lnetcdf -lm -o gen_test
./gen_test # writes sample.nc
./build/ncvista sample.ncThe overlays read coastlines.bin and borders.bin, compact little-endian
files of (lon, lat) polylines shipped with the project (Natural Earth 110m
coastline and admin-0 boundary lines, derived from public-domain data). At
runtime each is located via, in order: an environment override ($NCVISTA_COAST
/ $NCVISTA_BORDERS), next to the executable, <prefix>/share/ncvista/, then
the build-time source path.
To regenerate them from Natural Earth shapefiles (the generator uses cartopy or pyshp if present, otherwise a built-in standard-library reader):
python3 scripts/make_overlays.py ne_110m_coastline.shp coastlines.bin
python3 scripts/make_overlays.py ne_110m_admin_0_boundary_lines_land.shp borders.bin| File | Responsibility |
|---|---|
src/ncfile.* |
netCDF wrapper: dims, variables, coords, 2-D slices |
src/units.* |
udunits2: unit formatting, time-axis decoding |
src/colormap.* |
built-in perceptual colormaps |
src/coastline.* |
coastline data loader + overlay path resolution |
src/app.cpp |
Xlib + Cairo immediate-mode UI and event loop |
- The two plotted axes are identified by coordinate metadata — the CF
axisattribute (X/Y), thenstandard_name, then units, then the dimension name (all case-insensitive). A longitude/latitude pair is used wherever it appears in the dimension list, so permuted orders such as(lat, lon, time)or(lon, lat, time)are handled (the field is transposed to north-up row-major as needed). When no geographic pair is recognised, the last two non-time dimensions are used as Y, X, so a time axis is never plotted as a map axis. Curvilinear/unstructured grids are drawn in index space. - Time decoding for the standard calendar uses udunits' conversion to a
reference epoch and POSIX
gmtime(proleptic Gregorian, no leap seconds), which is accurate for typical climate-data date ranges.
Released under the MIT License.
The bundled coastlines.bin and borders.bin are derived from
Natural Earth vector data, which is in the
public domain. ncvista links the netCDF C library
and udunits2 (BSD-style licenses) and Cairo / Pango (LGPL/MPL); these are not
distributed with the source.
