What’s New in playNano 0.4.0

Release date: 226-05-11

This release adds a new file reader for Asylum Research high-speed AFM data, three new animated export formats, a unified colormap system with perceptually linear maps designed for AFM data, and a vertical-flip processing filter. It also extends Python and NumPy support, refactors the visual rendering pipeline, and includes numerous fixes to per-frame metadata handling across all loaders.

Added

  • ARIS File Reader: playNano can now load Asylum Research .aris high-speed AFM files. The loader extracts channel names from HDF5 metadata, computes global and per-frame pixel-size scaling with well-defined fallback behaviour, sorts and stacks frames, and parses and validates timestamps. Multi-suffix file loading (e.g. .ome.tif) is also now supported in the loader dispatch logic.

  • Video and Image Sequence Export: Two new animated export formats are available alongside GIF:

    • Video — MP4, AVI, MOV, and MKV via playnano.io.video_export.

    • Image sequences — individual PNG or JPEG files in a named folder via playnano.io.image_sequence_export.

    All three formats share a unified rendering pipeline in the new playnano.io.render_utils module, which enforces a minimum output resolution (512 px), ensures scale bars are physically accurate regardless of frame size, and keeps annotation proportions consistent across resolutions. See :doc:exporting for full details.

  • Native Colormaps: Three perceptually designed colormaps are now bundled and registered globally as Matplotlib colormaps on import:

    • afm_brown (default) — perceptually linear (R² ≈ 0.996), eliminates the dark plateau and flicker artefacts common in traditional AFM colour schemes.

    • playnano_gold — full dynamic range (L* 0–100), high contrast for complex topography.

    • classic_afm — non-linear legacy map for continuity with existing workflows.

    Reversed variants (_r) are registered automatically. See :doc:colormaps for background, usage, and a comparison with afmhot.

  • Vertical Flip Filter: A new built-in processing filter vertical_flip reverses the row order of a 2D frame using numpy.flipud.

  • Python 3.13 and NumPy 2.x Support: Python 3.13 is now officially supported and included in the CI test matrix. The NumPy upper-version pin (<2.0) has been removed, enabling compatibility with NumPy 2.0 and later.

  • CLI Additions:

    • --version global flag prints the installed playNano version and exits.

    • --cmap selects a colormap in play, process, and wizard.

    • --fps controls frame rate for animated exports. In play, the argument is optional and falls back gracefully to a default of 5 fps with a logged warning if a non-numeric value is supplied; in process, a numeric value is required.

    • --make-video exports video after processing (default format: MP4).

    • --make-sequence exports a PNG image sequence after processing.

    • --draw-ts toggles timestamp rendering on animated exports (default: off).

    • Wizard REPL extended: after GIF export the wizard now prompts for timestamps, scale-bar length, and optionally exports a video with configurable zmin, zmax, timestamps, and scale bar.

  • src/playnano/resources/: A dedicated package for non-code assets. Bundled fonts have been moved here from src/playnano/fonts/, and colormap CSV files are loaded via importlib.resources for robust cross-platform asset access.

  • sphinx-apidoc Integration: API documentation is now generated automatically via a builder-inited hook in conf.py, removing the need to maintain RST stubs manually.

Changed

Per-Frame Pixel-Size Semantics

AFMImageStack.pixel_size_nm now represents the global or first-frame pixel size only. Per-frame overrides are stored in frame_metadata[i]["frame_pixel_size_nm"] and are read via the new AFMImageStack.scaling_for_frame(idx) method. For most datasets the values are identical; differences arise when scan size changes mid-acquisition (e.g. ARIS files). GUI playback and all animated exports now respect per-frame pixel size.

All loaders have been updated to populate frame_pixel_size_nm in every frame_metadata entry. The frame_metadata construction bug that caused entries to be overwritten or incomplete in the .spm and .jpk loaders has been fixed. The .h5-jpk and .asd loaders record a constant value; .jpk, .spm, and .aris record per-frame values.

OME-TIFF export now raises a ValueError if pixel sizes are not consistent across frames, since the format only supports a single PhysicalSizeX/PhysicalSizeY value.

Visualisation Rendering

