pycat-napari 1.5.330__tar.gz → 1.5.332__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.
Files changed (168) hide show
  1. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/CHANGELOG.md +80 -0
  2. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/PKG-INFO +1 -1
  3. pycat_napari-1.5.332/docs/audits/DEV_NOTES.md +157 -0
  4. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/development/roadmap.rst +63 -0
  5. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/pyproject.toml +1 -1
  6. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/run_pycat.py +10 -0
  7. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/analysis_plots.py +13 -1
  8. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/condensate_physics_tools.py +330 -4
  9. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/vpt_tools.py +25 -27
  10. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/vpt_ui.py +127 -11
  11. pycat_napari-1.5.332/src/pycat/ui/coordinate_readout.py +134 -0
  12. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/.gitignore +0 -0
  13. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/CONTRIBUTING.md +0 -0
  14. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/LICENSE +0 -0
  15. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/README.md +0 -0
  16. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/THIRD_PARTY_LICENSES.txt +0 -0
  17. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/pycat-devbio-napari-env-arm-mac.yaml +0 -0
  18. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/pycat-devbio-napari-env-x86-windows.yaml +0 -0
  19. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/pycat-napari-env-arm-mac.yaml +0 -0
  20. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/pycat-napari-env-x86-windows.yaml +0 -0
  21. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/requirements-arm-mac.txt +0 -0
  22. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/requirements-base.txt +0 -0
  23. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/requirements-devbio-napari-arm-mac.txt +0 -0
  24. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/config/requirements-devbio-napari.txt +0 -0
  25. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/Makefile +0 -0
  26. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/audits/PyCAT_method_audit_2026-07-09.md +0 -0
  27. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/audits/PyCAT_napari_integration_audit_2026-07-09.md +0 -0
  28. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/logos/pycat_logo-2.png +0 -0
  29. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/logos/pycat_logo.png +0 -0
  30. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/logos/pycat_logo_1024.png +0 -0
  31. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/logos/pycat_logo_256.png +0 -0
  32. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/logos/pycat_logo_512.png +0 -0
  33. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/make.bat +0 -0
  34. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/requirements.txt +0 -0
  35. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/dark_mode.css +0 -0
  36. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/examples/Image 1 dapi.tif +0 -0
  37. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/examples/Image 1.tif +0 -0
  38. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/pycat_logo_512.png +0 -0
  39. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/screenshots/Viewer_and_menu_highlights.png +0 -0
  40. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/screenshots/cell_analyzer.png +0 -0
  41. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/screenshots/condensate_segmentation.png +0 -0
  42. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/screenshots/measuring_lines.png +0 -0
  43. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/screenshots/opened_image_in_viewer.png +0 -0
  44. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/screenshots/preprocessed_images.png +0 -0
  45. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_static/screenshots/save_and_clear_popup.png +0 -0
  46. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/_templates/autosummary/module.rst +0 -0
  47. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/index.rst +0 -0
  48. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/pycat.central_manager.rst +0 -0
  49. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/pycat.data.rst +0 -0
  50. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/pycat.file_io.rst +0 -0
  51. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/pycat.run_pycat.rst +0 -0
  52. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/pycat.toolbox.rst +0 -0
  53. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/pycat.ui.rst +0 -0
  54. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/api/pycat.utils.rst +0 -0
  55. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/conf.py +0 -0
  56. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/development/contributing.rst +0 -0
  57. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/development/index.rst +0 -0
  58. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/development/support.rst +0 -0
  59. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/features.rst +0 -0
  60. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/index.rst +0 -0
  61. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/installation.rst +0 -0
  62. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/usage/index.rst +0 -0
  63. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/source/usage/tutorials/nuclear_condensate_analysis_gui_tutorial.rst +0 -0
  64. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/docs/test.txt +0 -0
  65. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/notebooks/Synthtic Data Generation NB.ipynb +0 -0
  66. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/notebooks/int_truncated_dfs.ipynb +0 -0
  67. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/notebooks/pycat_plotting.ipynb +0 -0
  68. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/__init__.py +0 -0
  69. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/batch_processor.py +0 -0
  70. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/batch_step_registry.py +0 -0
  71. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/central_manager.py +0 -0
  72. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/data/__init__.py +0 -0
  73. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/data/data_modules.py +0 -0
  74. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/file_io/__init__.py +0 -0
  75. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/file_io/file_io.py +0 -0
  76. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/file_io/frap_io.py +0 -0
  77. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/file_io/metadata_extract.py +0 -0
  78. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/file_io/multidim_io.py +0 -0
  79. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/file_io/session_loader.py +0 -0
  80. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/fix_tifffile.py +0 -0
  81. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/icons/pycat_logo-2.png +0 -0
  82. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/icons/pycat_logo.png +0 -0
  83. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/icons/pycat_logo_1024.png +0 -0
  84. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/icons/pycat_logo_256.png +0 -0
  85. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/icons/pycat_logo_512.png +0 -0
  86. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/__init__.py +0 -0
  87. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/advanced_analysis_ui.py +0 -0
  88. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/batch_roi_tools.py +0 -0
  89. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/benchmark_tools.py +0 -0
  90. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/brightfield_tools.py +0 -0
  91. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/brightfield_ui.py +0 -0
  92. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/clean_spot_detection_tools.py +0 -0
  93. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/condensate_physics_ui.py +0 -0
  94. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/contrast_cascade_tools.py +0 -0
  95. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/contrast_cascade_ui.py +0 -0
  96. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/correlation_func_analysis_tools.py +0 -0
  97. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/data_qc_tools.py +0 -0
  98. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/data_qc_ui.py +0 -0
  99. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/data_viz_tools.py +0 -0
  100. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/dynamic_spatial_tools.py +0 -0
  101. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/fd_curve_tools.py +0 -0
  102. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/fd_curve_ui.py +0 -0
  103. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/feature_analysis_tools.py +0 -0
  104. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/fft_bandpass_tools.py +0 -0
  105. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/fibril_tools.py +0 -0
  106. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/fibril_ui.py +0 -0
  107. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/frap_tools.py +0 -0
  108. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/frap_ui.py +0 -0
  109. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/fusion_tools.py +0 -0
  110. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/fusion_ui.py +0 -0
  111. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/gaussian_localization_tools.py +0 -0
  112. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/gpu_utils.py +0 -0
  113. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/image_processing_tools.py +0 -0
  114. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/intensity_profile_tools.py +0 -0
  115. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/invitro_bf_ui.py +0 -0
  116. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/invitro_fluor_ui.py +0 -0
  117. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/invitro_tools.py +0 -0
  118. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/label_and_mask_tools.py +0 -0
  119. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/layer_tools.py +0 -0
  120. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/molecular_counting_tools.py +0 -0
  121. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/morphological_complexity_tools.py +0 -0
  122. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/nb_tools.py +0 -0
  123. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/nb_ui.py +0 -0
  124. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/numba_utils.py +0 -0
  125. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/obj_based_coloc_analysis_tools.py +0 -0
  126. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/organizational_metrics_tools.py +0 -0
  127. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/partition_enrichment_tools.py +0 -0
  128. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/pipeline_diagnostic_tools.py +0 -0
  129. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/pipeline_snr_tools.py +0 -0
  130. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/pixel_wise_corr_analysis_tools.py +0 -0
  131. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/segmentation_tools.py +0 -0
  132. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/spatial_acf_tools.py +0 -0
  133. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/spatial_metrology_tools.py +0 -0
  134. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/spatial_metrology_ui.py +0 -0
  135. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/spatial_randomness_tools.py +0 -0
  136. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/spida_tools.py +0 -0
  137. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/spida_ui.py +0 -0
  138. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/temperature_tools.py +0 -0
  139. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/temperature_ui.py +0 -0
  140. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/temporal_enhancement_tools.py +0 -0
  141. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/timeseries_condensate_tools.py +0 -0
  142. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/timeseries_invitro_fluor_ui.py +0 -0
  143. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/timeseries_invitro_tools.py +0 -0
  144. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/topology_tools.py +0 -0
  145. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/trackmate_bridge.py +0 -0
  146. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/ts_cache_manager.py +0 -0
  147. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/ts_cellpose_tools.py +0 -0
  148. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/two_channel_coloc_tools.py +0 -0
  149. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/video_export_tools.py +0 -0
  150. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/zstack_segmentation_tools.py +0 -0
  151. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/toolbox/zstack_segmentation_ui.py +0 -0
  152. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/__init__.py +0 -0
  153. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/field_status.py +0 -0
  154. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_analysis_mixin.py +0 -0
  155. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_diagnostics_mixin.py +0 -0
  156. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_filtering_mixin.py +0 -0
  157. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_imageops_mixin.py +0 -0
  158. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_labels_mixin.py +0 -0
  159. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_modules.py +0 -0
  160. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_segmentation_mixin.py +0 -0
  161. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/ui_utils.py +0 -0
  162. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/ui/workflow_checklist.py +0 -0
  163. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/utils/__init__.py +0 -0
  164. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/utils/channel_naming.py +0 -0
  165. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/utils/general_utils.py +0 -0
  166. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/utils/logging_utils.py +0 -0
  167. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/src/pycat/utils/math_utils.py +0 -0
  168. {pycat_napari-1.5.330 → pycat_napari-1.5.332}/tests/README.md +0 -0
