Open NetCDF files and OPeNDAP datasets far larger than memory, instantly.
Maps, vertical sections and a 3D globe for ocean and climate model outputs.
The Gulf Stream and a warm-core ring on 9 October 2026, at 1 km, streamed from the 21 TB NASA MUR sea surface temperature dataset. Grid Viewer transferred 17.5 MB to draw it.
Ocean and climate models write grids that do not fit in memory: a global 1/12° model writes billions of values per day, and satellite products such as MUR SST hold tens of terabytes. Most viewers load a whole variable, or at least a whole level, before they draw anything.
Grid Viewer never reads more grid points than your screen has pixels. A world map of a 36 000 × 18 000 grid on a 1600-pixel-wide window reads one point in twenty in each direction. Zoom in, and the visible window shrinks, the stride drops, and the missing detail is read, down to every single point. Pan back out, and it comes from the cache.
| What is on screen | Grid | Read by Grid Viewer | Whole level | Memory |
|---|---|---|---|---|
| World map, MUR SST over OPeNDAP | 36 000 × 17 999 | 6.2 MB (stride 20) | 2.41 GB | — |
| Gulf Stream at full 1 km resolution | 1 800 × 1 000 window | 17.5 MB (stride 1) | 2.41 GB | — |
| World map, local 1/24° NetCDF file | 8 640 × 4 320 | 5.7 MB in 0.2 s (stride 5) | 142 MB in 1.4 s | 170 MB instead of 1.3 GB |
Local figures: gridviewer render on a 600 MB NetCDF-3 file already in the page cache, whole
process included. The point is not the absolute numbers but that they do not grow with the file.
This was the idea behind the original Grid Viewer, written in 2006 at Mercator Océan to browse NEMO/OPA model outputs that were already too big for the workstations of the time. Twenty years later it is rewritten from scratch for Java 25, with the same trick at its heart.
- Huge files, instantly: only the header is read on opening; values are read one strided window at a time, on a dedicated I/O thread, and stale requests are dropped while you zoom.
- Local and remote: NetCDF-3, NetCDF-4/HDF5 and OPeNDAP URLs (THREDDS, ERDDAP, Hyrax). Remotely, the server does the subsetting, so only the points on screen cross the network.
- Map view with smooth zoom (wheel, pinch, box zoom), pan, longitude/latitude graticule and a read-out of the value, indices and coordinates under the pointer.
- Vertical sections along any row or column, by model level or at true depth.
- 3D globe that the current level wraps around, slowly turning, as the 2006 Java3D view did.
- Regular and curvilinear grids: CF coordinates, 2D
nav_lon/nav_lat(NEMO/ORCA), descending latitudes, fill values,valid_range, packed data, and NEMO's "land is 0". - Time and depth navigation with sliders, keyboard shortcuts and a play button for time series. Dates are decoded from CF units, climatologies are recognised.
- 29 colour maps: cmocean (made for oceanography), viridis/cividis/magma/turbo, and the 13 original 2006 palettes. The map is chosen from the variable (thermal for temperature, haline for salinity, balance centred on zero for anomalies and velocities...), the range is set automatically from what is on screen.
- Overlays from the 2006 version: point lists and NEMO
layout.datMPI domain decompositions. - Command line:
gridviewer infoto list variables,gridviewer renderto draw PNG maps from scripts, with the same strided reads. - Easy to install: native packages with their own Java runtime for Linux, Windows and macOS.
Every package ships its own Java runtime: nothing else to install. All of them are attached to each GitHub release; the commands below always fetch the latest one.
curl -LO https://github.com/laborima/gridviewer/releases/latest/download/gridviewer_amd64.deb
sudo apt install ./gridviewer_amd64.debsudo dnf install https://github.com/laborima/gridviewer/releases/latest/download/gridviewer.x86_64.rpm
# openSUSE: sudo zypper install https://github.com/laborima/gridviewer/releases/latest/download/gridviewer.x86_64.rpmcurl -LO https://github.com/laborima/gridviewer/releases/latest/download/gridviewer_amd64.snap
sudo snap install --dangerous ./gridviewer_amd64.snap--dangerous is needed because the snap comes from GitHub rather than the Snap Store.
curl -LO https://github.com/laborima/gridviewer/releases/latest/download/GridViewer-x86_64.AppImage
chmod +x GridViewer-x86_64.AppImage
./GridViewer-x86_64.AppImagecurl -L https://github.com/laborima/gridviewer/releases/latest/download/gridviewer-linux-x64.tar.gz | tar xz
./gridviewer-*-linux-x64/bin/gridviewerDownload and run
GridViewer-windows-x64.msi,
or unzip gridviewer-windows-x64.zip
anywhere and run Grid Viewer.exe. Use gridviewer-cli.exe for the command line.
Download the disk image for Apple silicon or Intel, open it and drag Grid Viewer to Applications. The app is not notarised yet: the first time, right-click it and choose Open.
The deb, rpm and snap add Grid Viewer to the application menu and open .nc files on
double-click. Each release also lists the files with their version number and a
SHA256SUMS.txt to check the downloads.
Open a file from the menu, drop it on the window, or pass it on the command line:
gridviewer ocean_model_output.nc
gridviewer https://coastwatch.pfeg.noaa.gov/erddap/griddap/jplMURSST41 --var analysed_sst --time -1No NetCDF file at hand? These public files are small and quick to download:
# World Ocean Atlas 2023, annual temperature, 1°, 102 depth levels (81 MB, NOAA)
curl -O https://www.ncei.noaa.gov/data/oceans/woa/WOA23/DATA/temperature/netcdf/decav/1.00/woa23_decav_t00_01.nc
# NOAA OISST, one day of sea surface temperature and anomaly, 0.25° (1.5 MB)
curl -O https://www.ncei.noaa.gov/data/sea-surface-temperature-optimum-interpolation/v2.1/access/avhrr/202409/oisst-avhrr-v02r01.20240915.nc| Action | Map | Globe |
|---|---|---|
| Zoom | wheel, pinch, + -, double-click (Alt: out) |
wheel |
| Move | drag, arrow keys | drag to rotate |
| Zoom to a box | Shift + drag | |
| Fit | 0, Ctrl+0 |
|
| Vertical section | right-click on the map | |
| Level up / down | Page Up / Page Down | Page Up / Page Down |
| Previous / next time step | Alt+← / Alt+→ | Alt+← / Alt+→ |
| Colour range from what is on screen | Ctrl+R | Ctrl+R |
| Export the view as PNG | Ctrl+E | Ctrl+E |
$ gridviewer info woa23_decav_t00_01.nc
woa23_decav_t00_01.nc
Hierarchical Data Format, version 5, 81.2 MB on disk
t_an Objectively analyzed mean fields for sea_water_temperature at standard depth levels. [degrees_celsius]
time=1 × depth=102 × lat=180 × lon=360, 25.2 MB as floats
102 levels: 0 m .. 5500 m
regular lon/lat grid
...
$ gridviewer render https://coastwatch.pfeg.noaa.gov/erddap/griddap/jplMURSST41 \
-v analysed_sst -t -1 -W 1600 -o world.png
analysed_sst: read 1,340,703 of 647,964,000 points (stride 22), 5.1 MB instead of 2.41 GB, in 16165 ms -> world.pnggridviewer render --help lists the options: level, time step, grid window, colour map, range,
size, and --full to read every point for comparison. gridviewer palettes lists the colour maps.
screen pixels ──► Stride ──► strided read ──► Slice ──► colour map ──► image
│ (netCDF-Java, │
zoom / pan ───────┘ one I/O thread) └──► LRU cache (¼ of the heap)
Stridepicks, for the visible window, the largest step that still gives one sample per device pixel. AVariable.readwith that step returns only those samples, whatever the file format or transport.- The map keeps two layers: a base covering the whole grid at a coarse stride, read once per level and time step, and a detail layer covering the view plus a margin, re-read 60 ms after the view stops moving. Meanwhile the previous pixels are stretched, so zooming always feels immediate.
- All netCDF reads go through a single I/O thread (netCDF-Java files are not thread safe).
LatestOnlykeeps just the newest pending request per view, so a fast zoom or a dragged slider never queues up stale reads. - Slices are cached by request in an LRU bounded to a quarter of the heap, so flipping back to a previous level, time step or zoom costs nothing.
The code is small and documented: data/ reads grids, render/ turns values into pixels,
ui/ is the JavaFX application, cli/ the command line.
You need JDK 25. Maven is fetched by the wrapper.
./mvnw verify # build and run the tests
java -jar target/gridviewer.jar # run (dependencies are in target/lib)
packaging/package.sh archive deb rpm # self-contained packages in dist/ (rpm needs rpmbuild)
packaging/appimage.sh # AppImage, from the archive
packaging/snap.sh # snap, from the archive (needs snapcraft)On Windows run packaging/package.sh archive msi from Git Bash (WiX needed), on macOS
packaging/package.sh archive dmg. Pushing a v* tag builds every package on GitHub Actions and
publishes them as a release.
The README screenshots are reproducible: the viewer accepts --window, --section, --tab,
--palette, --range and --screenshot FILE.png, for instance
java -jar target/gridviewer.jar woa23_decav_s00_01.nc --var s_an --tab section \
--section col:150 --range 33.8:37.6 --size 1600x1000 --screenshot section.pngGrid Viewer was written in 2005–2006 at Mercator Océan, on spare time, in Java 1.5 with SWT,
NetCDF-Java 2.2 and Java3D. It let oceanographers browse NEMO/OPA outputs on any workstation and
was used long after. The original sources are kept in legacy/ and tagged
legacy-2006.
Version 2 (2026) is a complete rewrite on Java 25, JavaFX 25 and netCDF-Java 5, keeping what made
the original useful: the strided reads, the vertical sections, the 2006 palettes and default
ranges, point lists, NEMO layout.dat overlays, and the turning globe.
- netCDF-Java by Unidata (BSD-3-Clause) reads every format and protocol.
- OpenJFX (GPL v2 with Classpath Exception) draws the interface.
- Colour maps: cmocean by Kristen Thyng et al. (MIT), and viridis, cividis, magma, turbo, RdBu and coolwarm from matplotlib.
- Data in the screenshots: MUR SST v4.1 (NASA JPL, served by NOAA CoastWatch ERDDAP), World Ocean Atlas 2023 and OISST v2.1 (NOAA NCEI).
Apache License 2.0. Copyright 2006–2026 Matthieu Laborie.