The rendering logic previously embedded in export_gif has been extracted into playnano.io.render_utils, which is now the single source of truth for frame normalisation, colourisation, upscaling, and annotation across all visual exports. Visual constants (minimum frame height, reference height, annotation colour, font scale) are centralised here. The default colormap for all exports has changed from afmhot to afm_brown.

GUI

  • A colormap selection dropdown has been added to the export panel.

  • The z-scale histogram bars are now coloured with the active colormap and update dynamically when zmin, zmax, or the colormap change.

  • The GIF export panel has been replaced with a unified Save Animated Data panel supporting GIF, MP4, AVI, and PNG folder exports via per-format checkboxes.

  • FPS is now initialised from --fps if provided, otherwise derived from line_rate in the first frame’s metadata (previously always defaulted to 10 fps in the controls).

Developer Tooling

  • Pre-commit exclude paths updated from src/playnano/fonts/ to src/playnano/resources/fonts/ across all hooks.

  • np.string_() replaced with np.bytes_() in HDF5 export for NumPy 2.x compatibility.

  • _decode_attr in read_h5jpk promoted to playnano.utils.io_utils.decode_hdf5_attr and reused in read_aris.

Fixed

  • Fixed loader errors caused by missing file extensions or no-suffix inputs; the loader now correctly handles multi-suffix formats such as .ome.tif and .ome.tiff.

  • Connected FPS calculation based on line_rate to GUI playback; previously the computed value was not passed through to the GUI controls.

  • Fixed frame_metadata construction in .spm and .jpk folder loaders: entries were previously overwritten in the loop, resulting in only the last frame’s metadata being retained.

  • Standardised per-frame metadata keys across all formats: timestamp, frame_pixel_size_nm, and line_rate.

  • Removed the inconsistent pixel-size equality check in .spm and .jpk folder loaders; per-frame variation is now recorded rather than raising a ValueError.

  • Improved numerical robustness in tests: floating-point comparisons now use pytest.approx for cross-platform consistency.

Documentation

  • New :doc:colormaps page covering the three native colormaps, their perceptual properties, usage in the CLI and GUI, and background on perceptual linearity in AFM visualisation.

  • :doc:exporting restructured into Animated Exports (GIF, video, image sequence) and Data Exports (OME-TIFF, NPZ, HDF5) sections, with full CLI and programmatic usage for each format.

  • :doc:cli updated with global options (--version, --log-level), new process and play flags, and corrected help text for FPS defaults.

  • :doc:gui updated to document the colormap selector, unified animated export panel, and revised annotation controls.

  • :doc:introduction and :doc:index updated to include .aris in the list of supported formats.

  • processing-operations-reference updated to include vertical_flip.

  • API reference reorganised into captioned sections: Core, IO & Data Formats, Processing Pipeline, Analysis & Modules, General Utilities, CLI & App Utils, and Graphical Interface.

Pytest Coverage Added

  • ARIS HDF5 loading: channel extraction, global pixel scaling, frame key sorting, per-frame pixel-size overrides and fallback to global scale, timestamp mismatch, and missing channel errors.

  • Multi-suffix file handling: .ome.tif, .ome.tiff, and all single-suffix formats via get_loader_for_file.

  • Video export: all four container formats, flat data, various z-scale configurations, raw/processed data selection, and early-exit when make_video=False.

  • Image sequence export: PNG and JPEG output, flat data, various z-scale configurations, raw/processed data selection, and invalid format rejection.

  • render_utils: upscaling behaviour, global normalisation, flat-frame handling, NaN/inf robustness, and physically accurate scale bar width across frame sizes and pixel sizes.

  • Colormap utilities: resolve_cmap fallback and warning, load-failure error logging, is_valid_cmap with non-string and unregistered inputs, get_available_cmaps sort order.

  • GUI: _get_cmap fallback, _on_cmap_changed with valid and invalid names, _update_histogram_colors z-range selection, and _export_animated raw/processed branch logic.

  • CLI FPS parsing: play with no flag, flag without value, valid numeric value, and invalid string; process error on invalid value; help text content.

  • AFMImageStack.scaling_for_frame: present and missing frame_pixel_size_nm entries.