Skip to main content

Superpixel

GitHub repository

superpixel models the effective point-spread function (PSF) of a detector superpixel. It combines an optical PSF with a gain-weighted array of shifted square-subpixel responses, or models the complete detector response as a single point at the superpixel origin. It handles different subpixel gains or dead subpixels.

The package calculates:

  • ensquared energy in a rectangular window or encircled energy in a circular aperture;
  • the radiometric barycenter;
  • orthogonal PSF cuts through the barycenter and their FWHM values;
  • the normalized 2D MTF, its x/y cuts, and values at the tiled-superpixel Nyquist frequencies.

Superpixel requires Python 3.10 or newer and uses uv for dependency management.

Python API

The supported Python API is the curated set of names exported directly from superpixel. Package submodules such as superpixel.plotting and superpixel.ui are implementation details and may change between releases.

From a source checkout, create the environment and install the locked dependencies:

uv sync

Basic analysis

A typical analysis creates an optical PSF, constructs the sampled superpixel response, and evaluates all metrics:

import numpy as np

from superpixel import (
    IntegrationWindow,
    analyze_superpixel,
    build_superpixel_psf,
    gaussian_psf,
)

psf = build_superpixel_psf(
    gaussian_psf(fwhm_x=14.4, fwhm_y=12.0),
    shape=(2, 3),
    pitch=(10.0, 10.0),
    subpixel_side=9.0,
    gains=np.array(
        [
            [1.00, 0.95, 1.05],
            [0.90, 1.10, 1.00],
        ]
    ),
    model_half_width=(80.0, 80.0),
    sample_spacing=(0.2, 0.2),
)

analysis = analyze_superpixel(
    psf,
    IntegrationWindow(
        center=(0.0, 0.0),
        size=(30.0, 20.0),
    ),
)

print("Integrated energy:", analysis.ensquared_energy)
print("Barycenter:", analysis.barycenter)
print("FWHM:", analysis.cuts.fwhm_x.width, analysis.cuts.fwhm_y.width)
print(
    "MTF at Nyquist:",
    analysis.mtf.at_nyquist_x,
    analysis.mtf.at_nyquist_y,
)

build_superpixel_psf returns a SuperpixelPSF whose sampled density is normalized so that its integral over the numerical grid is one. output_grid_energy_fraction is the fraction of the internally normalized, gain-weighted effective PSF that lies inside the requested output grid before this final normalization. It depends on relative gains when shifted subpixel responses are cropped by different amounts. Multiplying all gains by the same factor has no effect. Increase model_half_width until the results converge, particularly for an Airy PSF.

analyze_superpixel returns the PSF, integrated energy, barycenter, barycenter-centered PSF cuts and FWHM values, and the complete 2D MTF with its cuts.

Coordinate and unit conventions

  • Coordinate pairs and sizes are (x, y) = (column, row).
  • Array shapes and gain matrices are (rows, columns).
  • pitch=(pitch_x, pitch_y), model_half_width=(x, y), and sample_spacing=(x, y).
  • All lengths in one analysis must use the same unit.
  • The tiled-superpixel Nyquist frequencies are 1 / (2 * columns * pitch_x) and 1 / (2 * rows * pitch_y).
  • A full-superpixel point response has no detector pitch and therefore no detector-defined Nyquist frequency.

Optical PSF models

A Gaussian can be specified using sigma or FWHM values. Its optional rotation angle is measured counter-clockwise in radians:

from superpixel import gaussian_psf

model = gaussian_psf(fwhm_x=14.4, fwhm_y=10.0, angle=0.2)

An Airy PSF accepts either its first-zero radius or wavelength and f-number:

from superpixel import airy_psf

model = airy_psf(wavelength=0.55, f_number=8.0)
# Alternatively: airy_psf(first_zero_radius=5.37)

Wavelength and first-zero radius must use the same length unit as the detector geometry.

Any vectorized callable with the signature psf(x, y) can be supplied:

import numpy as np


def custom_psf(x, y):
    sigma_x = 5.0
    sigma_y = 7.0
    return np.exp(-0.5 * ((x / sigma_x) ** 2 + (y / sigma_y) ** 2))

The callable receives NumPy arrays and must return finite, non-negative values. It does not need to be pre-normalized.

For trusted local code stored as text, custom_psf_from_code compiles a function named psf. This executes Python and is not a security sandbox.

Optical and detector response modes

Pass None as the optical PSF to model ideal optics with only the square detector response:

pixel_only = build_superpixel_psf(
    None,
    subpixel_side=10.0,
)

Square-subpixel mode is the default and requires a positive subpixel_side. There is no per-subpixel point-response mode.

Use detector_response="point" to replace the complete subpixel array with a single point response at the origin. Shape, pitch, side length, and gains are ignored in this mode:

optics_only = build_superpixel_psf(
    gaussian_psf(fwhm_x=14.4),
    detector_response="point",
)

sampled_dirac = build_superpixel_psf(
    None,
    detector_response="point",
)

Numerical convolution is performed only when both an optical PSF and the square detector response are enabled.

Integration apertures

The default IntegrationWindow is rectangular. Use a circular aperture by selecting its shape and radius:

window = IntegrationWindow(
    center=(0.0, 0.0),
    shape="circle",
    radius=15.0,
)
analysis = analyze_superpixel(psf, window)

JSON configuration

The UI configuration schema is also available through the Python API:

from superpixel import AppConfig, load_config, save_config

config = AppConfig()
save_config(config, "superpixel-config.json")
restored = load_config("superpixel-config.json")

Configuration objects are validated when constructed or loaded. Invalid values and unsupported configuration versions raise ValueError.

Use analyze_config when an application configuration is already available. It is the same configuration-driven workflow used by the desktop UI; display settings do not affect its numerical result:

from superpixel import AppConfig, analyze_config

analysis = analyze_config(AppConfig())
print(analysis.ensquared_energy)

Desktop UI

Start the native NiceGUI application from the repository:

uv run superpixel

The repository entry point can also be run directly:

uv run python run_ui.py

The input area is organized into Optical PSF, Superpixel Configuration, Numerical Grid, and Integrated Energy Analysis sections. Click Simulate to run the same numerical API used directly from Python and update the PSF, MTF, cut plots, and numerical results.

The configuration menu provides:

  • Save configuration to download the current settings as JSON;
  • Load configuration to validate and apply a JSON configuration to the inputs;
  • Reset to defaults to restore the original application settings.

Loading a configuration updates the inputs but does not execute custom PSF code or start a simulation. Review the settings and click Simulate.

Every simulation also saves the current configuration to ~/.superpixel/config.json. The UI restores this file on its next launch. Set SUPERPIXEL_CONFIG_PATH to use a different automatic configuration path.

Custom PSF code entered in the UI is executed as Python. Only run code you trust, and do not expose the UI as a public service while custom code is enabled.

Maintenance and contribution

Development workflow

Synchronize the locked environment after cloning the repository or changing dependencies:

uv sync

Run the complete test suite before submitting a change:

uv run pytest

Install the repository hook once after cloning. It automatically sorts imports, applies safe Ruff lint fixes, and formats staged Python files before each commit:

uv run pre-commit install

The main source areas are:

  • src/superpixel/simulation.py: sampled PSF construction and detector response modes;
  • src/superpixel/models.py: built-in and custom optical PSF models;
  • src/superpixel/metrics.py: energy, barycenter, cuts, FWHM, and MTF;
  • src/superpixel/analysis.py: high-level analysis orchestration;
  • src/superpixel/workflow.py: configuration-driven application workflow;
  • src/superpixel/plotting.py: thin internal facade for focused PSF and MTF plotting modules;
  • src/superpixel/config.py: validated JSON configuration;
  • src/superpixel/ui.py: the NiceGUI controller, with form, gain, persistence, and result views in internal _ui_* modules;
  • tests/: numerical, configuration, plotting, and UI tests.

Keep numerical behavior in the Python API rather than in the UI. The UI should remain a thin controller that builds AppConfig, calls analyze_config, and presents its result. Export supported interfaces from src/superpixel/__init__.py, use Google-style docstrings for those interfaces, and add tests for changed behavior.

Build a one-file executable

The application uses NiceGUI native mode and can be packaged with PyInstaller. Build on the same operating system and CPU architecture on which the executable will run; PyInstaller does not cross-compile.

After uv sync, run from the repository root:

uv run build

The build command reads the installed package version and passes Superpixel-<version> to nicegui-pack. Updating the project version therefore also updates the executable name without changing the build command. Run it from the repository root so it can package run_ui.py.

The executable is written to:

  • Windows: dist/Superpixel-<version>.exe
  • macOS: dist/Superpixel-<version>
  • Linux: dist/Superpixel-<version>

License

Superpixel is released under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

superpixel-1.2.0.tar.gz (32.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

superpixel-1.2.0-py3-none-any.whl (41.3 kB view details)

Uploaded Python 3

File details

Details for the file superpixel-1.2.0.tar.gz.

File metadata

  • Download URL: superpixel-1.2.0.tar.gz
  • Upload date:
  • Size: 32.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for superpixel-1.2.0.tar.gz
Algorithm Hash digest
SHA256 5fa94a8f862448ae9370304755d1fe93711413d969d0d29b3b03efd3c60c7104
MD5 90b12be9f6c4b92d5f2186bf89fd1b3f
BLAKE2b-256 3e49ca5537b55bd0210334ec31ee70bc11521b643c97e77976476a955a38c2cb

See more details on using hashes here.

File details

Details for the file superpixel-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: superpixel-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 41.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for superpixel-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7b28649f0817d8bd314d9ab46a522b6c06f45c18f32d2a21c4ecc468a2080f5a
MD5 186caa22dac05adc0af3c649feaf7f77
BLAKE2b-256 8cd8e2c6ea448d8ce17648928760d588306627074688eccc4ab1adfef32cc247

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 files

1.1.0

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page