NISAR OPERA frame viewer¶
An interactive map of the NISAR OPERA frames over North America — the same
frame_idx keys used by the consistent-mode, blackout, and reference-date
databases. Pan and zoom to inspect track/frame footprints and their attributes.
The viewer is a self-contained MapLibre page generated by
scripts/generate_scope_viewer.py;
the embedded copy below is served as a static asset with these docs.
Refreshed every Monday
The
Update frame viewer
workflow re-queries CMR for the GSLC archive each Monday at 06:00 UTC,
rebuilds the consistent-mode database from it, re-renders this page, and
republishes the site. The catalog behind a given run is attached to it as a
workflow artifact. Blackout and reference dates are climatological rather
than weekly, so they are not rebuilt: the blackout dates come from
catalog/opera-nisar-disp-blackout-dates.json,
derived from the snow analysis in scripts/snow-analysis/ with
nisar-db create-blackout-dates, and the reference dates from the latest
release.
The sidebar header carries the CMR queried timestamp of the catalog the
page was built from, so a scheduled run and a manual workflow_dispatch
both show up there.
Each run queries the entire GSLC archive (--max-results 0), not a
capped slice.
It opens on the globe projection (the control at the bottom right switches to
Mercator), with frames coloured by GSLC count in CMR and the science modes
(2005, 4005) and polarizations (DHDH, QPDH) preselected under
GSLC Mode / Polarization. The count colourings (GSLC acquisitions, duplicate
granules, distinct modes, GUNW interferograms) follow those chips and the date
range of GSLC Acquisitions Over Time: drag across its bars, or type the
dates, and every frame is recounted over just that window. The numeric ramps fit
the frames currently shown.
Frame Color / Opacity has two tabs, the same as the map's colour panel. Color by lists the colourings grouped into counts, mode / coverage, planning, flags and quality (QA), each with a preview of its colours. Style holds fill and outline opacity and the colormap: pick one of 31, in folding groups (closed at first; each header names the current colormap) of perceptual (Viridis, Turbo, Batlow, ...), single hue (Blues, Greens, ...), multi hue (YlOrRd, YlGnBu, ...) and diverging (RdBu, Vik, Roma, ...), invert it, or fix its min / max; an empty range, or Auto, fits the frames shown again. Every swatch of a categorical legend is a colour picker — click one to recolour that category. Hide frames with no value removes the frames the current colouring has nothing for: a category of none, not collected or no GUNW, a QA metric not read yet, or no acquisitions / interferograms / modes at all (zero duplicates or zero blackout months are values, and stay). It filters like the other filters, so the counts and charts follow, and it follows the colouring when that changes. Reset all to default puts colours, colormaps, ranges and opacities back, and shows every frame again.
Clicking a frame opens the frame panel; drag its bottom-right corner to resize it, or use ⤢ to widen it (the map pans to keep it on screen). Its other parts: Show granules expands the granule list, which can be filtered to ascending or descending passes; Export CSV downloads that frame's granules; and Show plot charts observation mode against acquisition date, drawing ascending acquisitions as circles and descending as diamonds. The plot window resizes from its corner, and ⤢ fills the screen; the chart redraws to the new size.
The (i) button above the globe toggle turns on hover summaries: with it on,
pointing at a frame pops up its summary, which stays until you move on or close
it with its x. GSLC Acquisitions Over Time, at the top of the sidebar,
counts granules by acquisition date across the frames currently shown — binning
to weeks or months as the span grows. Its date range (dragged on the bars or
typed) also sets the window the frame colours count over; All clears it.
When the viewer is built with a GUNW catalog, a GSLC / GUNW switch sits at the top left. GUNW colours the frames by interferogram count and turns the hover summary, popup, CSV export and Show plot over to the frame's interferograms: the plot draws each pair as a segment from reference to secondary date, raised by its temporal baseline, over the frame's blackout windows. When the pairs do not form one connected network, the subtitle says so in red, spans no pair bridges are shaded red, and pairs cut off from the main network get a red halo. Color frames by → GUNW network paints every frame by the same test: connected, disconnected, or no GUNW, so broken networks can be found on the map without opening each plot. The over-time chart counts interferograms by secondary date, and the Mode / Polarization chips list GUNW modes and polarizations; each product keeps its own chip selection.
Pass direction sits in the top-left map controls; basemaps (light, dark, Esri satellite, Google hybrid as Satellite-H) and the Frame popup switch in the top-right; the light/dark theme switch is beside the viewer title. The antenna button under the volcanoes, bottom right, shows the Nevada Geodetic Laboratory GPS sites, off by default; clicking a site opens its position time series (and never the frame panel underneath it).
OPERA switch. The stacked-layers icon beside the viewer title, on by default, carries the DISP planning features: the rainy / snow blackouts (map layer, colourings, popup month strip and the grey bands in Show plot), Blackout by Month, the rollout regions (map layer, sidebar section, filter and colouring), the consistent mode with its Consistent Mode Summary, and the reference resets. Turned off, all of these leave the page, and the GPS layer widens from North America to the whole network.
Play and full screen. Under the Frame popup switch, the play button slowly spins the globe; a second click stops it, as does grabbing the map. Double-click it (long-press on a phone) for its options: step through the cycles (the cycle filter) or through time (the date range, in windows of a chosen number of days), one step at a time or cumulatively, at a chosen speed, with any Color frames by colouring. A caption over the map names the step and its frames; stopping restores the cycle filter and the date range. The button beside it fills the screen with the map alone; Esc brings the sidebar and the controls back. The third, a moon with stars, sets what shows behind the globe: the theme's colour, white, black, or space (a starfield with the atmosphere's glow).
Links and the API. The page reads its state from the URL, so a link can
open it on a product, filters, colouring, background and play mode: for example
?product=gunw&cycle=20-25&sky=space&play=spin. The REST API builds
such links (/api/v1/viewer/link) and answers the same queries from code; the
MCP server gives them to AI assistants.
Per-granule flags. When the viewer is built with --granule-flags, six
Color frames by options paint each frame by a flag read from every product's
HDF5 metadata. The flags are joint observation, full frame, orbit type, RFI
mitigation applied, mixed mode and dithered. A frame reads all, some or
none of its acquisitions under the current mode / polarization chips; orbit
type shows its value, or mixed. Show flags in the plot window adds one lane
per flag under the GSLC timeline and the GUNW pair plot, and the hover tooltip
lists every flag of the granule or pair. scripts/collect_granule_qa.py
--flags-output reads the flags from each product's small QA_STATS.h5 (an
Earthdata login in ~/.netrc), with the orbit type from CMR, into
catalog/granule_flags.json.gz; the weekly viewer build reads only the
granules published since the last run. A GUNW's orbit type is its reference
acquisition's, the one CMR records; pairs read from the product before carry
both as reference/secondary (e.g. MOE/FOE). Joint observation, full frame and
orbit type are also in every granule's CMR record, and RFI mitigation is the
same for every granule of a product type and release, so a local rebuild shows
those four for every granule; mixed mode and dithering wait for the download
and read not read until then.
Where each flag, QA metric and frame value comes from is listed in Viewer data sources.
QA metrics. When the viewer is built with --granule-qa, the
Quality (QA) group of Color frames by paints each frame by a metric from
every product's QA_STATS.h5. For GUNW the metrics are:
- the coherence median and mean;
- the valid unwrapped share (pixels in a non-zero connected component), as a percentage of the data area rather than of the whole grid;
- the share of the largest connected component;
- the number of connected components;
- the ionosphere screen's mean, median and spread, and its mean uncertainty;
- the pair's RFI likelihood, the larger of its two acquisitions'.
For GSLC it is the RFI likelihood alone.
A frame's value summarises the granules or pairs that pass the chips and the date range, the same way the counts do. The Style tab chooses the statistic: the median, the worst value (the 10th or 90th percentile, whichever direction is bad), or the % bad past a threshold you can edit. Frames with nothing read yet are grey.
Means, medians and spreads are computed from the stored histograms. The QA software's own means read near zero for some granules whose histograms are fine.
The RFI likelihood is documented as 0-1, but most granules report far larger values, up to about 1e31, so it is coloured on a log10 scale, and "bad" means above 1. The ionosphere mean carries a different arbitrary offset in each pair. Its spread compares better across pairs.
In the plot window, Show QA adds one lane per metric under the timeline or pair plot. Values are coloured from dark (worse) to bright (better), and a red mark flags a value past its threshold. Colour pairs recolours the GUNW segments by one metric, so poor pairs stand out in the network. The tooltips, the frame popup's QA line and the CSV export carry the values.
scripts/collect_granule_qa.py downloads the QA files into
catalog/granule_qa.json.gz, 48 at a time; with --flags-output it also fills
the flag cache from the same files. The weekly build reads only new granules, and a
granule withdrawn from the archive is cached as empty.
Browse and QA images. Each row in the granule or interferogram list has a browse button, and so does each point in the plot (click it). The button opens a card with the product's public browse image: the unwrapped phase of a GUNW, the backscatter of a GSLC.
Browse images in the frame popup lays out a strip of thumbnails for the granules or pairs that pass the filters. Each thumbnail's border is coloured by a QA metric.
The wrapped phase, coherence, connected components and ionosphere screen are
drawn only in each product's QA report, which needs an Earthdata login that a
web page cannot send. scripts/qa_browse_server.py runs on your own machine
(127.0.0.1:8797, with your login in ~/.netrc). On request it downloads a
report (about 400 kB), extracts its images and caches them. It also reads the
grid corners that place any image on the map.
Start it from a checkout of this repository with pixi:
Then open http://127.0.0.1:8797/. The first run installs the environment.
Extra arguments pass through to the helper, e.g.
pixi run nisar_db-ui --port 8800 or --viewer-html <page> to serve another
page. Its cache stays in .qa_helper_cache/ in the checkout.
The helper uses the
urs.earthdata.nasa.gov entry of ~/.netrc (or $NETRC). Without one, the
key icon next to the theme switch logs it in instead. The page sends the
username and password only to the helper on 127.0.0.1. The helper checks them
with Earthdata, keeps them in memory until it stops, and sends them only to
Earthdata's login host. The page never stores the password.
The key's dot shows the helper's state: green when it is connected with a
login, yellow when it is connected without one, grey when the page cannot
reach it. Its panel says where the login comes from. On start the helper also
prints Earthdata login: found in ~/.netrc (or that it found none), and
curl http://127.0.0.1:8797/health reports it as "auth": "netrc".
Open the viewer from the helper. The helper also serves the viewer at
http://127.0.0.1:8797/. Opened there, the page and the helper share one
address, so the browser has nothing to block. From the published page, Chrome
asks before a public site may reach a program on your computer ("local network
access"), and may refuse it. Allow it from the lock icon's site settings, or
use the helper's address instead. When the browser runs on another computer
than the helper (a laptop viewing a server), forward the port first, e.g.
ssh -L 8797:127.0.0.1:8797 <server> (VS Code's port forwarding does the same),
and open http://127.0.0.1:8797/ on the laptop. A
web page cannot send an Earthdata login to ASF itself, because ASF's download
endpoint refuses that cross-origin request, so the login has to sit with the
helper.
While the helper runs, the card gains a tab for each layer, the strip can show any of them, and on map lays the image over its frame with an opacity slider. The first request for a pair takes a few seconds, and later ones come from the cache. Without the helper the card shows the public image and the command to start it.
The published page reaches the helper from Chrome, Edge and Firefox; Chrome may first ask to allow access to devices on your local network. Safari and phones see the public images only.
Search and rebuild (local). On a page the helper serves, a magnifier sits next to the key. The first click opens its choices, and a second click (or Search & rebuild) starts a build:
| Scope | What it covers | Build time | Page size |
|---|---|---|---|
| OPERA North America (default) | the published page's 1,295 frames, rebuilt from a fresh CMR search | about a minute | similar to the published page |
| Globe | every frame of the NISAR TrackFrame database, about 30,000 | about 5 minutes, ~10 GB of memory | about 70 MB, 10-20 s to draw |
| Screen view | the frames in the map's current view | seconds | small |
Land only leaves the frames with no land out of the page, and their
granules out of any collection: about half the globe's frames are open ocean.
Two boxes in the same panel also collect what the caches miss: granule
flags and QA metrics. Both come from one download of each granule's small
QA_STATS.h5, about 75 granules a second (a globe of ~185,000 granules in
about 40 minutes), so ticking either box fills both. The orbit type comes from
the CMR search, and the RFI mitigation flag, which no small file records, is
inherited from the granules of the same product type and release already read
(one product read for a release not seen before). Both are written to the
helper's cache, not the repository's, and need the Earthdata login in
~/.netrc.
The helper searches CMR for every GSLC and GUNW granule in that scope. It
builds the page with scripts/build_local_view.py and opens it; a box in the
lower-left corner shows each step until it does. Frames keep the frame_idx
OPERA uses, the TrackFrame database's row number, so a North American frame has
the same number in every scope.
The consistent mode is computed from the catalog. Blackout dates, granule flags
and QA metrics come from the repo's caches, so they cover North America and
the granules collected so far. back to the published view returns to /.
The same build runs by hand:
Rollout regions. NISAR has no rollout list of its own yet, so each NISAR
frame is tagged with the DISP-S1 North America rollout options it overlaps:
priorities P0, P1, P2, P3a, P3b and P4, from the frame-based rollout
in opera-adt/burst_db
(priority 3 is split into its 3a and 3b deliveries). A frame joins an option
once that option's Sentinel-1 frames cover at least a quarter of it, so a frame
on a boundary can sit in two. The Rollout Regions section lists the frames
per option under the other filters; click an option to show only its frames,
and Color frames by → Rollout option paints each frame by its earliest
option. The frame popup names its options and the states / regions it overlaps,
and the CSV export carries both. scripts/make_rollout_regions.py refreshes
scripts/disp_s1_rollout_regions.geojson
from burst_db; --rollout on either viewer script takes another GeoJSON, or an
OPERA PCM-style region database {"<option>": [frame_idx, ...]} once an official
NISAR list exists.
Map buttons. Three buttons stack above the globe toggle at the bottom
right. For the two overlays each click steps through layer on, layer and
panel, then off; a panel's x hides just the panel. On a phone only one
bottom panel is open at a time.
- The palette button is Color frames by on the map. The first click opens
its panel. The Color by tab lists every colouring for the product shown
(GSLC or GUNW), grouped into counts, mode / coverage, planning, flags and quality (QA),
each with a preview of its colours; tap one to apply it. The Style tab holds
fill opacity (with 0-100 presets), outline opacity (fill 0 with outlines gives
an outline-only map), and the colormap, invert and range of a numeric
colouring or the colour of each category. The second click (or the panel's
x) closes the panel and leaves a small legend on the map; drag it by its title bar to wherever it is out of the way (the spot is remembered), or click it to reopen the panel. The third click, or the legend'sx, hides it. The panel and the sidebar's Frame Color / Opacity edit the same settings. - The flag button draws the rollout regions themselves, coloured by option, with a panel listing each option's NISAR and Sentinel-1 frame counts and the states / regions it spans; click an option to zoom to it.
- The cloud button shows the rainy / snow season blackouts: every frame with a blackout window is filled on a light-to-dark blue ramp by the share of the year it loses (YR, the default; the panel gives it in days), or of one month picked in the panel. The frame colouring is hidden underneath while it is on. Most windows are winter snow cover. Central America's frames carry an August-November window instead: its peak rainy season, which DISP-S1 blacks out the same way and the NISAR windows inherit.
Earthquakes. The seismogram button above the globe toggle draws USGS earthquakes, fetched straight from the USGS FDSN event service, so it works on the published page too. The first click shows them: M4.5 and larger over the last year, in this page's area. The second click opens its panel:
- Minimum magnitude;
- Period: 7 days, 30 days, a year, 5 years, or two dates;
- Area: this page's area, the current map view, or the whole world;
- Colour by: depth (the default, as USGS maps draw it), magnitude, age, or one colour of your choice; this recolours at once, with no new fetch.
Show fetches again. Circles grow with magnitude, and clicking one gives its
time, depth and a link to its USGS event page. USGS
returns at most 20,000 events per request; the panel says when that cap was
hit. The third click swaps the panel for a small legend: the query, the event
count, magnitude sizes and colour key. Its x hides just the legend. The
fourth click adds labels: magnitude over date beside each event. Overlapping
labels are dropped, larger events first. The fifth click hides everything.
Volcanoes. The volcano button steps through the same five clicks as
the earthquakes: triangles, options, legend, labels (name and last eruption),
off. The volcanoes are the Smithsonian Global Volcanism Program's Holocene list
(about 1,200 worldwide). Its server sends no CORS header, so a trimmed copy
ships in the page, refreshed by scripts/make_volcano_list.py. The current US
alert levels and aviation colour codes come live from the USGS Volcano Hazards
Program each time the layer first opens.
The options panel offers:
- Erupted since: any time in the Holocene, or a year;
- Area: this page's area, the current view, or the world;
- Colour by: USGS alert (the default), volcano type, last eruption, or one colour;
- USGS-monitored only.
Clicking a volcano gives its type, country, last eruption, elevation and evidence, any USGS alert with its notice, and links to its GVP page and its USGS observatory page.
The plates, earthquake and volcano buttons share one box above the frame colouring (palette) button, set apart from the frame tools below it.
Tectonic plates. The plates button draws the plate boundaries of Bird (2003), PB2002, fetched from fraxen/tectonicplates on first use. Subduction zones are drawn a little thicker, and hovering a boundary names its two plates. A second click adds the plate names, and a third hides them. The button works as in the geepers UNR grid viewer. The boundaries sit above the frames and below earthquakes and volcanoes.
CRID. The Mode / Polarization / CRID section also lists the composite
release IDs (P05023, ...) read from the granule names. Selecting some narrows
the map to frames with granules from those releases and recounts the colourings
over just them; none selected means every release.
Blackout by month. When the viewer is built with blackout dates, the Blackout by Month chart counts, for each calendar month, the frames shown whose blackout window covers at least half of it (dark) or any part of it (light). Clicking a month colours the map by the share of that month each frame loses (Color frames by → Blackout share of a month, with a month picker), and the frame popup draws a twelve-month strip shaded by the same share. Blackout duration (months) still colours by the window's total length.
Cycle. The Location (Track / Frame / Cycle) section also takes cycle
numbers (23, 20-25, 12,14). Like the CRID chips, they narrow the map to
frames with granules from those cycles and recount the colourings (counts and
QA) over just them. A GUNW pair counts when either acquisition is in one of the
cycles; its name carries both.
Show only selected frames, in the same section, narrows the map, the
summary and the over-time chart to the frames in your selection, on top of
whatever other filters are set. Land frames only hides the frames with no
land at all (the TrackFrame database's hasLand, i.e. fractionLand above
zero): about half of the globe's frames, and 30 of North America's 1,295.
Where the CalVal frames come from
CalVal frames only shows the NISAR frames over the twelve DISP-S1
validation sites, listed as DISP-S1 frame polygons in
scripts/disp_s1_calval_sites.geojson,
plus the Mexico City basin, added as a fast-deforming area. No DISP-S1 frame
is centred on the city, so that site is a box around the basin instead.
Every NISAR frame covering at least 10 % of a site is flagged, ascending and
descending alike. This replaces the TrackFrame GeoPackage's own
isCalVal flag; isSNWG and isDNC are still carried from the GeoPackage.
To change the sites, edit the GeoJSON (or pass --calval-sites) and rebuild
the viewer, or re-flag an already built one in place (this also re-tags
the rollout options):
python scripts/generate_scope_viewer.py --frames-gpkg ... --gslc-db ...
python scripts/sync_viewer_html.py docs/assets/opera_nisar_db_viewer.html
sync_viewer_html.py also takes --blackout-json and --gunw-catalog to
attach snow blackout dates or the GUNW view to a page built without them.