pycat-napari 1.5.332__tar.gz → 1.5.334__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/CHANGELOG.md +73 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/PKG-INFO +1 -1
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/pyproject.toml +1 -1
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/dynamic_spatial_tools.py +18 -6
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/vpt_tools.py +491 -14
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/vpt_ui.py +132 -4
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/.gitignore +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/CONTRIBUTING.md +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/LICENSE +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/README.md +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/THIRD_PARTY_LICENSES.txt +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/pycat-devbio-napari-env-arm-mac.yaml +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/pycat-devbio-napari-env-x86-windows.yaml +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/pycat-napari-env-arm-mac.yaml +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/pycat-napari-env-x86-windows.yaml +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/requirements-arm-mac.txt +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/requirements-base.txt +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/requirements-devbio-napari-arm-mac.txt +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/config/requirements-devbio-napari.txt +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/Makefile +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/audits/DEV_NOTES.md +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/audits/PyCAT_method_audit_2026-07-09.md +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/audits/PyCAT_napari_integration_audit_2026-07-09.md +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/logos/pycat_logo-2.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/logos/pycat_logo.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/logos/pycat_logo_1024.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/logos/pycat_logo_256.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/logos/pycat_logo_512.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/make.bat +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/requirements.txt +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/dark_mode.css +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/examples/Image 1 dapi.tif +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/examples/Image 1.tif +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/pycat_logo_512.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/screenshots/Viewer_and_menu_highlights.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/screenshots/cell_analyzer.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/screenshots/condensate_segmentation.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/screenshots/measuring_lines.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/screenshots/opened_image_in_viewer.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/screenshots/preprocessed_images.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_static/screenshots/save_and_clear_popup.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/_templates/autosummary/module.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/index.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/pycat.central_manager.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/pycat.data.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/pycat.file_io.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/pycat.run_pycat.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/pycat.toolbox.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/pycat.ui.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/api/pycat.utils.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/conf.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/development/contributing.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/development/index.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/development/roadmap.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/development/support.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/features.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/index.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/installation.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/usage/index.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/source/usage/tutorials/nuclear_condensate_analysis_gui_tutorial.rst +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/docs/test.txt +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/notebooks/Synthtic Data Generation NB.ipynb +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/notebooks/int_truncated_dfs.ipynb +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/notebooks/pycat_plotting.ipynb +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/__init__.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/batch_processor.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/batch_step_registry.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/central_manager.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/data/__init__.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/data/data_modules.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/file_io/__init__.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/file_io/file_io.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/file_io/frap_io.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/file_io/metadata_extract.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/file_io/multidim_io.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/file_io/session_loader.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/fix_tifffile.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/icons/pycat_logo-2.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/icons/pycat_logo.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/icons/pycat_logo_1024.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/icons/pycat_logo_256.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/icons/pycat_logo_512.png +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/run_pycat.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/__init__.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/advanced_analysis_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/analysis_plots.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/batch_roi_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/benchmark_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/brightfield_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/brightfield_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/clean_spot_detection_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/condensate_physics_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/condensate_physics_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/contrast_cascade_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/contrast_cascade_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/correlation_func_analysis_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/data_qc_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/data_qc_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/data_viz_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/fd_curve_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/fd_curve_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/feature_analysis_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/fft_bandpass_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/fibril_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/fibril_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/frap_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/frap_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/fusion_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/fusion_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/gaussian_localization_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/gpu_utils.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/image_processing_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/intensity_profile_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/invitro_bf_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/invitro_fluor_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/invitro_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/label_and_mask_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/layer_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/molecular_counting_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/morphological_complexity_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/nb_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/nb_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/numba_utils.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/obj_based_coloc_analysis_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/organizational_metrics_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/partition_enrichment_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/pipeline_diagnostic_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/pipeline_snr_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/pixel_wise_corr_analysis_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/segmentation_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/spatial_acf_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/spatial_metrology_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/spatial_metrology_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/spatial_randomness_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/spida_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/spida_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/temperature_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/temperature_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/temporal_enhancement_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/timeseries_condensate_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/timeseries_invitro_fluor_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/timeseries_invitro_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/topology_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/trackmate_bridge.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/ts_cache_manager.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/ts_cellpose_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/two_channel_coloc_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/video_export_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/zstack_segmentation_tools.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/toolbox/zstack_segmentation_ui.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/__init__.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/coordinate_readout.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/field_status.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_analysis_mixin.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_diagnostics_mixin.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_filtering_mixin.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_imageops_mixin.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_labels_mixin.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_modules.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_segmentation_mixin.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/ui_utils.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/ui/workflow_checklist.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/utils/__init__.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/utils/channel_naming.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/utils/general_utils.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/utils/logging_utils.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/src/pycat/utils/math_utils.py +0 -0
- {pycat_napari-1.5.332 → pycat_napari-1.5.334}/tests/README.md +0 -0
|
@@ -4,6 +4,79 @@ All notable changes to PyCAT-Napari will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.5.334] - 2026-07-10
|
|
8
|
+
### Fixed — VPT linker shattered stable beads into short tracks (the core linking problem)
|
|
9
|
+
- **Root cause 1 — gap-frame off-by-one.** The greedy linker's viability AND
|
|
10
|
+
expiry checks used `t - last_frame <= max_gap_frames`, which at `gap=0` rejects
|
|
11
|
+
even the immediately-previous frame — collapsing every detection into its own
|
|
12
|
+
length-1 "track" (and hanging/crashing the GUI when it then tried to build a
|
|
13
|
+
Tracks layer from tens of thousands of singletons). Fixed to
|
|
14
|
+
`<= max_gap_frames + 1` so `gap=0` links consecutive frames, `gap=1` bridges one
|
|
15
|
+
missing frame, etc. The Bayesian linker had the same off-by-one in its expiry
|
|
16
|
+
check only (inconsistent with its own viability filter, which was already
|
|
17
|
+
correct) — also fixed. Verified on real data: a confirmed stable bead present in
|
|
18
|
+
1000/1000 frames now links into ONE 1000-frame track instead of shattering.
|
|
19
|
+
- **Root cause 2 — max linking distance too tight, now auto-derived from bead
|
|
20
|
+
motion.** The dominant problem: the default linking distance (~0.4 µm) was below
|
|
21
|
+
the beads' own frame-to-frame jitter tail (they move up to ~340 nm/frame), so it
|
|
22
|
+
clipped real motion and broke stable beads into short fragments that cannot
|
|
23
|
+
support the MSD measurement window. **New `estimate_linking_distance_um()`
|
|
24
|
+
derives a physically-grounded distance WITHOUT linking any tracks**, via a
|
|
25
|
+
short-window MAX-projection of the stack: the projected bead width broadened
|
|
26
|
+
beyond the single-frame PSF width gives the per-frame displacement scale
|
|
27
|
+
(`motion_σ = √(σ²_proj − σ²_psf)`), and the distance is `k × motion_σ` (k margin,
|
|
28
|
+
default 2.5), capped at the bead footprint so it can't grab neighbours. It is
|
|
29
|
+
viscosity-adaptive (slow beads → tight, fast beads → loose) and needs no
|
|
30
|
+
provisional linking pass. Auto-filled into the Step-4 linker field after Detect
|
|
31
|
+
Beads (shown and editable; anti-black-box), with the margin `k` exposed under a
|
|
32
|
+
new "Show advanced linking options" expander. Validated on real data: derives
|
|
33
|
+
0.58 µm (per-frame motion ~232 nm × 2.5), and linking there yields full
|
|
34
|
+
1000-frame tracks — 10% of tracks now span ≥80% of the movie (was ~0%),
|
|
35
|
+
i.e. measurement-grade trajectories.
|
|
36
|
+
- **GUI crash guard.** If a link still comes out degenerate (>2000 tracks and
|
|
37
|
+
>90% single-frame), PyCAT warns and skips building the Tracks layer instead of
|
|
38
|
+
freezing.
|
|
39
|
+
|
|
40
|
+
### Changed — track-length histogram pops out
|
|
41
|
+
- The linker track-length histogram now opens as a dockable "Track lengths" panel
|
|
42
|
+
(reused across relinks) instead of sitting inline in the Step-4 form.
|
|
43
|
+
|
|
44
|
+
## [1.5.333] - 2026-07-10
|
|
45
|
+
### Added — VPT detection-variant staging + track-length histogram
|
|
46
|
+
- **Detection-variant staging framework.** `detect_beads_stack` gained a
|
|
47
|
+
`detection_variant` argument (default `'baseline'` = the 1.5.329-validated
|
|
48
|
+
path, byte-identical). New detection/classification approaches are opt-in
|
|
49
|
+
variants routed through their own branches, so the validated ~8.325-through-
|
|
50
|
+
TrackMate path stays selectable and any regression is a clean one-arg revert. A
|
|
51
|
+
`compare_detection_variants()` harness runs two variants on the same stack and
|
|
52
|
+
reports the classification diff, and the chosen variant is recorded on the
|
|
53
|
+
output DataFrame's attrs. This is the safety net for the detection rework —
|
|
54
|
+
every proposed change is A/B-measured against baseline before it is trusted.
|
|
55
|
+
- **`ring_merge` variant** (`dedup_detections_ring_merge`) — sigma-scaled merge
|
|
56
|
+
radius that folds DIM Airy-ring fragments into their BRIGHT centre while keeping
|
|
57
|
+
two genuinely-bright nearby beads as two. Built and kept in the codebase but
|
|
58
|
+
**not surfaced in the widget and flagged as needing validation data with
|
|
59
|
+
resolved Airy rings**: A/B on the current bead data showed it is a near no-op
|
|
60
|
+
there (beads well-separated, blob_log already ~one detection per bead). Reach it
|
|
61
|
+
via `detection_variant='ring_merge'`.
|
|
62
|
+
- **`hot_pixel_reject` variant** (`build_hot_pixel_mask` + harsher on-pixel NCC
|
|
63
|
+
gate) — identifies FIXED sensor hot/dead pixels from the stack's *temporal*
|
|
64
|
+
statistics (scene-independent: hot pixels are flat in time, tstd~3-4; beads are
|
|
65
|
+
variable, tstd~40-50), then applies a STRICTER acceptance test to detections
|
|
66
|
+
landing on them rather than a flat veto — so a real bead drifting over a hot/
|
|
67
|
+
dead pixel still survives on its template evidence. Validated correct and safe
|
|
68
|
+
(every confirmed bead survived, including one adjacent to a hot pixel). Nearly a
|
|
69
|
+
no-op on the current clean fluorescence data (~18 hot pixels found, blob_log
|
|
70
|
+
barely fires on them); earns its place on data/modes that turn hot pixels into
|
|
71
|
+
recurring false detections. Reach it via `detection_variant='hot_pixel_reject'`.
|
|
72
|
+
- **Track-length histogram in the linker widget.** Step 4 (Link Trajectories) now
|
|
73
|
+
shows an embedded histogram of trajectory lengths (frames per track) after each
|
|
74
|
+
link. A healthy link piles mass toward long tracks; a fragmentation-prone linker
|
|
75
|
+
shows a spike of very short tracks. The title reports the track count and the
|
|
76
|
+
fraction spanning ≥½ the movie, and a dashed line marks the median — an
|
|
77
|
+
at-a-glance linker-quality check. Fails safe if matplotlib-Qt embedding is
|
|
78
|
+
unavailable.
|
|
79
|
+
|
|
7
80
|
## [1.5.332] - 2026-07-10
|
|
8
81
|
### Fixed — VPT classifier green↔yellow flicker on bright, well-matched beads
|
|
9
82
|
- **A bright, high-NCC bead no longer flips singlet↔out_of_plane frame-to-frame.**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycat-napari
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.334
|
|
4
4
|
Summary: Python Condensate Analysis Toolbox - A napari-based tool for biomolecular condensate analysis
|
|
5
5
|
Project-URL: Homepage, https://github.com/BanerjeeLab-repertoire/pycat-napari
|
|
6
6
|
Project-URL: Repository, https://github.com/BanerjeeLab-repertoire/pycat-napari
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pycat-napari"
|
|
7
|
-
version = "1.5.
|
|
7
|
+
version = "1.5.334"
|
|
8
8
|
description = "Python Condensate Analysis Toolbox - A napari-based tool for biomolecular condensate analysis"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12,<3.13"
|
|
@@ -332,9 +332,12 @@ def link_trajectories_bayesian(
|
|
|
332
332
|
assigned_dets.add(c)
|
|
333
333
|
# else: death (r < n_viable, c >= n_curr) — track ends naturally
|
|
334
334
|
|
|
335
|
-
# Expire tracks not seen for too long
|
|
335
|
+
# Expire tracks not seen for too long. Must match the viability filter
|
|
336
|
+
# above (t - last_frame <= max_gap_frames + 1); using the bare
|
|
337
|
+
# max_gap_frames here expired tracks one frame too early, so a track was
|
|
338
|
+
# admitted as viable next frame but could already have been dropped.
|
|
336
339
|
active = {tid: info for tid, info in active.items()
|
|
337
|
-
if t - info['last_frame'] <= max_gap_frames}
|
|
340
|
+
if t - info['last_frame'] <= max_gap_frames + 1}
|
|
338
341
|
|
|
339
342
|
# ── Gap closing: second pass ──────────────────────────────────────────
|
|
340
343
|
if max_gap_frames > 0:
|
|
@@ -470,9 +473,17 @@ def link_trajectories(
|
|
|
470
473
|
curr = df[df['frame'] == t].copy()
|
|
471
474
|
curr_pts = curr[['y_um', 'x_um']].values
|
|
472
475
|
|
|
473
|
-
# Find which active tracks are still linkable (within gap window)
|
|
476
|
+
# Find which active tracks are still linkable (within gap window).
|
|
477
|
+
# max_gap_frames = number of MISSING frames tolerated, so a track last
|
|
478
|
+
# seen at frame f is linkable at frame t when (t - f) - 1 <= max_gap,
|
|
479
|
+
# i.e. t - f <= max_gap + 1. gap=0 therefore links CONSECUTIVE frames
|
|
480
|
+
# (t - f == 1), gap=1 bridges one missing frame (t - f == 2), etc.
|
|
481
|
+
# (Previously this used `t - f <= max_gap`, an off-by-one that made
|
|
482
|
+
# gap=0 reject even the immediately-previous frame — collapsing every
|
|
483
|
+
# track to length 1. Beads present in consecutive frames must link at
|
|
484
|
+
# gap=0.)
|
|
474
485
|
viable = {tid: info for tid, info in active_tracks.items()
|
|
475
|
-
if t - info[2] <= max_gap_frames}
|
|
486
|
+
if t - info[2] <= max_gap_frames + 1}
|
|
476
487
|
|
|
477
488
|
if not viable or len(curr_pts) == 0:
|
|
478
489
|
# Start new tracks for all detections this frame
|
|
@@ -516,9 +527,10 @@ def link_trajectories(
|
|
|
516
527
|
df.at[df_idx, 'y_um'], df.at[df_idx, 'x_um'], t)
|
|
517
528
|
next_track += 1
|
|
518
529
|
|
|
519
|
-
# Remove expired tracks
|
|
530
|
+
# Remove expired tracks (same gap semantics as the viability filter:
|
|
531
|
+
# keep a track while it could still be linked at the next frame).
|
|
520
532
|
active_tracks = {tid: info for tid, info in active_tracks.items()
|
|
521
|
-
if t - info[2] <= max_gap_frames}
|
|
533
|
+
if t - info[2] <= max_gap_frames + 1}
|
|
522
534
|
|
|
523
535
|
return df
|
|
524
536
|
|