celldetective 1.5.0b9__tar.gz → 1.5.0b10__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 (204) hide show
  1. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/PKG-INFO +1 -1
  2. celldetective-1.5.0b10/celldetective/_version.py +1 -0
  3. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_measurements.py +10 -2
  4. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/viewers/spot_detection_viewer.py +14 -0
  5. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/measure.py +11 -11
  6. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/data_cleaning.py +7 -3
  7. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective.egg-info/PKG-INFO +1 -1
  8. celldetective-1.5.0b10/tests/gui/test_spot_detection_viewer.py +394 -0
  9. celldetective-1.5.0b10/tests/test_measure.py +243 -0
  10. celldetective-1.5.0b9/celldetective/_version.py +0 -1
  11. celldetective-1.5.0b9/tests/gui/test_spot_detection_viewer.py +0 -187
  12. celldetective-1.5.0b9/tests/test_measure.py +0 -141
  13. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/LICENSE +0 -0
  14. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/README.md +0 -0
  15. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/__init__.py +0 -0
  16. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/__main__.py +0 -0
  17. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/datasets/segmentation_annotations/blank +0 -0
  18. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/datasets/signal_annotations/blank +0 -0
  19. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/event_detection_models.py +0 -0
  20. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/events.py +0 -0
  21. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/exceptions.py +0 -0
  22. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/extra_properties.py +0 -0
  23. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/filters.py +0 -0
  24. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/InitWindow.py +0 -0
  25. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/__init__.py +0 -0
  26. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/about.py +0 -0
  27. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/analyze_block.py +0 -0
  28. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/__init__.py +0 -0
  29. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/channel_norm_generator.py +0 -0
  30. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/components.py +0 -0
  31. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/feature_choice.py +0 -0
  32. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/figure_canvas.py +0 -0
  33. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/list_widget.py +0 -0
  34. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/styles.py +0 -0
  35. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base/utils.py +0 -0
  36. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/base_annotator.py +0 -0
  37. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/classifier_widget.py +0 -0
  38. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/configure_new_exp.py +0 -0
  39. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/control_panel.py +0 -0
  40. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/dynamic_progress.py +0 -0
  41. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/event_annotator.py +0 -0
  42. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/generic_signal_plot.py +0 -0
  43. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/gui_utils.py +0 -0
  44. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
  45. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
  46. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/cell-populations.json +0 -0
  47. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/exp-structure.json +0 -0
  48. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/feature-btrack.json +0 -0
  49. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/neighborhood.json +0 -0
  50. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
  51. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/preprocessing.json +0 -0
  52. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/propagate-classification.json +0 -0
  53. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/track-postprocessing.json +0 -0
  54. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/help/tracking.json +0 -0
  55. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/interactions_block.py +0 -0
  56. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/interactive_timeseries_viewer.py +0 -0
  57. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/json_readers.py +0 -0
  58. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/layouts/__init__.py +0 -0
  59. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/layouts/background_model_free_layout.py +0 -0
  60. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/layouts/channel_offset_layout.py +0 -0
  61. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/layouts/local_correction_layout.py +0 -0
  62. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/layouts/model_fit_layout.py +0 -0
  63. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/layouts/operation_layout.py +0 -0
  64. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/layouts/protocol_designer_layout.py +0 -0
  65. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/measure_annotator.py +0 -0
  66. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/pair_event_annotator.py +0 -0
  67. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/plot_measurements.py +0 -0
  68. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/plot_signals_ui.py +0 -0
  69. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/preprocessing_block.py +0 -0
  70. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/process_block.py +0 -0
  71. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/seg_model_loader.py +0 -0
  72. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/__init__.py +0 -0
  73. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_cellpose_model_params.py +0 -0
  74. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_event_detection_model_params.py +0 -0
  75. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_segmentation_model_params.py +0 -0
  76. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_base.py +0 -0
  77. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_event_model_training.py +0 -0
  78. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_neighborhood.py +0 -0
  79. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_segmentation.py +0 -0
  80. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_segmentation_model_training.py +0 -0
  81. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_signal_annotator.py +0 -0
  82. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_settings_tracking.py +0 -0
  83. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/settings/_stardist_model_params.py +0 -0
  84. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/survival_ui.py +0 -0
  85. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/tableUI.py +0 -0
  86. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/table_ops/__init__.py +0 -0
  87. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/table_ops/_maths.py +0 -0
  88. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/table_ops/_merge_groups.py +0 -0
  89. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/table_ops/_merge_one_hot.py +0 -0
  90. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/table_ops/_query_table.py +0 -0
  91. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/table_ops/_rename_col.py +0 -0
  92. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/thresholds_gui.py +0 -0
  93. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/viewers/__init__.py +0 -0
  94. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/viewers/base_viewer.py +0 -0
  95. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/viewers/channel_offset_viewer.py +0 -0
  96. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/viewers/contour_viewer.py +0 -0
  97. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/viewers/size_viewer.py +0 -0
  98. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/viewers/threshold_viewer.py +0 -0
  99. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/gui/workers.py +0 -0
  100. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/logo-large.png +0 -0
  101. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/logo.png +0 -0
  102. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/signals_icon.png +0 -0
  103. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/splash-test.png +0 -0
  104. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/splash.png +0 -0
  105. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/splash0.png +0 -0
  106. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/survival2.png +0 -0
  107. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/vignette_signals2.png +0 -0
  108. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/icons/vignette_signals2.svg +0 -0
  109. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/links/zenodo.json +0 -0
  110. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/log_manager.py +0 -0
  111. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/pair_signal_detection/blank +0 -0
  112. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/segmentation_effectors/blank +0 -0
  113. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/segmentation_generic/blank +0 -0
  114. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/segmentation_targets/blank +0 -0
  115. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/signal_detection/blank +0 -0
  116. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/tracking_configs/biased_motion.json +0 -0
  117. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/tracking_configs/mcf7.json +0 -0
  118. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
  119. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/tracking_configs/ricm.json +0 -0
  120. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/models/tracking_configs/ricm2.json +0 -0
  121. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/napari/__init__.py +0 -0
  122. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/napari/utils.py +0 -0
  123. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/neighborhood.py +0 -0
  124. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/preprocessing.py +0 -0
  125. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/__init__.py +0 -0
  126. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/background_correction.py +0 -0
  127. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/compute_neighborhood.py +0 -0
  128. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/detect_events.py +0 -0
  129. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/downloader.py +0 -0
  130. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/load_table.py +0 -0
  131. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/measure_cells.py +0 -0
  132. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/segment_cells.py +0 -0
  133. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/track_cells.py +0 -0
  134. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/train_segmentation_model.py +0 -0
  135. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/train_signal_model.py +0 -0
  136. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/processes/unified_process.py +0 -0
  137. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/regionprops/__init__.py +0 -0
  138. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/regionprops/_regionprops.py +0 -0
  139. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/regionprops/props.json +0 -0
  140. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/relative_measurements.py +0 -0
  141. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/analyze_signals.py +0 -0
  142. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/measure_cells.py +0 -0
  143. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/measure_relative.py +0 -0
  144. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/segment_cells.py +0 -0
  145. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/segment_cells_thresholds.py +0 -0
  146. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/track_cells.py +0 -0
  147. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/train_segmentation_model.py +0 -0
  148. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/scripts/train_signal_model.py +0 -0
  149. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/segmentation.py +0 -0
  150. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/signals.py +0 -0
  151. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/tracking.py +0 -0
  152. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/__init__.py +0 -0
  153. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/cellpose_utils/__init__.py +0 -0
  154. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/color_mappings.py +0 -0
  155. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/data_loaders.py +0 -0
  156. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/dataset_helpers.py +0 -0
  157. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/downloaders.py +0 -0
  158. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/event_detection/__init__.py +0 -0
  159. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/experiment.py +0 -0
  160. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/image_augmenters.py +0 -0
  161. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/image_cleaning.py +0 -0
  162. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/image_loaders.py +0 -0
  163. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/image_transforms.py +0 -0
  164. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/io.py +0 -0
  165. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/mask_cleaning.py +0 -0
  166. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/mask_transforms.py +0 -0
  167. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/masks.py +0 -0
  168. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/maths.py +0 -0
  169. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/model_getters.py +0 -0
  170. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/model_loaders.py +0 -0
  171. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/normalization.py +0 -0
  172. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/parsing.py +0 -0
  173. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/plots/__init__.py +0 -0
  174. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/plots/regression.py +0 -0
  175. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/resources.py +0 -0
  176. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/stardist_utils/__init__.py +0 -0
  177. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/stats.py +0 -0
  178. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective/utils/types.py +0 -0
  179. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective.egg-info/SOURCES.txt +0 -0
  180. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective.egg-info/dependency_links.txt +0 -0
  181. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective.egg-info/entry_points.txt +0 -0
  182. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective.egg-info/not-zip-safe +0 -0
  183. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective.egg-info/requires.txt +0 -0
  184. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/celldetective.egg-info/top_level.txt +0 -0
  185. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/setup.cfg +0 -0
  186. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/setup.py +0 -0
  187. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/__init__.py +0 -0
  188. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/gui/__init__.py +0 -0
  189. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/gui/test_enhancements.py +0 -0
  190. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/gui/test_measure_annotator_bugfix.py +0 -0
  191. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/gui/test_new_project.py +0 -0
  192. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/gui/test_project.py +0 -0
  193. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_cellpose_fallback.py +0 -0
  194. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_events.py +0 -0
  195. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_filters.py +0 -0
  196. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_io.py +0 -0
  197. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_neighborhood.py +0 -0
  198. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_notebooks.py +0 -0
  199. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_partial_install.py +0 -0
  200. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_preprocessing.py +0 -0
  201. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_segmentation.py +0 -0
  202. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_signals.py +0 -0
  203. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_tracking.py +0 -0
  204. {celldetective-1.5.0b9 → celldetective-1.5.0b10}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: celldetective
3
- Version: 1.5.0b9
3
+ Version: 1.5.0b10
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -0,0 +1 @@
1
+ __version__ = "1.5.0b10"
@@ -838,7 +838,6 @@ class SettingsMeasurements(CelldetectiveSettingsPanel):
838
838
  self.imshow_digit_window.canvas.draw()
839
839
  self.imshow_digit_window.show()
840
840
 
841
-
842
841
  def control_haralick_intensity_histogram(self):
843
842
  """
844
843
  Load an image for the first experiment movie found.
@@ -1123,7 +1122,9 @@ class SettingsMeasurements(CelldetectiveSettingsPanel):
1123
1122
  # else:
1124
1123
  # invert_value = None
1125
1124
 
1126
- from celldetective.gui.viewers.spot_detection_viewer import SpotDetectionVisualizer
1125
+ from celldetective.gui.viewers.spot_detection_viewer import (
1126
+ SpotDetectionVisualizer,
1127
+ )
1127
1128
 
1128
1129
  self.spot_visual = SpotDetectionVisualizer(
1129
1130
  frame_slider=True,
@@ -1139,6 +1140,13 @@ class SettingsMeasurements(CelldetectiveSettingsPanel):
1139
1140
  parent_diameter_le=self.diameter_value,
1140
1141
  parent_threshold_le=self.threshold_value,
1141
1142
  parent_preprocessing_list=self.spot_preprocessing.list,
1143
+ initial_diameter=self.diameter_value.text(),
1144
+ initial_threshold=self.threshold_value.text(),
1145
+ initial_preprocessing=(
1146
+ self.spot_preprocessing.list.items
1147
+ if self.spot_preprocessing.list.items
1148
+ else None
1149
+ ),
1142
1150
  # parent_invert_check=self.invert_check,
1143
1151
  # invert = self.invert_check.isChecked(),
1144
1152
  # invert_value = self.invert_value_le.text().replace(',','.'),
@@ -43,6 +43,9 @@ class SpotDetectionVisualizer(StackVisualizer):
43
43
  parent_preprocessing_list=None,
44
44
  cell_type="targets",
45
45
  labels=None,
46
+ initial_diameter=None,
47
+ initial_threshold=None,
48
+ initial_preprocessing=None,
46
49
  *args,
47
50
  **kwargs,
48
51
  ):
@@ -113,6 +116,17 @@ class SpotDetectionVisualizer(StackVisualizer):
113
116
  min(self.target_channel, self.n_channels - 1)
114
117
  )
115
118
 
119
+ # Initialize from provided values (sync with settings panel)
120
+ if initial_diameter is not None:
121
+ self.spot_diam_le.setText(str(initial_diameter))
122
+ if initial_threshold is not None:
123
+ self.spot_thresh_le.setText(str(initial_threshold))
124
+ if initial_preprocessing is not None and len(initial_preprocessing) > 0:
125
+ items_for_list = [a[0] for a in initial_preprocessing]
126
+ for it in items_for_list:
127
+ self.preprocessing.list.addItemToList(it)
128
+ self.preprocessing.list.items = list(initial_preprocessing)
129
+
116
130
  def closeEvent(self, event):
117
131
  """Clean up resources on close."""
118
132
  # Clear large arrays
@@ -23,6 +23,7 @@ from celldetective.utils.maths import step_function
23
23
  from celldetective.utils.image_cleaning import interpolate_nan
24
24
  from celldetective.preprocessing import field_correction
25
25
  from celldetective.log_manager import get_logger
26
+ import pandas as pd
26
27
 
27
28
  logger = get_logger(__name__)
28
29
 
@@ -279,8 +280,6 @@ def measure(
279
280
 
280
281
  timestep_dataframes.append(measurements_at_t)
281
282
 
282
- import pandas as pd
283
-
284
283
  measurements = pd.concat(timestep_dataframes)
285
284
  if trajectories is not None:
286
285
  measurements = measurements.sort_values(
@@ -435,8 +434,11 @@ def measure_features(
435
434
 
436
435
  if spot_detection is not None:
437
436
  detection_channel = spot_detection.get("channel")
438
- if detection_channel in channels:
439
- ind = channels.index(detection_channel)
437
+ channels_list = (
438
+ list(channels) if not isinstance(channels, list) else channels
439
+ )
440
+ if detection_channel in channels_list:
441
+ ind = channels_list.index(detection_channel)
440
442
  if "image_preprocessing" not in spot_detection:
441
443
  spot_detection.update({"image_preprocessing": None})
442
444
 
@@ -458,8 +460,11 @@ def measure_features(
458
460
  if normalisation_list:
459
461
  for norm in normalisation_list:
460
462
  target = norm.get("target_channel")
461
- if target in channels:
462
- ind = channels.index(target)
463
+ channels_list = (
464
+ list(channels) if not isinstance(channels, list) else channels
465
+ )
466
+ if target in channels_list:
467
+ ind = channels_list.index(target)
463
468
 
464
469
  if norm["correction_type"] == "local":
465
470
  normalised_image = normalise_by_cell(
@@ -529,7 +534,6 @@ def measure_features(
529
534
  extra_properties=extra_props_list,
530
535
  channel_names=channels,
531
536
  )
532
- import pandas as pd
533
537
 
534
538
  df_props = pd.DataFrame(props)
535
539
 
@@ -598,7 +602,6 @@ def measure_features(
598
602
  extra_properties=intensity_extra,
599
603
  channel_names=channels,
600
604
  )
601
- import pandas as pd
602
605
 
603
606
  df_props_border_d = pd.DataFrame(props_border)
604
607
 
@@ -821,8 +824,6 @@ def compute_haralick_features(
821
824
  len(np.unique(labels)) - 1
822
825
  ), "Some cells have not been measured..."
823
826
 
824
- import pandas as pd
825
-
826
827
  return pd.DataFrame(haralick_properties)
827
828
 
828
829
 
@@ -1070,7 +1071,6 @@ def measure_at_position(pos, mode, return_measurements=False, threads=1):
1070
1071
 
1071
1072
  table = pos + os.sep.join(["output", "tables", f"trajectories_{mode}.csv"])
1072
1073
  if return_measurements:
1073
- import pandas as pd
1074
1074
 
1075
1075
  df = pd.read_csv(table)
1076
1076
  return df
@@ -249,9 +249,13 @@ def rename_intensity_column(df, channels):
249
249
  if np.any(test_digit):
250
250
  index = int(sections[np.where(test_digit)[0]][-1])
251
251
  else:
252
- print(
253
- f"No valid channel index found for {intensity_cols[k]}... Skipping the renaming for {intensity_cols[k]}..."
254
- )
252
+ # Check if the column already contains a channel name (e.g., spot detection columns)
253
+ # If so, skip silently as no renaming is needed
254
+ already_named = any(ch in intensity_cols[k] for ch in channel_names)
255
+ if not already_named:
256
+ print(
257
+ f"No valid channel index found for {intensity_cols[k]}... Skipping the renaming for {intensity_cols[k]}..."
258
+ )
255
259
  continue
256
260
 
257
261
  channel_name = channel_names[np.where(channel_indices == index)[0]][0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: celldetective
3
- Version: 1.5.0b9
3
+ Version: 1.5.0b10
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -0,0 +1,394 @@
1
+ import pytest
2
+ import numpy as np
3
+ import logging
4
+ from PyQt5.QtWidgets import QApplication
5
+ from celldetective.gui.viewers.spot_detection_viewer import SpotDetectionVisualizer
6
+ from celldetective.gui.gui_utils import PreprocessingLayout2
7
+ from unittest.mock import MagicMock, patch
8
+
9
+
10
+ @pytest.fixture(autouse=True)
11
+ def disable_logging():
12
+ """Disable all logging to avoid Windows OSError with pytest capture."""
13
+ logger = logging.getLogger()
14
+ try:
15
+ logging.disable(logging.CRITICAL)
16
+ yield
17
+ finally:
18
+ logging.disable(logging.NOTSET)
19
+
20
+
21
+ @pytest.fixture
22
+ def dummy_data():
23
+ """
24
+ Create a dummy stack: 5 frames, 100x100 pixels, 2 channels.
25
+ Channel 0: Clean background (zeros)
26
+ Channel 1: Two Gaussian spots with high intensity
27
+ """
28
+ frames = 5
29
+ y, x = 100, 100
30
+ channels = 2
31
+
32
+ stack = np.zeros((frames, y, x, channels), dtype=np.float32)
33
+
34
+ # Create coordinate grids
35
+ Y, X = np.ogrid[:y, :x]
36
+
37
+ # Gaussian spot 1 at (22, 22) - center of mask 1
38
+ center_y1, center_x1 = 22, 22
39
+ sigma = 2.0
40
+ gaussian1 = np.exp(-((Y - center_y1) ** 2 + (X - center_x1) ** 2) / (2 * sigma**2))
41
+
42
+ # Gaussian spot 2 at (62, 62) - center of mask 2
43
+ center_y2, center_x2 = 62, 62
44
+ gaussian2 = np.exp(-((Y - center_y2) ** 2 + (X - center_x2) ** 2) / (2 * sigma**2))
45
+
46
+ # Add to stack with high intensity (1000 for spot 1, 800 for spot 2)
47
+ spots_frame = (gaussian1 * 1000 + gaussian2 * 800).astype(np.float32)
48
+ for f in range(frames):
49
+ stack[f, :, :, 1] = spots_frame
50
+
51
+ # Channel 0 stays at zero (clean background)
52
+
53
+ # Create dummy masks (labels) - each spot is inside its own cell
54
+ masks = np.zeros((frames, y, x), dtype=np.uint16)
55
+ masks[:, 15:30, 15:30] = 1 # Mask around Spot 1 (22, 22)
56
+ masks[:, 55:70, 55:70] = 2 # Mask around Spot 2 (62, 62)
57
+
58
+ return stack, masks
59
+
60
+
61
+ def test_spot_detection_visualizer_interactions(qtbot, dummy_data):
62
+ """
63
+ Test interactions with SpotDetectionVisualizer.
64
+ """
65
+ stack, labels = dummy_data
66
+ channel_names = ["Background", "Spots"]
67
+
68
+ # Mock parent widgets that might be updated by the visualizer
69
+ parent_channel_cb = MagicMock()
70
+ parent_diameter_le = MagicMock()
71
+ parent_threshold_le = MagicMock()
72
+ parent_preprocessing_list = MagicMock()
73
+
74
+ viewer = SpotDetectionVisualizer(
75
+ stack=stack,
76
+ labels=labels,
77
+ channel_names=channel_names,
78
+ n_channels=2,
79
+ parent_channel_cb=parent_channel_cb,
80
+ parent_diameter_le=parent_diameter_le,
81
+ parent_threshold_le=parent_threshold_le,
82
+ parent_preprocessing_list=parent_preprocessing_list,
83
+ window_title="Test Spot Detective",
84
+ channel_cb=True,
85
+ contrast_slider=False,
86
+ frame_slider=False,
87
+ )
88
+
89
+ qtbot.addWidget(viewer)
90
+ viewer.show()
91
+ qtbot.waitForWindowShown(viewer)
92
+
93
+ # 1. Test Channel Selection
94
+ # Default is target_channel=0 (Background)
95
+ assert viewer.detection_channel == 0
96
+
97
+ # Switch to Spots channel (Index 1)
98
+ viewer.detection_channel_cb.setCurrentIndex(1)
99
+ assert viewer.detection_channel == 1
100
+
101
+ # Force frame update to ensure target_img is correct for channel 1
102
+ viewer.change_frame(0)
103
+
104
+ # Verify image updated to Channel 1, Frame 0
105
+ current_img = viewer.target_img
106
+ expected_img = stack[0, :, :, 1]
107
+ np.testing.assert_array_equal(current_img, expected_img)
108
+
109
+ # 2. Test Spot Detection Parameters
110
+ # Set Diameter (LoG works best with diameter ~ 2*sqrt(2)*sigma ~ 5.6 for sigma=2)
111
+ viewer.spot_diam_le.clear()
112
+ qtbot.keyClicks(viewer.spot_diam_le, "4")
113
+ assert viewer.spot_diam_le.text() == "4"
114
+
115
+ # Set Threshold (low threshold to ensure detection)
116
+ viewer.spot_thresh_le.clear()
117
+ qtbot.keyClicks(viewer.spot_thresh_le, "0.01")
118
+ assert viewer.spot_thresh_le.text() == "0.01"
119
+
120
+ # Manually trigger control_valid_parameters to update self.diameter and self.thresh
121
+ viewer.control_valid_parameters()
122
+
123
+ # Verify parameters were set
124
+ assert viewer.diameter == 4.0
125
+ assert viewer.thresh == 0.01
126
+
127
+ # Trigger detection by clicking apply button
128
+ qtbot.mouseClick(viewer.apply_diam_btn, 1) # Qt.LeftButton = 1
129
+ qtbot.wait(200) # Wait for detection to complete
130
+
131
+ # Check that we recovered 2 spots
132
+ # In dummy_data: Spot 1 at (22, 22), Spot 2 at (62, 62)
133
+ n_spots = (
134
+ len(viewer.spot_positions)
135
+ if hasattr(viewer, "spot_positions") and viewer.spot_positions is not None
136
+ else 0
137
+ )
138
+ assert (
139
+ n_spots == 2
140
+ ), f"Expected 2 spots, found {n_spots}. Positions: {viewer.spot_positions if hasattr(viewer, 'spot_positions') else 'N/A'}"
141
+
142
+ # Verify positions roughly match (22, 22) and (62, 62)
143
+ # spot_positions are (x, y) pairs
144
+ pos = viewer.spot_positions
145
+ has_spot_1 = np.any(np.all(np.abs(pos - [22, 22]) < 5, axis=1))
146
+ has_spot_2 = np.any(np.all(np.abs(pos - [62, 62]) < 5, axis=1))
147
+ assert has_spot_1, f"Spot 1 not found near (22, 22). Positions: {pos}"
148
+ assert has_spot_2, f"Spot 2 not found near (62, 62). Positions: {pos}"
149
+
150
+ # 3. Test Preprocessing and Preview
151
+ # Ensure preview is unchecked initially
152
+ assert not viewer.preview_cb.isChecked()
153
+
154
+ # Check "Preview" - should show original image if filter list is empty
155
+ viewer.preview_cb.setChecked(True)
156
+ assert viewer.preview_cb.isChecked()
157
+ # Image should still match original target since no filters
158
+ np.testing.assert_array_equal(viewer.im.get_array(), expected_img)
159
+
160
+ # Add a filter: "gauss" with sigma=2
161
+ # Directly manipulate the list since dialog interaction is complex
162
+ viewer.preprocessing.list.items.append(["gauss", 2])
163
+ viewer.preprocessing.list.list_widget.addItems(["gauss_filter"])
164
+
165
+ # Force preview update
166
+ viewer.update_preview_if_active()
167
+ qtbot.wait(200)
168
+
169
+ preview_img = viewer.im.get_array()
170
+ assert not np.array_equal(
171
+ preview_img, expected_img
172
+ ), "Preview image should differ after adding gaussian filter"
173
+
174
+ # 4. Remove Filter
175
+ # Select item 0
176
+ viewer.preprocessing.list.list_widget.setCurrentRow(0)
177
+ # Click remove button
178
+ viewer.preprocessing.delete_filter_btn.click()
179
+
180
+ qtbot.wait(200)
181
+
182
+ # Internal items should be empty
183
+ assert len(viewer.preprocessing.list.items) == 0
184
+
185
+ # Preview should revert to original
186
+ reverted_img = viewer.im.get_array()
187
+ np.testing.assert_array_equal(reverted_img, expected_img)
188
+
189
+
190
+ @pytest.fixture
191
+ def dark_spots_data():
192
+ """
193
+ Create a dummy stack with DARK spots on a BRIGHT background.
194
+ This simulates scenarios like:
195
+ - Absorbing particles on a bright field
196
+ - Phase contrast imaging with dark nuclei
197
+ The invert preprocessing filter should be used to detect these spots.
198
+ """
199
+ frames = 5
200
+ y, x = 100, 100
201
+ channels = 2
202
+
203
+ # Bright background (value 1000)
204
+ stack = np.ones((frames, y, x, channels), dtype=np.float32) * 1000
205
+
206
+ # Create coordinate grids
207
+ Y, X = np.ogrid[:y, :x]
208
+
209
+ # Dark Gaussian spot 1 at (22, 22)
210
+ center_y1, center_x1 = 22, 22
211
+ sigma = 2.0
212
+ gaussian1 = np.exp(-((Y - center_y1) ** 2 + (X - center_x1) ** 2) / (2 * sigma**2))
213
+
214
+ # Dark Gaussian spot 2 at (62, 62)
215
+ center_y2, center_x2 = 62, 62
216
+ gaussian2 = np.exp(-((Y - center_y2) ** 2 + (X - center_x2) ** 2) / (2 * sigma**2))
217
+
218
+ # Subtract from bright background to create dark spots
219
+ # Spot 1: drops to ~0 at center, Spot 2: drops to ~200 at center
220
+ dark_spots_frame = 1000 - (gaussian1 * 1000 + gaussian2 * 800)
221
+ dark_spots_frame = dark_spots_frame.astype(np.float32)
222
+
223
+ for f in range(frames):
224
+ stack[f, :, :, 1] = dark_spots_frame
225
+
226
+ # Channel 0 stays uniform bright (no spots)
227
+
228
+ # Create dummy masks
229
+ masks = np.zeros((frames, y, x), dtype=np.uint16)
230
+ masks[:, 15:30, 15:30] = 1 # Mask around Spot 1
231
+ masks[:, 55:70, 55:70] = 2 # Mask around Spot 2
232
+
233
+ return stack, masks
234
+
235
+
236
+ def test_dark_spot_detection_with_invert(qtbot, dark_spots_data):
237
+ """
238
+ Test detection of dark spots on a bright background using the invert filter.
239
+
240
+ Bug Prevention:
241
+ - Ensures the preprocessing pipeline (invert) correctly transforms images
242
+ before spot detection.
243
+ - Verifies that the detection uses the preprocessed image, not the raw image.
244
+
245
+ Steps:
246
+ 1. Load stack with dark spots on bright background.
247
+ 2. Switch to the dark spots channel.
248
+ 3. Add an "invert" preprocessing filter with max value 1000.
249
+ 4. Set detection parameters (diameter, threshold).
250
+ 5. Trigger detection.
251
+ 6. Verify that both dark spots are detected.
252
+
253
+ Expected Outcome:
254
+ - 2 spots detected at positions (22, 22) and (62, 62).
255
+ """
256
+ stack, labels = dark_spots_data
257
+ channel_names = ["Uniform", "DarkSpots"]
258
+
259
+ parent_channel_cb = MagicMock()
260
+ parent_diameter_le = MagicMock()
261
+ parent_threshold_le = MagicMock()
262
+ parent_preprocessing_list = MagicMock()
263
+
264
+ viewer = SpotDetectionVisualizer(
265
+ stack=stack,
266
+ labels=labels,
267
+ channel_names=channel_names,
268
+ n_channels=2,
269
+ parent_channel_cb=parent_channel_cb,
270
+ parent_diameter_le=parent_diameter_le,
271
+ parent_threshold_le=parent_threshold_le,
272
+ parent_preprocessing_list=parent_preprocessing_list,
273
+ window_title="Test Dark Spot Detection",
274
+ channel_cb=True,
275
+ contrast_slider=False,
276
+ frame_slider=False,
277
+ )
278
+
279
+ qtbot.addWidget(viewer)
280
+ viewer.show()
281
+ qtbot.waitForWindowShown(viewer)
282
+
283
+ # 1. Switch to DarkSpots channel (Index 1)
284
+ viewer.detection_channel_cb.setCurrentIndex(1)
285
+ assert viewer.detection_channel == 1
286
+ viewer.change_frame(0)
287
+
288
+ # Verify image is bright with dark spots
289
+ current_img = viewer.target_img
290
+ # The center of spot 1 (22, 22) should be dark (near 0)
291
+ assert (
292
+ current_img[22, 22] < 100
293
+ ), f"Expected dark spot at (22,22), got {current_img[22, 22]}"
294
+ # The background should be bright (near 1000)
295
+ assert (
296
+ current_img[0, 0] > 900
297
+ ), f"Expected bright background, got {current_img[0, 0]}"
298
+
299
+ # 2. Add invert preprocessing filter
300
+ # invert filter inverts the image: output = max_value - input
301
+ # With max_value=1000, dark spots become bright spots
302
+ viewer.preprocessing.list.items.append(["invert", 1000])
303
+ viewer.preprocessing.list.list_widget.addItems(["invert_1000"])
304
+
305
+ # 3. Set detection parameters
306
+ viewer.spot_diam_le.clear()
307
+ qtbot.keyClicks(viewer.spot_diam_le, "4")
308
+ viewer.spot_thresh_le.clear()
309
+ qtbot.keyClicks(viewer.spot_thresh_le, "0.01")
310
+ viewer.control_valid_parameters()
311
+
312
+ assert viewer.diameter == 4.0
313
+ assert viewer.thresh == 0.01
314
+
315
+ # Enable preview to verify inversion works
316
+ viewer.preview_cb.setChecked(True)
317
+ viewer.update_preview_if_active()
318
+ qtbot.wait(200)
319
+
320
+ # After inversion, the former dark spot at (22, 22) should now be bright
321
+ preview_img = viewer.im.get_array()
322
+ assert (
323
+ preview_img[22, 22] > 900
324
+ ), f"After invert, spot should be bright. Got {preview_img[22, 22]}"
325
+
326
+ # 4. Trigger detection
327
+ qtbot.mouseClick(viewer.apply_diam_btn, 1)
328
+ qtbot.wait(200)
329
+
330
+ # 5. Verify spots detected
331
+ n_spots = (
332
+ len(viewer.spot_positions)
333
+ if hasattr(viewer, "spot_positions") and viewer.spot_positions is not None
334
+ else 0
335
+ )
336
+ assert (
337
+ n_spots == 2
338
+ ), f"Expected 2 dark spots detected, found {n_spots}. Positions: {getattr(viewer, 'spot_positions', 'N/A')}"
339
+
340
+ # Verify positions
341
+ pos = viewer.spot_positions
342
+ has_spot_1 = np.any(np.all(np.abs(pos - [22, 22]) < 5, axis=1))
343
+ has_spot_2 = np.any(np.all(np.abs(pos - [62, 62]) < 5, axis=1))
344
+ assert has_spot_1, f"Dark Spot 1 not found near (22, 22). Positions: {pos}"
345
+ assert has_spot_2, f"Dark Spot 2 not found near (62, 62). Positions: {pos}"
346
+
347
+
348
+ def test_viewer_initializes_from_parent_values(qtbot, dummy_data):
349
+ """
350
+ Test that the viewer initializes its widgets from initial_* arguments.
351
+ """
352
+ stack, labels = dummy_data
353
+ channel_names = ["Background", "Spots"]
354
+
355
+ # Mock parent widgets
356
+ parent_channel_cb = MagicMock()
357
+ parent_diameter_le = MagicMock()
358
+ parent_threshold_le = MagicMock()
359
+ parent_preprocessing_list = MagicMock()
360
+
361
+ initial_params = [["gauss", 1.5], ["invert", 500]]
362
+
363
+ viewer = SpotDetectionVisualizer(
364
+ stack=stack,
365
+ labels=labels,
366
+ channel_names=channel_names,
367
+ n_channels=2,
368
+ parent_channel_cb=parent_channel_cb,
369
+ parent_diameter_le=parent_diameter_le,
370
+ parent_threshold_le=parent_threshold_le,
371
+ parent_preprocessing_list=parent_preprocessing_list,
372
+ window_title="Test Init Values",
373
+ channel_cb=True,
374
+ contrast_slider=False,
375
+ frame_slider=False,
376
+ # Pass initial values
377
+ initial_diameter="8.5",
378
+ initial_threshold="1.2",
379
+ initial_preprocessing=initial_params,
380
+ )
381
+
382
+ qtbot.addWidget(viewer)
383
+ viewer.show()
384
+ qtbot.waitForWindowShown(viewer)
385
+
386
+ # Verify widgets were initialized with passed values
387
+ assert viewer.spot_diam_le.text() == "8.5"
388
+ assert viewer.spot_thresh_le.text() == "1.2"
389
+
390
+ # Verify preprocessing list was populated
391
+ current_filters = viewer.preprocessing.list.items
392
+ assert len(current_filters) == 2
393
+ assert current_filters[0] == ["gauss", 1.5]
394
+ assert current_filters[1] == ["invert", 500]