@@ -4,6 +4,86 @@ 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.332] - 2026-07-10
8
+ ### Fixed — VPT classifier green↔yellow flicker on bright, well-matched beads
9
+ - **A bright, high-NCC bead no longer flips singlet↔out_of_plane frame-to-frame.**
10
+ The out_of_plane (yellow) class used a per-frame amplitude/SNR percentile, so
11
+ when the bead population is uniformly low-quality a genuinely good bead sitting
12
+ near the moving percentile line was demoted ~a quarter of the time — driven
13
+ mainly by a `low-SNR OR` clause that could yellow a bead whose amplitude was
14
+ fine. Fix: (1) require the AMPLITUDE to actually be low for the dim class (SNR
15
+ is now only a secondary confirmation, never demotes a bright bead on its own),
16
+ and (2) add a high-NCC singlet guard (NCC ≥ 0.80) so a well-matched bead is
17
+ immune to the dim percentile. Verified on real data: the previously-flickering
18
+ bead (amp~164, NCC~0.94) is now singlet in 1000/1000 frames (was ~76%), while a
19
+ genuinely dim bead (amp~75, NCC~0.76) correctly STAYS out_of_plane — the garbage
20
+ rejection (NCC floor) and aggregate class are untouched. This preserves the
21
+ hard-won hot-pixel/ring/noise rejection while stopping the erroneous demotion of
22
+ real beads.
23
+
24
+ ### Added — MSD lag-window fit gate (hardware-defensible fit bounds)
25
+ - `fit_anomalous_diffusion` now computes a **defensible MSD lag window** bounded
26
+ by the frame rate (high-frequency cutoff = frame interval) and the acquisition
27
+ duration (low-frequency cutoff), and by default confines the D/α fit to it.
28
+ Fitting outside this band (only sub-second lags, dominated by the localization
29
+ floor, or out toward the full duration, where a handful of pairs dominate)
30
+ produces a wrong D/α. Exposed under the VPT "Show advanced fit / moduli options"
31
+ expander:
32
+ - **Upper-lag rule** (user-selectable, with tooltips): *Fraction of track length*
33
+ (default, 0.25), *Fixed frequency window* (set the upper lag in seconds), or
34
+ *Minimum independent pairs* (keep a lag only while ≥ N independent tracks span
35
+ it).
36
+ - **"Confine fit to scientifically defensible bounds"** toggle (default ON) —
37
+ clips the fit to the window; turn off to fit the full range at your own risk.
38
+ - The gate **warns, never blocks**: if the acquisition can't cover the requested
39
+ window (too-short clip), it emits a clear warning and falls back gracefully.
40
+ Validated on real data across all three rules + the confine toggle + the
41
+ too-short-data warning path.
42
+
43
+ ## [1.5.331] - 2026-07-10
44
+ ### Added — Evans (2009) viscoelastic moduli + bootstrap confidence bands
45
+ - **G′/G″ (storage/loss moduli) now use the Evans et al. (2009) direct
46
+ compliance→moduli conversion** (`compute_moduli_evans` in
47
+ condensate_physics_tools.py), replacing the Mason (2000) single-point algebraic
48
+ GSER in the VPT pipeline. Evans represents the creep compliance J(t) as a
49
+ piecewise-linear interpolant and analytically Fourier-transforms it, so
50
+ G*(ω)=1/(iω·J̃(ω)) with **no local-power-law assumption** — it handles
51
+ curvature, plateaus, and crossovers directly. Validated in-sandbox against
52
+ known analytic MSDs: exact on a pure viscous fluid (G′≈0, G″=ηω to machine
53
+ precision) and ~1–2% on a Maxwell fluid across the reliable band. The highest
54
+ one or two frequencies (shortest lags) are the least reliable and are dropped.
55
+ The Mason `compute_moduli_gser` is retained (additive/revertable).
56
+ - **Optional bootstrap confidence intervals on G′/G″**
57
+ (`compute_moduli_evans_bootstrap`), exposed under a new hidden "Show advanced
58
+ moduli (G′/G″) options" expander in the VPT Step-5 panel (default off). Resamples
59
+ whole tracks with replacement, recomputes moduli per resample, and shades
60
+ percentile bands on the plot (`plot_moduli` draws bands when present). Validated
61
+ in-sandbox: ~93–97% empirical coverage of a known analytic truth for a nominal
62
+ 95% band. This is the honest response to noisy data — it shows which parts of
63
+ the spectrum to trust.
64
+ - NOTE: a compliance-interpolation upgrade (natural/Akima spline) was evaluated
65
+ and **rejected** — validated as a no-op on smooth MSDs and unhelpful (can worsen
66
+ jitter) on noisy ones; the real levers for noise are the CIs above plus upstream
67
+ trajectory cleanup. Documented as such in the code.
68
+
69
+ ### Added — dual pixel/µm coordinate readout
70
+ - **The napari status bar now shows both the pixel index (r, c) and the world
71
+ (µm) position under the cursor**, plus the value under the cursor, e.g.
72
+ `px (r=362, c=483) | µm (y=242.5, x=323.6) | Bead Detections = 171`
73
+ (`pycat/ui/coordinate_readout.py`, installed at launch in run_pycat.py). PyCAT
74
+ scales image layers by pixel size (µm/px), so napari's default status showed
75
+ microns only; pixel indices are what the analysis actually runs in (blob sigma,
76
+ linking distances, template windows, FIJI cross-referencing), so both are now
77
+ surfaced. Best-effort and fail-safe — never blocks launch, and leaves napari's
78
+ default status untouched if the coordinate can't be resolved.
79
+
80
+ ### Docs
81
+ - Added a "Near-term UX & interaction" section to the development roadmap
82
+ (frame-0-on-load, materialization progress, pixel-size acquisition profiles,
83
+ command palette, plot↔layer brushing, dual px/µm readout).
84
+ - Added `docs/audits/DEV_NOTES.md` (private, Sphinx-excluded): instrument-scoped
85
+ module roadmap and known-issues detail kept out of the published docs.
86
+
7
87
  ## [1.5.208] - 2026-07-05
8
88
  ### Fixed (overlay stripe — the ACTUAL root cause: a scale mismatch)
9
89
  - **The Overlay Image now inherits the source image layer's scale.** Confirmed via git
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycat-napari
3
- Version: 1.5.330
3
+ Version: 1.5.332
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
@@ -0,0 +1,157 @@
1
+ # PyCAT — Private Development Notes
2
+
3
+ > **PRIVATE / NOT PUBLISHED.** This file lives in `docs/audits/` which is *outside*
4
+ > the Sphinx source tree (`docs/source/`) and is not in any `toctree`, so it is never
5
+ > built into the public documentation. It intentionally contains lab-specific detail
6
+ > (instrument inventory, hardware-gated scoping, machine/collaborator-specific bug
7
+ > notes) that must **not** appear in anything scraped or shown externally. Keep
8
+ > equipment names and internal scoping here, not in `roadmap.rst`.
9
+
10
+ ---
11
+
12
+ ## 1. Lab / instrument base (scoping reference — keep private)
13
+
14
+ Informs which advanced analysis modules are worth building; scope modules to real
15
+ hardware. **Do not list this equipment in published docs.**
16
+
17
+ - **LUMICKS C-TRAP** — optical-tweezers + confocal, 3 lasers. Source instrument for
18
+ the existing FRAP / droplet-fusion / force-distance modules; Lumicks `.h5` files.
19
+ - **ISS Q2** — laser-scanning confocal with APDs on 3 channels; does FLIM and
20
+ point-detector FCS/FCCS. Native instrument for single-point FCS/FCCS and FLIM.
21
+ - **Andor Dragonfly** — spinning-disk confocal with TIRF/HILO, Micropoint, Mosaic,
22
+ two pinhole discs (25 & 40 µm). Two cameras: Andor iXon 888 EMCCD (1024×1024,
23
+ back-illuminated) and Andor Zyla sCMOS; both fast (~1000 fps with cropping). For
24
+ camera-FCS the **Zyla (sCMOS)** is correct (no EM gain, well-characterized per-pixel
25
+ noise); the iXon EMCCD is weaker for FCS (EM gain adds multiplicative excess noise
26
+ ~√2 on variance). Dragonfly TIRF/HILO gives a defined thin axial volume, so
27
+ **Dragonfly TIRF/HILO + Zyla is a viable present-day imaging/camera-FCS testbed**
28
+ (spinning-disk is a messier volume model). Unconfirmed: can Dragonfly TIRF route to
29
+ the Zyla port? sCMOS imaging-FCS also needs a per-pixel offset/gain/variance
30
+ calibration map (the N&B documented hook).
31
+ - **Leica Stellaris** (campus access) with LIGHTNING deconvolution + a STED path.
32
+ - **Zeiss Airyscan 2** — incoming access (super-resolution detector-array confocal).
33
+ - **Photometrics Kinetix sCMOS** — currently on a Zeiss Axio Observer with LED
34
+ widefield (epi, no defined axial slice → not ideal for FCS). Future: Kinetix moves
35
+ to a custom ring-TIRF/HILO scope, with planned PolScope (polarization/birefringence
36
+ orientation) and FLIM on the other illumination path.
37
+ - Confocal imaging source for the 2D/TS condensate pipelines: Zeiss/ZEN Plan-Apo
38
+ 63×/1.40 Oil, 405 + Argon 488, 3 PMTs, 0.0264 µm/px, DAPI/EGFP/transmitted.
39
+
40
+ **Implications:** single-point FCS/FCCS and FLIM are native to the ISS Q2 (PyCAT does
41
+ phasor/lifetime *downstream* analysis + import, not raw TCSPC); PolScope/orientation
42
+ pairs with the future Kinetix polarization path.
43
+
44
+ ---
45
+
46
+ ## 2. Advanced spectroscopy / imaging module roadmap (hardware-scoped)
47
+
48
+ All are **import-and-analyze** modules: PyCAT quantifies what the specialized
49
+ instrument produces; it does not reimplement acquisition. Ordered by data-availability.
50
+
51
+ **Buildable now (data exists today):**
52
+
53
+ - **FCS/FCCS analysis module** — native to the ISS Q2 (APDs, 3 channels). Import
54
+ point-detector correlation curves / photon streams; fit diffusion models
55
+ (single/multi-component, triplet, anomalous); FCCS cross-correlation amplitude ratio
56
+ → bound fraction. Composes with the fluctuation-spectroscopy family (MSD/VPT
57
+ viscosity, N&B, SpIDA). *Prereq:* confirm what the Q2 exports (correlation curves vs
58
+ raw photon stream vs `.fcs`). Extend `correlation_func_analysis_tools.py` (already
59
+ has spatial ACF/CCF + Gaussian-peak fitting, ICS-style); N&B (`nb_tools.py`) already
60
+ flags per-pixel sCMOS variance/offset correction.
61
+ - **FLIM phasor + downstream module** — native to ISS Q2. Import-based (no raw TCSPC).
62
+ Import lifetime/decay → phasor-plot analysis (model-free lifetime separation) →
63
+ segmentation-linked biology (per-condensate mean lifetime, lifetime vs partition
64
+ coefficient, lifetime shift across a phase transition). The distinctive "PyCAT owns
65
+ the downstream biology" play.
66
+ - **RICS / STICS** (raster & spatiotemporal image correlation spectroscopy) —
67
+ highest-leverage near-term. Works on current laser-scanning confocals (ISS Q2,
68
+ C-Trap) with no new hardware; extracts diffusion maps AND flow/velocity fields.
69
+ Reuses the existing spatial-correlation backend. Smaller lift than camera
70
+ imaging-FCS. *Prereq:* confirm the Q2 / C-Trap scanned-image-series export format +
71
+ whether pixel dwell / line time is in metadata (RICS depends on scan timing).
72
+
73
+ **Future (hardware-gated):**
74
+
75
+ - **Imaging / multipoint camera-FCS** — flagship but future. Tie to the Kinetix's
76
+ future ring-TIRF/HILO scope, NOT the current Axio Observer + LED widefield (no
77
+ defined axial slice → per-pixel FCS volume not well-posed). Per-pixel temporal
78
+ autocorrelation of a fast sCMOS stream → diffusion/concentration maps. Hard parts:
79
+ per-pixel sCMOS noise/variance/offset correction, frame-timing calibration,
80
+ bleaching, TIRF/HILO axial volume model.
81
+ - **PolScope / orientation analysis** — future, pairs with the Kinetix polarization
82
+ path. Import orientation/birefringence/anisotropy maps → orientational order
83
+ parameters, anisotropy distributions, orientation-vs-condensate-structure.
84
+ - **SMLM / localization-table analysis** — three super-res-capable instruments
85
+ (Dragonfly TIRF single-molecule, campus STED, incoming Airyscan 2) but zero
86
+ localization-table analysis today. Import localization tables (PALM/STORM/PAINT);
87
+ the Ripley/PCF cluster-analysis machinery already exists and applies directly; add
88
+ localization precision + drift correction. LOCAN ecosystem interop lands here.
89
+ - **Fluorescence anisotropy / homo-FRET** (steady-state polarization) — precursor to
90
+ PolScope; buildable sooner if any current instrument has a parallel/perpendicular
91
+ channel pair. Two-channel ratiometric-style computation.
92
+
93
+ *Caveat for all:* some capabilities are inferred from instrument class — confirm the
94
+ specific unit configuration (does the Dragonfly config do true SMLM? does any current
95
+ instrument have polarization optics installed?) before committing.
96
+
97
+ ---
98
+
99
+ ## 3. Known issues (may name specific machines/configs — keep private)
100
+
101
+ ### GPU / OpenGL canvas corruption on some NVIDIA configs (ACTIVE, not resolved)
102
+
103
+ **Symptom:** after loading an image, clicking the canvas renders the view
104
+ tilted/sheared (diagonal split); scroll/zoom still work (input + data fine — a
105
+ display/framebuffer-presentation problem). Earlier empty-canvas clicks showed
106
+ triangular tearing / swirling moiré + UI vanishing. Constant flickering appears only
107
+ on dim/out-of-focus objects.
108
+
109
+ **Confirmed NOT a PyCAT bug** — reproduces in plain napari (no PyCAT).
110
+
111
+ **Environment where seen** (collaborator machine, NVIDIA T400 4GB): Win11, Python 3.12,
112
+ napari 0.7.1, vispy 0.16.2, Qt 5.15.2/PyQt5, **NVIDIA driver 595.97**, OpenGL 4.6,
113
+ 1920×1080 @ 100% single monitor, 75Hz HDMI. Ruled out (via `gpu_diag.py`):
114
+ wrong-GPU-selection, integrated graphics, Qt high-DPI scaling, multi-monitor.
115
+
116
+ **Three OpenGL backends all fail differently:** native NVIDIA → tearing/tilt on click;
117
+ `QT_OPENGL=angle` → crashes at startup (GLError 1282 on `glGetParameter(GL_MAX_TEXTURE_SIZE)`,
118
+ GL context broken at creation); `LIBGL_ALWAYS_SOFTWARE=1` → opens clean but slow to
119
+ start, then tears after repeated clicks.
120
+
121
+ **Prime suspect:** NVIDIA driver 595.97 (newest; only recently-changed variable; a
122
+ tilt/shear = framebuffer stride/row-alignment presentation bug — a classic driver-build
123
+ regression that hits OpenGL apps while leaving the desktop compositor fine).
124
+
125
+ **Next steps (awaiting):** clear env vars (`set QT_OPENGL=` / `set LIBGL_ALWAYS_SOFTWARE=`),
126
+ roll back the NVIDIA driver to the prior Studio branch (clean-install checkbox), reboot,
127
+ retest plain napari + load image + click/scroll. Open question: is this the only machine
128
+ affected, or do others on the same napari/vispy fail? (only → isolate this box's
129
+ GPU/driver, rollback is the fix; several → consider pinning napari/vispy.)
130
+
131
+ **When the fix is confirmed:** write a *public-facing* known-issues note (symptom →
132
+ confirm via plain napari → `gpu_diag.py` → resolution = driver rollback; software
133
+ rendering as an imperfect last resort). A possible PyCAT `--safe-rendering` launch flag
134
+ (sets `LIBGL_ALWAYS_SOFTWARE` before napari init) is opt-in first, but software
135
+ rendering was not fully stable here (tore after repeated clicks) so it's an imperfect
136
+ stopgap, not a clean fix. `gpu_diag.py` delivered (one-shot GPU/OpenGL/Qt/scaling report
137
+ + opens plain napari for the reproduce test).
138
+
139
+ ### Multi-file OME-TIFF with a missing linked member (hardened 1.5.330)
140
+
141
+ A multi-file OME-TIFF that references a missing sibling (e.g. a `...MMStack_Pos0.ome.tif`
142
+ referencing an absent later-timepoint file) makes the loader zero/truncate the missing
143
+ data, and a degenerate 1-D frame could reach `score_beads_template`, crashing with
144
+ `ValueError: not enough values to unpack (expected 2, got 1)`. 1.5.330 guards this
145
+ (squeeze + skip frame with a warning). Root fix for a *complete* analysis: ensure all
146
+ linked `.ome.tif` files are present, or use a self-contained single-file export.
147
+
148
+ ---
149
+
150
+ ## 4. VPT calibrated-thermodynamics scoping notes (lab-specific framing)
151
+
152
+ The calibrated intensity → concentration → ΔG_transfer workflow (see public roadmap for
153
+ the capability description) is scoped against the lab's Csat / phase-diagram /
154
+ quantitative-measurement program. This is the flagship manuscript differentiator:
155
+ converts PyCAT from "image analysis" to "biophysical parameter extraction." PyCAT today
156
+ has intensity-based ratios (partition coefficient, client enrichment) but zero
157
+ `delta_g` / standard-curve-concentration code — that gap is the build.
@@ -396,6 +396,69 @@ supporting Category B, because PyCAT's point-based spatial statistics are alread
396
396
  what localization-cluster analysis needs.
397
397
 
398
398
 
399
+ Near-term UX & interaction
400
+ --------------------------
401
+
402
+ Small, mostly self-contained quality-of-life items that improve responsiveness and
403
+ keep the scientist engaged with their data. None are architectural; each can ship
404
+ independently.
405
+
406
+ .. rubric:: Default to the first frame on load
407
+
408
+ Most image viewers open a stack on frame 0; PyCAT currently opens on the middle
409
+ frame. Change the default so a freshly loaded stack shows frame 0 (set the viewer's
410
+ current step on the T axis to 0 after load), matching viewer convention.
411
+
412
+ .. rubric:: Materialization progress on stack-consuming methods
413
+
414
+ Where a method must read/decode a whole stack before working (e.g. bead detection),
415
+ the progress indication should read as one continuous 0→100% pass rather than
416
+ reaching 100% twice (once for materialization, once for the work). The reusable
417
+ ``PhasedProgress`` helper already exists; the remaining work is rolling it out to the
418
+ other stack-consuming workflows so a materialization wait is always labelled and never
419
+ double-counts. Useful app-wide, since materialization is a common shared wait.
420
+
421
+ .. rubric:: Pixel-size acquisition profiles
422
+
423
+ Users repeatedly image files from the same microscope with the same missing-metadata
424
+ flaw (no pixel size, often no magnification either), so re-entering the scale every
425
+ load is friction. The robust design is **named acquisition profiles**: the user
426
+ creates and names a profile (storing its pixel size), saved to a small JSON on disk,
427
+ and selects it (or it is remembered as default) at load time. This sidesteps the
428
+ metadata problem by having the human supply the key the file cannot. When camera +
429
+ magnification *are* present in metadata, auto-fill the pixel size as a bonus. Scoped
430
+ as an additive picker on the existing load-time pixel-size dialog, composing with the
431
+ existing "persist through session" option — not a rewrite. (Metadata-only
432
+ auto-recovery was considered and rejected as the primary mechanism, because the exact
433
+ scopes this targets omit the metadata needed to compute the scale.)
434
+
435
+ .. rubric:: Command palette / search bar
436
+
437
+ A search bar (command-palette pattern, à la VS Code Ctrl+Shift+P or Spotlight) to
438
+ find and jump to functionality by name, in three scopes of increasing difficulty:
439
+ (1) open a method/widget by name — easy, a fuzzy filter over the existing
440
+ analysis-method registry calling the same launch function the menu does; (2) find a
441
+ layer by name — trivial, a thin wrapper over the viewer's layer list; (3) find a
442
+ step/process within a widget by name — harder, requires steps to be enumerable and
443
+ addressable (name → widget + the control that runs it + a scroll-to/highlight). Ship
444
+ 1 + 2 first as a simple palette; extend to steps once step-addressing infrastructure
445
+ firms up (the same "steps as first-class addressable things" requirement also serves
446
+ the pipeline-step-diagnostics dropdown and the linked-navigation object model).
447
+
448
+ .. rubric:: VPT/MSD plot ↔ layer brushing (first instance of linked navigation)
449
+
450
+ A concrete, near-term instance of the linked multiscale navigation idea (see the
451
+ biological object model section): click a trajectory in the MSD plot → highlight that
452
+ bead and its track in the canvas and surface its data row, so browsing the plot leads
453
+ back to the data in the image. This is a small build for VPT specifically because the
454
+ identity plumbing already exists end-to-end — every MSD line carries a track id, and
455
+ the tracks layer holds those trajectories keyed by the same id. The missing piece is
456
+ narrow: make the (currently static) MSD plot pickable, map the picked line → track id,
457
+ then select/centre that track in the viewer and surface its row. Once proven here it
458
+ generalizes to the other plots (partition-coefficient scatter → condensate;
459
+ enrichment plot → cell).
460
+
461
+
399
462
  Calibrated Thermodynamic & Quantitative Condensate Reporting
400
463
  ------------------------------------------------------------
401
464
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pycat-napari"
7
- version = "1.5.330"
7
+ version = "1.5.332"
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"
@@ -322,6 +322,16 @@ def run_pycat_func():
322
322
  # be skipped entirely by setting PYCAT_SKIP_WARMUP=1.
323
323
  viewer = napari.Viewer(title="PyCAT-Napari")
324
324
 
325
+ # Dual pixel / micron coordinate readout in the status bar. PyCAT scales
326
+ # layers by pixel size (µm/px), so napari's default status shows microns
327
+ # only; this surfaces the raw pixel index alongside it (px is what the
328
+ # analysis runs in). Best-effort — never blocks launch.
329
+ try:
330
+ from pycat.ui.coordinate_readout import install_coordinate_readout
331
+ install_coordinate_readout(viewer)
332
+ except Exception as _e:
333
+ print(f"[PyCAT] Coordinate readout not installed: {_e}")
334
+
325
335
  if os.environ.get('PYCAT_SKIP_WARMUP', '') not in ('1', 'true', 'True'):
326
336
  import threading
327
337
  def _warmup():
@@ -97,7 +97,7 @@ def plot_moduli(moduli_df, title="Viscoelastic moduli (microrheology)",
97
97
  interactive=True):
98
98
  """
99
99
  Log-log plot of storage G'(ω) and loss G''(ω) vs angular frequency, from
100
- compute_moduli_gser(). The crossover (G'=G'') marks the viscoelastic
100
+ compute_moduli_evans() (or compute_moduli_gser()). The crossover (G'=G'') marks the viscoelastic
101
101
  relaxation frequency.
102
102
  """
103
103
  import matplotlib
@@ -114,6 +114,18 @@ def plot_moduli(moduli_df, title="Viscoelastic moduli (microrheology)",
114
114
  w = d['omega_rad_s'].values
115
115
  gp = d['g_prime_pa'].values
116
116
  gpp = d['g_double_prime_pa'].values
117
+
118
+ # Optional bootstrap confidence bands (drawn only if the columns are present,
119
+ # produced by compute_moduli_evans_bootstrap). Shaded region behind the lines.
120
+ if {'g_prime_lo', 'g_prime_hi'}.issubset(d.columns):
121
+ ax.fill_between(w, np.clip(d['g_prime_lo'].values, 1e-12, None),
122
+ np.clip(d['g_prime_hi'].values, 1e-12, None),
123
+ color='#c44e52', alpha=0.18, linewidth=0)
124
+ if {'g_double_prime_lo', 'g_double_prime_hi'}.issubset(d.columns):
125
+ ax.fill_between(w, np.clip(d['g_double_prime_lo'].values, 1e-12, None),
126
+ np.clip(d['g_double_prime_hi'].values, 1e-12, None),
127
+ color='#4c72b0', alpha=0.18, linewidth=0)
128
+
117
129
  # only positive values are meaningful on log axes
118
130
  ax.plot(w, np.clip(gp, 1e-12, None), '-o', ms=4, color='#c44e52',
119
131
  label="G′ (storage / elastic)")