Skip to content

Add a headless mode for running without a display - #67

Merged
HazenBabcock merged 1 commit into
ZhuangLab:masterfrom
HazenBabcock:add-headless-mode
Sep 8, 2026
Merged

HazenBabcock merged 1 commit into
ZhuangLab:masterfrom
HazenBabcock:add-headless-mode

Conversation

@HazenBabcock

Copy link
Copy Markdown
Member

Running the diagnostics one after another stops on a plot window.
frc/frc_calc2d.py has show_plot = True by default and
diagnostics/frc/analyze_data.py calls it without saying otherwise, once per
test directory. Its command line already has --no-plot; only the
programmatic call was missing the equivalent.

Two changes, because the immediate cause and the general one are different.

The call site

diagnostics/frc/analyze_data.py now passes show_plot = False. An analyze
step that loops over directories should never wait for someone to close a
window.

The general case

STORM_ANALYSIS_HEADLESS in the environment now selects a non-interactive
matplotlib backend, set in __init__.py before pyplot is imported. That
makes every pyplot.show() in the package a no-op — all 21 of them — without
touching a single call site.

Worth having because the flags controlling this are not consistent:

module flag note
frc/frc_calc2d.py show_plot defaults to True
multi_plane/plane_weighting.py no_plots inverted sense
rcc/rcc_drift_correction.py make_plots
micrometry/micrometry.py show, save_as

Four flags, three spellings, one inverted. Anyone adding a diagnostic has to
know which applies, and getting it wrong produces a hung script rather than an
error.

Figures written to disk are unaffected

savefig() works the same under Agg. Checked rather than assumed: directly,
and by re-running the multicolor diagnostic headless and confirming it still
produces its three mapping images.

Verified that the default is unchanged (tkagg here), that with the variable
set the backend is Agg and show() returns instead of blocking, and that
the frc diagnostic's analyze step drops from 9s to 2s because it no longer
builds the figure.

Also adds isHeadless(), for code that would rather skip building a figure it
cannot display.

The diagnostics README says how to use it, and — while there — that
multiplane/configure.py needs --psf-model, which is the one thing in that
directory you cannot work out from the README.


Full test suite passes, 280 tests. All 17 diagnostics were then run end to
end with this branch, 68 steps, no failures; multiplane was run three times,
once per PSF model.

Running the diagnostics one after another stops on a plot window, because
frc/frc_calc2d.py has show_plot = True by default and
diagnostics/frc/analyze_data.py calls it without saying otherwise, once
per test directory. Its command line already has --no-plot; only the
programmatic call was missing the equivalent.

Two changes, because the immediate cause and the general one are
different.

The call site now passes show_plot = False. An analyze step that loops
over directories should never wait for anyone.

And STORM_ANALYSIS_HEADLESS in the environment now selects a
non-interactive matplotlib backend, in __init__.py, before pyplot is
imported. That makes every pyplot.show() in the package a no-op, all
twenty one of them, without touching a single call site. Worth having
because the flags that control this are not consistent:

    frc/frc_calc2d.py            show_plot   default True
    multi_plane/plane_weighting  no_plots    inverted sense
    rcc/rcc_drift_correction     make_plots
    micrometry/micrometry        show, save_as

Four names, three spellings, one inverted. Anyone adding a diagnostic has
to know which one applies, and the failure is a hung script rather than
an error.

Figures written to disk are unaffected: savefig() works the same under
Agg, and the multicolor diagnostic still produces its three mapping
images. Checked rather than assumed, both by writing a file directly and
by re-running that diagnostic headless.

Verified that the default is unchanged, tkagg here, and that with the
variable set the backend is Agg and show() returns instead of blocking.
Also isHeadless(), for code that wants to skip building a figure it
cannot display.

The diagnostics README says how to use it, and, while there, that
multiplane/configure.py needs --psf-model.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@HazenBabcock
HazenBabcock merged commit ec03560 into ZhuangLab:master Sep 8, 2026
5 checks passed
@HazenBabcock
HazenBabcock deleted the add-headless-mode branch September 8, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant