openflo 2.6.2__tar.gz → 2.7.0b2__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.
- {openflo-2.6.2 → openflo-2.7.0b2}/CHANGELOG.md +917 -0
- {openflo-2.6.2/src/openflo.egg-info → openflo-2.7.0b2}/PKG-INFO +62 -19
- {openflo-2.6.2 → openflo-2.7.0b2}/README.md +58 -17
- {openflo-2.6.2 → openflo-2.7.0b2}/pyproject.toml +6 -4
- openflo-2.7.0b2/scripts/make_reference_values.py +243 -0
- openflo-2.7.0b2/scripts/preflight.py +232 -0
- openflo-2.7.0b2/scripts/prove_tests.py +1299 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/_console.py +1 -1
- openflo-2.7.0b2/src/openflo/acquisition.py +117 -0
- openflo-2.7.0b2/src/openflo/async_task.py +338 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/audit.py +17 -5
- openflo-2.7.0b2/src/openflo/batch_normalize.py +378 -0
- openflo-2.7.0b2/src/openflo/bead_tracking.py +163 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/calibration.py +33 -12
- openflo-2.7.0b2/src/openflo/capabilities.py +247 -0
- openflo-2.7.0b2/src/openflo/cellcycle_djf.py +124 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/cli.py +621 -301
- openflo-2.7.0b2/src/openflo/cli_args.py +259 -0
- openflo-2.7.0b2/src/openflo/clipboard_export.py +177 -0
- openflo-2.7.0b2/src/openflo/comp_spread.py +71 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/compare.py +166 -25
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/density.py +4 -4
- openflo-2.7.0b2/src/openflo/derived.py +262 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/diagnostics.py +8 -2
- openflo-2.7.0b2/src/openflo/dialog_inputs.py +96 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/diffexp.py +225 -26
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/dr_compare.py +11 -6
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_analysis.py +169 -54
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_audit.py +7 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_autoclean.py +4 -4
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_autogate.py +21 -4
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_chrome.py +141 -37
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_clipboard.py +27 -12
- openflo-2.7.0b2/src/openflo/editor_combos.py +213 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_compute.py +106 -24
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_console.py +5 -5
- openflo-2.7.0b2/src/openflo/editor_coords.py +139 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_dnd.py +186 -22
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_downsample.py +47 -12
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_export.py +227 -34
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_figure.py +16 -13
- openflo-2.7.0b2/src/openflo/editor_fixes.py +156 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_gatetools.py +157 -26
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_gating.py +371 -68
- openflo-2.7.0b2/src/openflo/editor_grouping.py +186 -0
- openflo-2.7.0b2/src/openflo/editor_help.py +391 -0
- openflo-2.7.0b2/src/openflo/editor_keyboard.py +152 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_lifecycle.py +295 -79
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_load.py +205 -55
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_loadpool.py +145 -48
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_menu.py +167 -70
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_mode.py +5 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_plot.py +328 -47
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_plotcache.py +183 -32
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_populations.py +205 -88
- openflo-2.7.0b2/src/openflo/editor_refit.py +102 -0
- openflo-2.7.0b2/src/openflo/editor_samples.py +83 -0
- openflo-2.7.0b2/src/openflo/editor_session.py +1734 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_slider.py +1 -1
- openflo-2.7.0b2/src/openflo/editor_specialist.py +49 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_stats.py +72 -8
- openflo-2.7.0b2/src/openflo/editor_tabs.py +699 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_template.py +93 -30
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_tools.py +269 -207
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_tree.py +265 -28
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_undo.py +44 -2
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_update.py +54 -26
- openflo-2.7.0b2/src/openflo/errors.py +82 -0
- openflo-2.7.0b2/src/openflo/export_stamp.py +156 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/fcs_export.py +94 -22
- openflo-2.7.0b2/src/openflo/fcs_read.py +68 -0
- openflo-2.7.0b2/src/openflo/fixes.py +620 -0
- openflo-2.7.0b2/src/openflo/fluor_catalog.py +29 -0
- openflo-2.7.0b2/src/openflo/fmo_sensitivity.py +98 -0
- openflo-2.7.0b2/src/openflo/gate_combos.py +235 -0
- openflo-2.7.0b2/src/openflo/gate_coords.py +280 -0
- openflo-2.7.0b2/src/openflo/gate_refit.py +226 -0
- openflo-2.7.0b2/src/openflo/gate_table.py +81 -0
- openflo-2.7.0b2/src/openflo/gating.py +628 -0
- openflo-2.7.0b2/src/openflo/gatingml.py +753 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/gpu_accel.py +34 -11
- openflo-2.7.0b2/src/openflo/group_test_choice.py +95 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/gui.py +540 -169
- openflo-2.7.0b2/src/openflo/guide/01-getting-started.md +31 -0
- openflo-2.7.0b2/src/openflo/guide/02-loading-samples.md +23 -0
- openflo-2.7.0b2/src/openflo/guide/03-gating.md +38 -0
- openflo-2.7.0b2/src/openflo/guide/04-compensation-and-scales.md +27 -0
- openflo-2.7.0b2/src/openflo/guide/05-statistics-and-figures.md +22 -0
- openflo-2.7.0b2/src/openflo/guide/06-analysis-tools.md +21 -0
- openflo-2.7.0b2/src/openflo/guide/07-spectral.md +13 -0
- openflo-2.7.0b2/src/openflo/guide/08-quality-control.md +18 -0
- openflo-2.7.0b2/src/openflo/guide/09-sharing.md +27 -0
- openflo-2.7.0b2/src/openflo/guide/10-troubleshooting.md +17 -0
- openflo-2.7.0b2/src/openflo/index_sort.py +90 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/inspect_fcs.py +4 -1
- openflo-2.7.0b2/src/openflo/kinetics.py +135 -0
- openflo-2.7.0b2/src/openflo/layout_page.py +610 -0
- openflo-2.7.0b2/src/openflo/layout_render.py +976 -0
- openflo-2.7.0b2/src/openflo/parallel.py +65 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/paths.py +22 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/pipeline.py +1523 -171
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/plotcache.py +13 -4
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/plotmath.py +2 -2
- openflo-2.7.0b2/src/openflo/pptx_export.py +212 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/prefs.py +29 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/preview.py +2 -2
- openflo-2.7.0b2/src/openflo/project_archive.py +169 -0
- openflo-2.7.0b2/src/openflo/proliferation.py +128 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/provenance.py +1 -1
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/report.py +11 -3
- openflo-2.7.0b2/src/openflo/result_stamp.py +315 -0
- openflo-2.7.0b2/src/openflo/sample_meta.py +157 -0
- openflo-2.7.0b2/src/openflo/saturation.py +147 -0
- openflo-2.7.0b2/src/openflo/saved_stats.py +197 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/scales.py +283 -27
- openflo-2.7.0b2/src/openflo/session_compare.py +168 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/session_format.py +39 -4
- openflo-2.7.0b2/src/openflo/session_lock.py +189 -0
- openflo-2.7.0b2/src/openflo/session_sidecar.py +129 -0
- openflo-2.7.0b2/src/openflo/som_kernel.py +141 -0
- openflo-2.7.0b2/src/openflo/spectral_af.py +136 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/stats.py +266 -31
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/synthetic.py +4 -2
- openflo-2.7.0b2/src/openflo/table_export.py +336 -0
- openflo-2.7.0b2/src/openflo/theme.py +480 -0
- openflo-2.7.0b2/src/openflo/tk_threads.py +104 -0
- openflo-2.7.0b2/src/openflo/tool_window.py +513 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_abscounts.py +14 -10
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_annotation.py +16 -12
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_audit.py +15 -15
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_autogate.py +38 -26
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_axis_config.py +117 -24
- openflo-2.7.0b2/src/openflo/ui_batch_normalize.py +473 -0
- openflo-2.7.0b2/src/openflo/ui_bead_tracking.py +248 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_calibration.py +39 -15
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_cell_cycle.py +25 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_comp.py +112 -25
- openflo-2.7.0b2/src/openflo/ui_comp_spread.py +260 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_compare.py +26 -13
- openflo-2.7.0b2/src/openflo/ui_concatenate.py +122 -0
- openflo-2.7.0b2/src/openflo/ui_derived.py +177 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_diff.py +59 -15
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_embedding.py +34 -12
- openflo-2.7.0b2/src/openflo/ui_errors.py +174 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_expression.py +128 -51
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_figure_layout.py +9 -8
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_figure_window.py +1 -1
- openflo-2.7.0b2/src/openflo/ui_fixes.py +304 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_flowsom_tree.py +9 -7
- openflo-2.7.0b2/src/openflo/ui_fmo.py +472 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_frequency.py +114 -42
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_group_stats.py +26 -3
- openflo-2.7.0b2/src/openflo/ui_guide.py +149 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_inspect.py +13 -8
- openflo-2.7.0b2/src/openflo/ui_kinetics.py +358 -0
- openflo-2.7.0b2/src/openflo/ui_layout_editor.py +2448 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_logic.py +13 -5
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_methods.py +31 -19
- openflo-2.7.0b2/src/openflo/ui_notice.py +77 -0
- openflo-2.7.0b2/src/openflo/ui_plate.py +262 -0
- openflo-2.7.0b2/src/openflo/ui_polyfunction.py +176 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_preferences.py +197 -20
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_preview.py +16 -16
- openflo-2.7.0b2/src/openflo/ui_proliferation.py +269 -0
- openflo-2.7.0b2/src/openflo/ui_refit.py +104 -0
- openflo-2.7.0b2/src/openflo/ui_sample_groups.py +152 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_sample_qc.py +44 -24
- openflo-2.7.0b2/src/openflo/ui_saturation.py +182 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_spectral_qc.py +20 -12
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_spectral_unmix.py +24 -8
- openflo-2.7.0b2/src/openflo/ui_statistics.py +662 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_synth.py +17 -13
- openflo-2.7.0b2/src/openflo/ui_table.py +122 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_tips.py +1 -1
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_trajectory.py +74 -37
- openflo-2.7.0b2/src/openflo/ui_unmixed_pairs.py +51 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/ui_voltage.py +20 -12
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/update.py +50 -28
- openflo-2.7.0b2/src/openflo/user_guide.py +114 -0
- openflo-2.7.0b2/src/openflo/view_tabs.py +315 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/workspace.py +298 -101
- {openflo-2.6.2 → openflo-2.7.0b2/src/openflo.egg-info}/PKG-INFO +62 -19
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo.egg-info/SOURCES.txt +165 -6
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo.egg-info/entry_points.txt +1 -1
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo.egg-info/requires.txt +3 -1
- openflo-2.7.0b2/tests/_fcs_writer.py +59 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/conftest.py +144 -21
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_apply_region_gates.py +61 -30
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_autoclean_counts.py +38 -10
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_axis_intensity_ticks.py +4 -1
- openflo-2.7.0b2/tests/test_batch_d_responsive.py +745 -0
- openflo-2.7.0b2/tests/test_batch_e_quick_features.py +599 -0
- openflo-2.7.0b2/tests/test_batch_g_cli_sharding.py +248 -0
- openflo-2.7.0b2/tests/test_batch_h_consistent_dialogs.py +560 -0
- openflo-2.7.0b2/tests/test_batch_i_menus_fonts_colours.py +608 -0
- openflo-2.7.0b2/tests/test_batch_j_data_handling.py +382 -0
- openflo-2.7.0b2/tests/test_batch_k_specialist.py +740 -0
- openflo-2.7.0b2/tests/test_batch_l_offline_help.py +187 -0
- openflo-2.7.0b2/tests/test_batch_n_exports_access.py +582 -0
- openflo-2.7.0b2/tests/test_batch_normalize.py +323 -0
- openflo-2.7.0b2/tests/test_batch_normalize_dialog.py +203 -0
- openflo-2.7.0b2/tests/test_beta_look.py +364 -0
- openflo-2.7.0b2/tests/test_beta_release.py +21 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_boolean_gate_fails_closed.py +57 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_boolean_gate_tools.py +53 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_calibration_dialog.py +3 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_capabilities.py +29 -8
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cell_cycle_dialog.py +10 -2
- openflo-2.7.0b2/tests/test_ci_full_matrix_events.py +107 -0
- openflo-2.7.0b2/tests/test_ci_macos_job.py +44 -0
- openflo-2.7.0b2/tests/test_ci_privacy_gate_on_mirror.py +54 -0
- openflo-2.7.0b2/tests/test_clean_install_round2.py +121 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cli_cluster.py +3 -3
- openflo-2.7.0b2/tests/test_cli_reproducibility.py +270 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cli_run.py +79 -8
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cli_shared_clusters.py +142 -2
- openflo-2.7.0b2/tests/test_close_save.py +418 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cluster_dialog.py +48 -8
- openflo-2.7.0b2/tests/test_cluster_recovery_highdim.py +142 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_clustering_known_defects.py +44 -14
- openflo-2.7.0b2/tests/test_combination_gates.py +323 -0
- openflo-2.7.0b2/tests/test_comp_apply_keeps_computed.py +254 -0
- openflo-2.7.0b2/tests/test_comp_apply_to_batch.py +149 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compare_flowjo_semantics.py +13 -1
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compensation_editor_apply.py +7 -6
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_console_encoding.py +12 -0
- openflo-2.7.0b2/tests/test_copy_gates_dialog.py +123 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cytonorm_qc_undefined.py +19 -9
- openflo-2.7.0b2/tests/test_derived_kinetics.py +403 -0
- openflo-2.7.0b2/tests/test_dialog_actions.py +282 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_dialog_tooltips.py +132 -12
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_diffexp.py +48 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_editor_tools.py +3 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ellipse_tool.py +3 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ellipsoid_quadrant.py +26 -11
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_embedding_dialog.py +1 -1
- openflo-2.7.0b2/tests/test_engine_availability.py +155 -0
- openflo-2.7.0b2/tests/test_error_handling.py +279 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_exit_autosave.py +92 -17
- openflo-2.7.0b2/tests/test_export_audit.py +282 -0
- openflo-2.7.0b2/tests/test_export_stamp.py +288 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_expression_window.py +30 -4
- openflo-2.7.0b2/tests/test_fcs_speed.py +226 -0
- openflo-2.7.0b2/tests/test_fcs_stored_values.py +82 -0
- openflo-2.7.0b2/tests/test_fcs_writer_quirks.py +127 -0
- openflo-2.7.0b2/tests/test_fixes.py +713 -0
- openflo-2.7.0b2/tests/test_fmo_gating_dialog.py +308 -0
- openflo-2.7.0b2/tests/test_fmo_histogram_overlay.py +85 -0
- openflo-2.7.0b2/tests/test_fmo_threshold_compare.py +116 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_frequency_missing_populations.py +2 -2
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_frequency_window.py +36 -10
- openflo-2.7.0b2/tests/test_gate_coordinates.py +320 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_editor_helpers.py +27 -6
- openflo-2.7.0b2/tests/test_gate_on_missing_channel.py +87 -0
- openflo-2.7.0b2/tests/test_gate_refit.py +282 -0
- openflo-2.7.0b2/tests/test_gate_table.py +71 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_text_intensity.py +8 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_tools_axis_ends.py +7 -6
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gating.py +7 -6
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gating_helpers.py +8 -4
- openflo-2.7.0b2/tests/test_gating_strategy_page.py +107 -0
- openflo-2.7.0b2/tests/test_gatingml.py +367 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gui_smoke.py +17 -11
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gui_toolings.py +6 -4
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gui_ux.py +28 -19
- openflo-2.7.0b2/tests/test_highlighted_sample_is_plotted.py +105 -0
- openflo-2.7.0b2/tests/test_independent_reference.py +112 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_inspect_fcs.py +0 -4
- openflo-2.7.0b2/tests/test_install_leaves_no_files.py +126 -0
- openflo-2.7.0b2/tests/test_knn_threads.py +93 -0
- openflo-2.7.0b2/tests/test_layout_editor.py +935 -0
- openflo-2.7.0b2/tests/test_layout_exploded.py +463 -0
- openflo-2.7.0b2/tests/test_load_reliability.py +391 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_no_plausible_fills.py +5 -1
- openflo-2.7.0b2/tests/test_parallel_load_blas.py +125 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_parse_ellipsoid.py +17 -2
- openflo-2.7.0b2/tests/test_pipeline_missing_embedding.py +97 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_plot_cache.py +17 -0
- openflo-2.7.0b2/tests/test_plot_defaults.py +405 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_polygon_gating.py +81 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_polygon_rect_tools.py +38 -14
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_population_stats_geomean.py +1 -1
- openflo-2.7.0b2/tests/test_population_stats_speed.py +315 -0
- openflo-2.7.0b2/tests/test_pptx_export.py +128 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_preexisting_data_defects.py +6 -0
- openflo-2.7.0b2/tests/test_public_links.py +59 -0
- openflo-2.7.0b2/tests/test_python_readiness.py +363 -0
- openflo-2.7.0b2/tests/test_quadrant_tool.py +306 -0
- openflo-2.7.0b2/tests/test_result_stamps.py +355 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_sample_qc_window_values.py +2 -0
- openflo-2.7.0b2/tests/test_saved_stats.py +454 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_session.py +15 -6
- openflo-2.7.0b2/tests/test_session_compare.py +147 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_session_continuity.py +19 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_session_json_is_valid.py +4 -5
- openflo-2.7.0b2/tests/test_session_lock.py +386 -0
- openflo-2.7.0b2/tests/test_session_missing_samples.py +155 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_session_restore_transforms.py +41 -6
- openflo-2.7.0b2/tests/test_session_safety.py +400 -0
- openflo-2.7.0b2/tests/test_session_saves_label_populations.py +82 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_session_sidecar_collision.py +15 -14
- openflo-2.7.0b2/tests/test_session_sidecar_cut_short.py +118 -0
- openflo-2.7.0b2/tests/test_setup_installer.py +299 -0
- openflo-2.7.0b2/tests/test_small_n_statistics.py +464 -0
- openflo-2.7.0b2/tests/test_som_kernel.py +190 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_spectral_qc_window.py +2 -3
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_spectral_unmix_gui.py +2 -2
- openflo-2.7.0b2/tests/test_stat_forms.py +115 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_statistics_export.py +10 -4
- openflo-2.7.0b2/tests/test_statistics_population_column.py +134 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_stats.py +4 -2
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_theme.py +9 -0
- openflo-2.7.0b2/tests/test_tk_main_thread.py +296 -0
- openflo-2.7.0b2/tests/test_tk_threads.py +89 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_trajectory_window.py +6 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_transform_records.py +58 -1
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_typecheck_config.py +31 -6
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_audit_sign_verify.py +3 -1
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_logic.py +6 -5
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_undo_redo.py +1 -0
- openflo-2.7.0b2/tests/test_unknown_population_is_missing.py +144 -0
- openflo-2.7.0b2/tests/test_unknown_scale_export.py +164 -0
- openflo-2.7.0b2/tests/test_unknown_scale_import_is_missing.py +87 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_update.py +28 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_update_flow.py +35 -4
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_v261_sessions.py +102 -4
- openflo-2.7.0b2/tests/test_view_tabs.py +491 -0
- openflo-2.7.0b2/tests/test_window_fit.py +460 -0
- openflo-2.7.0b2/tests/test_windows_nothing_hidden.py +386 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_workspace.py +16 -7
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_workspace_prep_offthread.py +16 -1
- openflo-2.7.0b2/tests/test_wsp_boolean_gates.py +152 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_export_golden.py +4 -1
- openflo-2.7.0b2/tests/test_wsp_extract.py +100 -0
- openflo-2.7.0b2/tests/test_wsp_groups_subfolders.py +154 -0
- openflo-2.7.0b2/tests/test_wsp_time_edge_check.py +76 -0
- openflo-2.7.0b2/tests/test_wsp_unnamed_population_names.py +89 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_writer.py +26 -19
- openflo-2.7.0b2/tests/tk_main_thread.py +208 -0
- openflo-2.6.2/scripts/bench_accelerators.py +0 -294
- openflo-2.6.2/scripts/bench_louvain_restarts.py +0 -120
- openflo-2.6.2/scripts/bench_ui_responsiveness.py +0 -174
- openflo-2.6.2/scripts/bench_umap_knn.py +0 -177
- openflo-2.6.2/scripts/mutate_controls.py +0 -283
- openflo-2.6.2/scripts/preflight.py +0 -72
- openflo-2.6.2/src/openflo/async_task.py +0 -78
- openflo-2.6.2/src/openflo/capabilities.py +0 -116
- openflo-2.6.2/src/openflo/editor_grouping.py +0 -87
- openflo-2.6.2/src/openflo/editor_help.py +0 -237
- openflo-2.6.2/src/openflo/editor_session.py +0 -848
- openflo-2.6.2/src/openflo/gating.py +0 -360
- openflo-2.6.2/src/openflo/theme.py +0 -230
- openflo-2.6.2/src/openflo/tool_window.py +0 -160
- openflo-2.6.2/src/openflo/ui_fmo.py +0 -174
- openflo-2.6.2/src/openflo/ui_statistics.py +0 -382
- openflo-2.6.2/tests/test_fmo_gating_dialog.py +0 -157
- openflo-2.6.2/tests/test_quadrant_tool.py +0 -171
- openflo-2.6.2/tests/test_wsp_extract.py +0 -71
- {openflo-2.6.2 → openflo-2.7.0b2}/LICENSE.txt +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/MANIFEST.in +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/bench_import_cost.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/bench_snn_prune.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/lowest_direct_requirements.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/make_synthetic_dataset.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/migrate_session.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/run_analyses.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/smoke_test.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/theme_audit.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/scripts/typecheck.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/setup.cfg +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/__init__.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/_golden.json +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/annotate.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/comp_qc.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/compliance.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_base.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/editor_channels.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/gatetree.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/gating_helpers.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/interop.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/py.typed +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/selftest.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/selftest_controls.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/spectral.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/template_library/README.md +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/template_library/cleanup_acquisition_qc.json +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/template_library/cleanup_minimal.json +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/template_library/cleanup_standard.json +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/template_library/cleanup_strict.json +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/template_library/example_panel.json +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/trajectory.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/tree_ids.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/voltage.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo/warmup.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo.egg-info/dependency_links.txt +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/src/openflo.egg-info/top_level.txt +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/templates/testtemplate.json +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/__init__.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_abscounts.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_acquisition_qc_ground_truth.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_annotate.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_annotate_clusters.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_annotate_rename_dialogs.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_annotation_window.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_async_task.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_audit.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_autoclean_doublets_scale.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_autoclean_editor_actions.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_autoclean_methods.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_autogate.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_autogate_dialog.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_autogate_reproducible.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_calibration.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cell_cycle.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_channel_classification.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cli_e2e.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cli_export_wsp.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cli_run_options.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cli_unmix.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_clipboard_move_marker.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cluster_gpu_fallback.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cluster_heatmap.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cluster_labels.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cluster_reproducible.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_clustering_reproducible.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_comp_editor.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_comp_matrix_csv_quoting.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_comp_qc.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compare.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compare_all.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compare_conditions_absent_clusters.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compare_conditions_joint_clustering.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compare_dialog.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compensation.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compensation_applied_once.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compensation_fcs_spill.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compensation_matrix_reading.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_compliance.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_cytonorm.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_degenerate_scatter_gating.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_density.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_diagnostics.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_diagnostics_selftest_gate.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_diff_abundance_small_n.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_diffabundance.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_diffabundance_calibration.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_doctor_tk_check.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_dr_compare.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_drag_tree_refresh.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_editor_mixins.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ellipse_params_geometry.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_embedding.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_embeddings.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_exceptions.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_fast_graph.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_fcs_export.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_figure_layout.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_flowsom.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_flowsom_mst.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_flowsom_tree_window.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_fmo_threshold_log.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_fold_change_direction.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_impl_parity.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_import_fixes.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_mask_cache.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_nonfinite_events.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_partition.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gate_replication_parent.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gatetree.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gmm_ellipse_info.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_golden_regression.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gpu_accel.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_group_stats.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_group_stats_window.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_group_summary_sd.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_grouping.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_gui_guard.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_histogram_offscale_note.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_histogram_resolution.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_import_is_lazy.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_interop.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_interop_h5ad_roundtrip.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_label_align.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_legend_placement.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_leiden.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_load_no_copy.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_loader_queue.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_log_histogram_range.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_log_transform_nonpositive.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_mem_tiny_clusters.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_normalise_groups_idempotent.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_not_gate_excludes_unmeasured.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_optimize_compensation_truth.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_panel_pairs.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_paths.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_phenograph_pool_cap.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_plot_density.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_plotmath.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_preferences_wiring.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_prefs.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_prepare_unit_tags.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_preview_quadrants.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_propagate_downsample_order.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_provenance.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_provenance_unreadable_entries.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_qc.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_qc_ignores_derived_columns.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_qc_integer_channels.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_qc_removed_visible.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_quality_correctness.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_quick_preview_dialog.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_raw_not_aliased.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_report.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_resume_and_transfer_hygiene.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_run_louvain.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_scales.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_scales_logicle.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_seed_phrases.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_selftest.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_selftest_cli.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_selftest_controls.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_session_migration_machinery.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_spectral.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_spectral_degenerate_reference.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_spectral_matched_af.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_spectral_measured_and_spread.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_spectral_unmix_nonfinite.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_stats_multigroup.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_survivor_boundaries.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_synthetic.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_template_apply.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_template_one_sample.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_templates.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_threshold_inclusive.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_tool_window.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_trajectory.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_trajectory_nonfinite.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_transform_consistency.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_transform_nonfinite.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_transform_record_writes.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_transforms.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_tree_ids.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_compare.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_dialogs_smoke.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_inspect.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_preview.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_sample_qc.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_synth.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_ui_voltage.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_umap_embedding.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_voltage.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_voltage_cli.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_voltage_titration_dialog.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_warmup.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_workspace_batch_folder.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_workspace_job_driver.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_write_fcs.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_axis_floor.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_gate_units.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_partial_matrix.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_population_names.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_quadrant_export.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_sample_compensation.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_sample_keywords.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_time_units.py +0 -0
- {openflo-2.6.2 → openflo-2.7.0b2}/tests/test_wsp_writer_structure.py +0 -0
|
@@ -6,6 +6,923 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
This becomes **2.7.0b2**, the first public beta on PyPI (the version in
|
|
10
|
+
pyproject.toml); 2.7.0b1 went only to the public source mirror. It is tagged
|
|
11
|
+
as a pre-release, so `pip install openflo` keeps installing 2.6.2 until
|
|
12
|
+
`--pre` is given, and the update check offers a beta only to someone already
|
|
13
|
+
on a pre-release.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **No error disappears unseen any more.** An error in a background
|
|
17
|
+
thread, or in background work with no handler of its own, now opens the
|
|
18
|
+
same "Something went wrong" window and problem report as any other,
|
|
19
|
+
instead of only printing or only flashing in the status bar. The 418
|
|
20
|
+
places that caught every error and did nothing now catch only what they
|
|
21
|
+
expect, write a "[handled]" line to the log, or say why nothing can
|
|
22
|
+
matter there; a test keeps new ones out.
|
|
23
|
+
- **Dialogs say which setting is wrong.** Fifteen number settings
|
|
24
|
+
(Cluster, Cell cycle, Proliferation, Bead tracking, Auto-gate, Batch-norm,
|
|
25
|
+
Calibration, Embedding, MEM annotation, FMO, Spectral unmixing,
|
|
26
|
+
Trajectory, Figure layout and the layout editor's text size) refuse text
|
|
27
|
+
that is not a number in range with a message naming the setting.
|
|
28
|
+
**Behaviour change:** several used to swap a mistyped value for a default
|
|
29
|
+
without saying so, or clamp it into range; they now stop instead.
|
|
30
|
+
- **Re-fit per sample finds the valley before a bright population at the
|
|
31
|
+
top of the range.** It used to say "one population, no valley" and keep
|
|
32
|
+
the old cut when a tight population sat at the top of the data.
|
|
33
|
+
**Behaviour change:** such gates now move to the valley.
|
|
34
|
+
- **The layout editor's Layout and Export buttons** no longer show the menu
|
|
35
|
+
arrow twice.
|
|
36
|
+
- **The embedding warm-up no longer stalls.** Tk clean-up that a background
|
|
37
|
+
thread's garbage collection triggers is handed to the window's event loop
|
|
38
|
+
rather than waiting on it.
|
|
39
|
+
- **Group comparisons can come out significant at 3 to 5 samples a
|
|
40
|
+
group.** Mann-Whitney's smallest possible p at 3 vs 3 is 0.1, so two
|
|
41
|
+
groups that did not overlap at all read "not significant". Frequencies
|
|
42
|
+
and Marker expression now default to Welch's t-test (ANOVA for more
|
|
43
|
+
groups) on transformed values: percentages as log odds, counts as log,
|
|
44
|
+
intensities on the arcsinh scale (cofactor 150). The Test box keeps the
|
|
45
|
+
rank test and a t-test on raw values. **Behaviour change:** p-values in
|
|
46
|
+
those windows, Compare all, and the CLI's `compare_*.csv` (now Welch's t
|
|
47
|
+
on the logit of each sample's %) differ from earlier versions on purpose.
|
|
48
|
+
- **Paired by donor.** A tick in Frequencies and Marker expression matches
|
|
49
|
+
samples by their name with the group taken out (D1_Stim with D1_Ctrl):
|
|
50
|
+
two groups get a paired t-test (Wilcoxon signed-rank with the rank test),
|
|
51
|
+
more get a repeated-measures ANOVA (Friedman). Differential abundance
|
|
52
|
+
then models the donor as a term (`count ~ donor + group`, as diffcyt's
|
|
53
|
+
edgeR model), so a donor's own level is taken out before the groups are
|
|
54
|
+
compared. A sample with no partner is left out and named.
|
|
55
|
+
- **Saying when a test can't reach 0.05.** Every result carries the
|
|
56
|
+
smallest p its test could give at those group sizes; the summaries,
|
|
57
|
+
Compare all and Group comparison say plainly when that is above 0.05.
|
|
58
|
+
- **MESF calibration fits log-log by default.** Tools > Calibration fits
|
|
59
|
+
log MESF against log MFI, the standard for bead sets spanning decades;
|
|
60
|
+
Linear is one click away. `fit_mesf_calibration` and `apply_calibration`
|
|
61
|
+
take `model='loglog'` and keep linear as their default.
|
|
62
|
+
- **Faster `openflo-run` batches, same files.** With `--workers` above 1,
|
|
63
|
+
each sample's scatter plots and stats CSV are drawn in the worker that
|
|
64
|
+
clustered it, instead of one at a time in the main process while the
|
|
65
|
+
workers wait; group UMAPs are drawn in parallel; and `compare` takes
|
|
66
|
+
`--workers` (default up to 4) and compares samples in parallel, reporting
|
|
67
|
+
them in workspace order. The files are byte-identical to a one-worker run.
|
|
68
|
+
- **Every dialog behaves the same way.** Each window opened from the editor
|
|
69
|
+
stays in front of it (no taskbar entry of its own), Escape closes it, and
|
|
70
|
+
Return runs its main action, which sits beside Cancel or Close at the
|
|
71
|
+
right of the button row. The layout editor and a popped-out workspace stay
|
|
72
|
+
separate windows.
|
|
73
|
+
- **Errors in plain words.** An error says what failed and why ("The file
|
|
74
|
+
may be open in another program") instead of the exception's name; Show
|
|
75
|
+
details has the technical description and Copy details copies it for a
|
|
76
|
+
bug report. An unexpected error opens that window once instead of popping
|
|
77
|
+
the log and console open.
|
|
78
|
+
- **Keyboard shortcuts and About are proper windows**: shortcuts in two
|
|
79
|
+
columns by menu, and About with the version, licence, how to cite (with a
|
|
80
|
+
Copy citation button) and links.
|
|
81
|
+
- **Clearer wording.** Side-panel buttons say what they do (Delete gate,
|
|
82
|
+
Delete all, Copy gates…, Populations…, Undo, Redo, Fit, Apply to all
|
|
83
|
+
shown), beta tags moved into the tips, no arrows used as words (File >
|
|
84
|
+
Export FlowJo workspace…), sentence case, American spelling, the methods'
|
|
85
|
+
published names (PhenoGraph, t-SNE, TriMap), and the Pipeline's fields
|
|
86
|
+
named in full (Method, Neighbors, Resolution, Max events, Seed).
|
|
87
|
+
- **The title names the session**: "session name — OpenFlo", with * while
|
|
88
|
+
there are unsaved changes.
|
|
89
|
+
- **Menus regrouped, with their shortcuts.** Tools is in four groups
|
|
90
|
+
(compensation and scales, figures, utilities, templates); exports moved
|
|
91
|
+
to File, and Methods & provenance sits beside History / audit in Analyze.
|
|
92
|
+
Menus show Ctrl+Z, Ctrl+Y, Ctrl+F, the zoom keys and F5, and on macOS
|
|
93
|
+
the same keys answer to Command. F1 opens the documentation, and the main
|
|
94
|
+
window's File menu ends in Quit OpenFlo (Ctrl+Q).
|
|
95
|
+
- **No pop-up after an export.** The status bar says what was saved, with
|
|
96
|
+
an Open folder button, instead of a box to click away.
|
|
97
|
+
- **Theme: windows and plot background, chosen separately.** View > Theme
|
|
98
|
+
is Light or Dark windows, and View > Plot background is White or Black;
|
|
99
|
+
figures in analysis windows follow the plot background, so "Dark figures
|
|
100
|
+
in pop-ups" is gone. Sessions keep their theme.
|
|
101
|
+
- **Readable fonts and colours.** Windows use named fonts that follow the
|
|
102
|
+
window-width scaling and are never below 9 pt. Error, warning and success
|
|
103
|
+
text, the drag highlight and the log pane take their colours from the
|
|
104
|
+
theme, each readable at 4.5:1 or more; the log is light in the light
|
|
105
|
+
theme.
|
|
106
|
+
- **Cluster dialog**: only the picked method's settings show (FlowSOM's
|
|
107
|
+
grid and metaclusters, Leiden's resolution), and markers are listed as
|
|
108
|
+
"marker (channel)", as the axis menus show them.
|
|
109
|
+
- **Layout editor**: Ctrl+Z and Ctrl+Y undo and redo, Ctrl+S saves the
|
|
110
|
+
session (which carries the layout), and a change marks the session
|
|
111
|
+
unsaved, so closing asks to save it. The empty-page hint names the real
|
|
112
|
+
buttons and the status line wraps instead of running off the window.
|
|
113
|
+
- **Tools > Quick figure grid** is the old Figure layout, one name in the
|
|
114
|
+
menu and the window, so it is not mistaken for the layout editor.
|
|
115
|
+
|
|
116
|
+
### Added
|
|
117
|
+
- **Results record the OpenFlo version that made them (session schema
|
|
118
|
+
v3).** A gate placed by Re-place on each sample or by Auto-gate, and each
|
|
119
|
+
column written by clustering, an embedding, cell cycle, calibration or
|
|
120
|
+
pseudotime, carries a stamp: the step, the OpenFlo version and what it ran
|
|
121
|
+
on. The `.flowsession` gains a top-level `app_version`, and each sample
|
|
122
|
+
entry an `app_version` and `result_stamps` (gate stamps travel on the gate
|
|
123
|
+
as `stamp`). Saving writes an older result's stamp back unchanged, so a
|
|
124
|
+
later fix can find the results made before it. Each audit-trail entry
|
|
125
|
+
also records the version (`version`). Version-2 sessions upgrade on open,
|
|
126
|
+
their results' versions unknown; a session saved now does not open in an
|
|
127
|
+
older OpenFlo.
|
|
128
|
+
- **Fixes reach saved sessions, once and only when you say so.** When a
|
|
129
|
+
session opens, OpenFlo lists the saved results made by a version with a
|
|
130
|
+
bug since fixed: each sample's gate or column, the version that made it,
|
|
131
|
+
and its numbers before and after (events and % of parent for a gate).
|
|
132
|
+
Tick the ones to correct and Apply (one undo step); nothing changes
|
|
133
|
+
otherwise. A corrected result is recomputed with this version, its stamp
|
|
134
|
+
moves to it, and its original stays in the session (a gate's
|
|
135
|
+
`original`, a column's values under `<column> [original <version>]`,
|
|
136
|
+
out of plots and statistics). Fixes not taken are recorded and not
|
|
137
|
+
offered again; Tools > Review fixes for this session… lists them all.
|
|
138
|
+
Gates and other results built on a corrected one are offered as a
|
|
139
|
+
follow-up re-run, never started by themselves; for clusters, embeddings,
|
|
140
|
+
trajectory, cell cycle and calibration, Open… opens that tool on the
|
|
141
|
+
sample. The same list names the files exported from a corrected sample
|
|
142
|
+
before the fix (when made, by which version, whether still there), with
|
|
143
|
+
Show in folder; they are not re-exported. Plot images, Gating-ML,
|
|
144
|
+
FlowJo .wsp, population FCS folders and the Statistics, Frequencies,
|
|
145
|
+
Kinetics, workspace-comparison and differential-abundance exports are
|
|
146
|
+
recorded for it too. A changed default is
|
|
147
|
+
flagged, not applied. The first fix listed is the re-fit valley fix
|
|
148
|
+
(#78), for gates re-placed per sample before 2.7.0b2. Exports name the
|
|
149
|
+
fixes applied. The session gains `fixes_applied` and `fixes_declined`,
|
|
150
|
+
and each sample entry `result_originals`.
|
|
151
|
+
- **`openflo-run check-sessions <folder>`** lists, for every `.flowsession`
|
|
152
|
+
under a folder, the fixes that would apply to it. It only reads.
|
|
153
|
+
- **A gate moved by hand is yours.** Dragging, typing coordinates, the
|
|
154
|
+
arrow keys or a slider takes the step's stamp off the gate (its stamp
|
|
155
|
+
records the geometry it was placed with), and a pasted or copied gate
|
|
156
|
+
carries none, so a later fix never overwrites a hand edit.
|
|
157
|
+
- **A reopened session shows its gate counts and statistics at once.** Each
|
|
158
|
+
sample entry saves the counts its gates had and the Statistics window's
|
|
159
|
+
last few tables (`saved_stats`, numbers only), and a reopen uses them
|
|
160
|
+
instead of computing them again, but only when the sample's data digest,
|
|
161
|
+
the gates (and their ancestors), the statistics chosen, the Preferences
|
|
162
|
+
that change a formula and the OpenFlo version are all the same; anything
|
|
163
|
+
else is computed again as before. Measured on 6 samples of 500,000
|
|
164
|
+
events with 10 gates each: the counts were all shown 0.8 s after the last
|
|
165
|
+
sample loaded, now as each one loads; the Statistics window was ready in
|
|
166
|
+
1.1 s, now 0.25 s. Plots are not saved.
|
|
167
|
+
- **Normalize batches dialog.** Tools > Normalize batches (CytoNorm)
|
|
168
|
+
replaces the one-click batch-norm: batches by trial / day or by any FCS
|
|
169
|
+
keyword ($DATE by default), the mapping learnt from a reference sample
|
|
170
|
+
in every batch (named with a token such as "ref"; CytoNorm's standard
|
|
171
|
+
form) or from all samples (CytoNorm 2.0), 1 to 40 metaclusters, applied
|
|
172
|
+
to the loaded samples and/or written as normalized FCS copies. It shows
|
|
173
|
+
each batch before and after on a channel, the per-batch medians and a
|
|
174
|
+
methods sentence, which also goes into the audit trail. Compensation
|
|
175
|
+
controls and set-aside samples stay out of the fit. Restore original
|
|
176
|
+
values (in the dialog, or Tools > Undo batch normalization) puts the
|
|
177
|
+
loaded samples back on their pre-normalization values without reloading.
|
|
178
|
+
- **Excel workbooks and European CSV.** Statistics has Save as Excel: the
|
|
179
|
+
whole table on one sheet, then one sheet per statistic (populations
|
|
180
|
+
down, samples across), and an About sheet with the OpenFlo version.
|
|
181
|
+
Frequencies can save its tidy table as .xlsx, and `openflo-run --xlsx`
|
|
182
|
+
collects the run's CSV tables into one workbook. Preferences > Export >
|
|
183
|
+
CSV tables can follow this computer's list separator and decimal mark
|
|
184
|
+
(semicolon and decimal comma across most of Europe), so Excel opens the
|
|
185
|
+
CSV in columns; copied tables follow the same setting. The default CSV
|
|
186
|
+
is unchanged.
|
|
187
|
+
- **Set a sample aside.** Right-click a sample > Set aside from
|
|
188
|
+
comparisons, with a reason (failed QC, clogged, too few events). It stays
|
|
189
|
+
in the session and in the Statistics table (with a Set aside column),
|
|
190
|
+
is greyed with its reason in the tree, is left out of every group
|
|
191
|
+
comparison (Frequencies, Expression, Group stats, normalization) and is
|
|
192
|
+
listed with its reason in the methods text. A free-text note per sample
|
|
193
|
+
too. Both are saved in the session (additive keys an older OpenFlo
|
|
194
|
+
ignores).
|
|
195
|
+
- **Colour-blind-safe colours and keyboard gating.** Samples and groups
|
|
196
|
+
now take the Okabe-Ito colours, which stay distinct under the common
|
|
197
|
+
colour-vision deficiencies (tab10's red and green do not); View > Group
|
|
198
|
+
colors switches back to the classic palette, keeping colours you picked
|
|
199
|
+
by hand. The pipeline's `--palette auto` follows. The plot takes keyboard
|
|
200
|
+
focus (click it, or F6 from the gate list): the arrow keys move the gate
|
|
201
|
+
selected in the list, Shift for larger steps, one undo step per run of
|
|
202
|
+
presses.
|
|
203
|
+
- **Setup without Python.** `setup.bat` and `setup.sh` no longer stop when
|
|
204
|
+
no Python 3.11+ is installed (an older Python is now refused up front
|
|
205
|
+
instead of failing in pip). They use a `uv` on PATH, or download a pinned
|
|
206
|
+
uv release (Windows x86_64/ARM64, macOS Intel/Apple silicon, Linux
|
|
207
|
+
x86_64/aarch64) into `.tools/uv`, check its SHA-256 against the hash in
|
|
208
|
+
the script and refuse to continue on a mismatch, then let uv install
|
|
209
|
+
Python 3.12 and create `.venv`. An interactive Windows setup also adds
|
|
210
|
+
Desktop and Start-menu shortcuts. The scripts are not code-signed, so
|
|
211
|
+
SmartScreen or Gatekeeper may still warn.
|
|
212
|
+
- **Batch normalization helpers (library).** `openflo.batch_normalize`
|
|
213
|
+
wraps the existing CytoNorm model for acquisition-day batches: group
|
|
214
|
+
samples by any FCS keyword (`$DATE` by default in a dialog), fit on a
|
|
215
|
+
reference sample run in every batch ('controls') or on all samples
|
|
216
|
+
('goal'), apply to new frames without touching the loaded ones, a
|
|
217
|
+
per-channel, per-batch median and robust-SD before/after table with a
|
|
218
|
+
methods-report sentence, and normalized FCS copies (compensated linear
|
|
219
|
+
values, source keywords kept, `OPENFLO_NORMALIZATION` / `OPENFLO_NORM_*`
|
|
220
|
+
provenance keywords added) written to a folder. Original files are never
|
|
221
|
+
modified.
|
|
222
|
+
- **Combination gates.** Edit > Combination gates… (also on a gate's
|
|
223
|
+
right-click menu) takes 2 to 6 gates and makes every combination of
|
|
224
|
+
them, all positive to all negative, as boolean populations under the
|
|
225
|
+
gates' common parent, on every sample that has those gates; a negative
|
|
226
|
+
means in the parent and outside the gate, and an event with no value is
|
|
227
|
+
in no combination. A polyfunctionality window shows SPICE-style bars
|
|
228
|
+
per combination (group means with a dot per sample), the +/- grid and
|
|
229
|
+
pies of how many gates each positive event is in, and exports the
|
|
230
|
+
frequency table (NA where a frequency cannot be computed). The
|
|
231
|
+
combinations are ordinary gates, so they reach statistics and the
|
|
232
|
+
FlowJo export.
|
|
233
|
+
- **Typed gate coordinates.** A gate's right-click > Edit coordinates…
|
|
234
|
+
types a threshold, interval, rectangle, quadrant divider, polygon's
|
|
235
|
+
vertices or ellipse's centre and shape in the axis units (intensity;
|
|
236
|
+
1.5K reads as 1,500, a blank bound is open), optionally on the same gate
|
|
237
|
+
in every other sample. One undo step.
|
|
238
|
+
- **Gates that re-fit per sample.** A threshold or interval gate, or a
|
|
239
|
+
singlet or Gaussian-mixture gate from Auto-gate, can be re-placed on
|
|
240
|
+
each sample's own data (right-click > Re-place on each sample…): a cut
|
|
241
|
+
moves to the density valley nearest where it was drawn, and a proposal
|
|
242
|
+
is fitted again by its own rule. A grid shows every sample's old and
|
|
243
|
+
new placement before you accept; a sample with no landmark keeps its
|
|
244
|
+
gate and says why.
|
|
245
|
+
- **Compare FMO thresholds.** Edit > FMO gating has a Compare
|
|
246
|
+
thresholds button: every stained sample's % positive on each mapped
|
|
247
|
+
channel with the cutoff at each FMO percentile you list (99 and 99.5 by
|
|
248
|
+
default, i.e. 1 % and 0.5 % of FMO events above the gate), inside the
|
|
249
|
+
selected parent gate, without adding a gate. Copy or export the table.
|
|
250
|
+
- **FMO on histograms.** Once FMO gating has mapped a channel to its FMO
|
|
251
|
+
control, a histogram of that channel draws the FMO in grey behind the
|
|
252
|
+
sample, and the legend gives each one's % at or above the channel's
|
|
253
|
+
threshold gate. View > FMO on histograms turns it off. The mapping is
|
|
254
|
+
saved with the session.
|
|
255
|
+
- **Gating strategy page.** The layout editor's + Strategy (also on the
|
|
256
|
+
page menu) adds a page with one plot per gating step, each the parent
|
|
257
|
+
population on the gate's axes with its gates drawn; with a gate selected
|
|
258
|
+
in the main window, only the steps down to it. Batch export draws it for
|
|
259
|
+
every sample.
|
|
260
|
+
- **PowerPoint export.** The layout editor exports a page, or every
|
|
261
|
+
sample's pages in a batch, as a .pptx deck: one slide per page, the page
|
|
262
|
+
drawn at the export resolution and filling a slide of the page's size.
|
|
263
|
+
- **Compare with saved session.** File > Compare with saved session counts
|
|
264
|
+
every population with this session's gates and with a saved session's
|
|
265
|
+
gates, on the events loaded now, and highlights each count that moved
|
|
266
|
+
and each gate that changed.
|
|
267
|
+
- **Gate list.** File > Export gate list (CSV) writes every sample's gates
|
|
268
|
+
with their population path, kind, channels and coordinates, both as
|
|
269
|
+
stored and in linear units.
|
|
270
|
+
- **FlowJo export checks Time gates.** A Time gate whose upper edge ends
|
|
271
|
+
within the first `$TIMESTEP` fraction of the run (where an edge already
|
|
272
|
+
converted to seconds lands) now warns, with the events it cuts, since
|
|
273
|
+
OpenFlo keeps Time in ticks and converts it to seconds for FlowJo.
|
|
274
|
+
- **Derived channels.** Tools > Derived channels makes a channel computed
|
|
275
|
+
per event from others, such as the ratio of two detectors for a ratio
|
|
276
|
+
dye, FRET, or one marker over another: `[FL1-A] / [FL2-A]`,
|
|
277
|
+
`log10([FL1-A] / [FL2-A])`. Channels go in square brackets (a marker name
|
|
278
|
+
works too); + - * / ** and log, log10, log2, sqrt, exp, abs, asinh, min
|
|
279
|
+
and max can be used, and nothing else is run. It is computed on
|
|
280
|
+
compensated linear values, shows as `D:<name>` to plot, gate and
|
|
281
|
+
summarise, is saved with its formula (in the sample entry, so older
|
|
282
|
+
sessions open as before) and recomputed when a session reopens from the
|
|
283
|
+
FCS files. An event with no finite result (0 / 0) is NaN, not 0.
|
|
284
|
+
- **Kinetics.** Analyze > Kinetics follows a channel over acquisition time
|
|
285
|
+
(calcium flux, dye uptake): one binned median (or mean) trace per sample,
|
|
286
|
+
overlaid, and a table of each sample's baseline, peak after the
|
|
287
|
+
stimulus, time to peak, area over the baseline and peak / baseline, with
|
|
288
|
+
CSV and figure export. Time is in seconds when the file gives
|
|
289
|
+
`$TIMESTEP`, else in ticks, and the window says which. What can't be
|
|
290
|
+
computed (no baseline events, a baseline at 0 for the fold) reads NA.
|
|
291
|
+
- **Two windows can't overwrite one session silently.** Opening or saving a
|
|
292
|
+
session by name writes a small lock file beside it
|
|
293
|
+
(`name.flowsession.lock`) naming the computer and user. A second person,
|
|
294
|
+
or a window of another OpenFlo, is told the session is open and picks
|
|
295
|
+
Open read-only (Save then asks for a new name), Open anyway or Cancel. A
|
|
296
|
+
lock left by a crash on this computer is taken over without asking.
|
|
297
|
+
Before Save, or Save and close, writes over the file this window opened,
|
|
298
|
+
it checks the file is still the one it read or last saved; if someone
|
|
299
|
+
saved in between (or the file was deleted), it asks: Save as a copy,
|
|
300
|
+
Overwrite or Cancel. Synced folders copy lock files late, so this check
|
|
301
|
+
is what protects the data.
|
|
302
|
+
- **Every test proven to pass and to fail.** `scripts/prove_tests.py` runs
|
|
303
|
+
each test on the real code, then breaks the code it guards one change at
|
|
304
|
+
a time and records the break that made it fail. `docs/test-assurance/`
|
|
305
|
+
holds the result for all 3,420 tests (3,406 proven both ways) and the
|
|
306
|
+
method. Tests that needed a developer's own sample files now generate
|
|
307
|
+
their data, and tests that could never fail were strengthened.
|
|
308
|
+
- Hover help on the auto-gate method choices, the embedding method boxes and
|
|
309
|
+
the axis-settings parameter box.
|
|
310
|
+
- **Offline user guide.** Help > User guide (F1) opens a guide and
|
|
311
|
+
tutorial that ship with OpenFlo, so it works without a connection: ten
|
|
312
|
+
topics from a first analysis to troubleshooting, with search, and the
|
|
313
|
+
tutorial can load the example dataset. Help > Online documentation still
|
|
314
|
+
opens the web page. A test checks that every menu path the guide names
|
|
315
|
+
exists.
|
|
316
|
+
- **Dean-Jett-Fox cell cycle.** Analyze > Cell cycle fits G1 and G2/M peaks
|
|
317
|
+
and a polynomial S phase (Fox 1980) by default and reports their areas,
|
|
318
|
+
so S-phase cells under the peaks count as S (synthetic truth 56/30/14
|
|
319
|
+
read 55.8/30.5/13.6, against 53.4/29.3/17.4 by boundaries). The window
|
|
320
|
+
draws the fit and lists the boundaries result beside it; Boundaries stays
|
|
321
|
+
available, and `cell_cycle(method=...)` defaults to it.
|
|
322
|
+
- **Proliferation.** Analyze > Proliferation fits a dye-dilution histogram
|
|
323
|
+
as generations one halving apart and reports cells per generation,
|
|
324
|
+
precursor frequencies, percent divided and the division, proliferation
|
|
325
|
+
and expansion indices (Roederer 2011). The undivided peak is found, or
|
|
326
|
+
fixed at an unstimulated control's median. Too few cells read NA.
|
|
327
|
+
- **Spreading matrix for compensation.** Tools > Spreading matrix measures
|
|
328
|
+
the spillover spread of conventional compensation from compensated
|
|
329
|
+
single-stain controls, matched to their channels automatically; a
|
|
330
|
+
channel without a control reads NA. CSV and figure export.
|
|
331
|
+
- **Several autofluorescence signatures.** Spectral unmix can find up to
|
|
332
|
+
five autofluorescence spectra in the unstained control; each cell is
|
|
333
|
+
unmixed with the one that fits it best, and a U:AF index channel says
|
|
334
|
+
which. Spectral QC adds Unmixed pairs, an NxN plot of every pair of
|
|
335
|
+
unmixed fluors.
|
|
336
|
+
- **Bead tracking.** Tools > Bead tracking keeps a Levey-Jennings log of QC
|
|
337
|
+
bead runs (a CSV) and judges each run by the Westgard rules (1-3s, 2-2s,
|
|
338
|
+
R-4s, 4-1s and 10x reject; 1-2s warns).
|
|
339
|
+
- **Index-sort data.** Index-sort locations in the FCS keywords
|
|
340
|
+
(INDEX SORTING LOCATIONS, $INDEX and similar) are read, and the plate view
|
|
341
|
+
shows each sorted cell in its well, coloured by a channel.
|
|
342
|
+
- **Group samples by keyword or table.** Edit > Group samples puts the
|
|
343
|
+
samples into groups by an FCS keyword the files carry (tube, condition,
|
|
344
|
+
plate, ...) or by a sample-to-condition table (CSV or tab separated: the
|
|
345
|
+
sample or its file name, then its group), with a preview before Apply.
|
|
346
|
+
The groups are the ones the sample tree and the group statistics use.
|
|
347
|
+
- **Plate view.** Analyze > Plate view shows a 96-well plate heatmap of the
|
|
348
|
+
events, or a gate's count or percent of its parent, per well. The well
|
|
349
|
+
comes from the well keyword or the sample's name (Plate1_B07); a sample
|
|
350
|
+
without the gate reads NA, and samples without a well are listed.
|
|
351
|
+
- **Export populations, all samples.** File > Export populations, all
|
|
352
|
+
samples (FCS) writes every sample's gated populations, a folder per
|
|
353
|
+
sample.
|
|
354
|
+
- **Concatenate samples** from File: joins several samples with the same
|
|
355
|
+
channels and scales into one new sample, each event tagged with its
|
|
356
|
+
source in a `__sample__` column.
|
|
357
|
+
- **Downsampling the data can be undone.** Setting the downsample from
|
|
358
|
+
Display + data back to Display only or Off restores every event, except
|
|
359
|
+
in a sample whose data changed after the trim, which is named.
|
|
360
|
+
- **More statistics.** Analyze > Statistics adds %Grandparent, SD, robust
|
|
361
|
+
SD (half of P84.13 to P15.87), MAD, any percentiles you type (P5, P95,
|
|
362
|
+
...) and the MFI ratio: a population's median over the same population's
|
|
363
|
+
median in a reference sample you pick, such as the unstained control.
|
|
364
|
+
The column ticks sit on three rows so they fit a laptop screen, and Copy
|
|
365
|
+
table puts the table on the clipboard, tab separated, for Excel or Prism.
|
|
366
|
+
- **Editable figure text.** PDF and SVG exports keep their labels as text
|
|
367
|
+
(TrueType in PDF, `<text>` in SVG), so Illustrator and Inkscape can edit
|
|
368
|
+
them; Preferences can switch it off. Preferences also set the export
|
|
369
|
+
resolution (150 to 1200 dpi, 300 by default) and the figure font, from the
|
|
370
|
+
fonts installed. File > Copy plot to clipboard, and right-click on the
|
|
371
|
+
figure in analysis windows, copy a figure as an image.
|
|
372
|
+
- **Saturation report.** Analyze > Saturation report lists, per sample,
|
|
373
|
+
the percent of events at the top of each channel's range (`$PnR` - 1, on
|
|
374
|
+
the raw detector values) and across any channel, flags channels at 1 %
|
|
375
|
+
or more, and exports or copies the table. A channel whose range the file
|
|
376
|
+
does not give reads NA.
|
|
377
|
+
- **Gating-ML 2.0 files.** File > Export Gating-ML 2.0 gates writes the
|
|
378
|
+
active sample's gate tree in the ISAC standard other analysis tools read,
|
|
379
|
+
with each channel's scale (logicle, hyperlog, asinh as `fasinh`, log as
|
|
380
|
+
`flog`) and the sample's compensation matrix, so polygons keep their
|
|
381
|
+
shape. Templates > From file… and `openflo-run --gates-from` read them;
|
|
382
|
+
a polygon stays straight on the axes the file names. Gates Gating-ML
|
|
383
|
+
cannot hold, or OpenFlo cannot read (quadrant gates, ratio dimensions),
|
|
384
|
+
are left out with what is under them, and named.
|
|
385
|
+
- **FlowJo groups come across.** Opening a `.wsp` puts each sample in an
|
|
386
|
+
OpenFlo group named after its FlowJo group (not 'All Samples' or
|
|
387
|
+
'Compensation'), and the `.wsp` export writes OpenFlo's groups as FlowJo
|
|
388
|
+
groups. A workspace whose FCS files moved finds them in the subfolders
|
|
389
|
+
of its own folder or the FCS folder; two files of one name are told
|
|
390
|
+
apart by their folder, never guessed.
|
|
391
|
+
- **`openflo-run` reproducibility.** Each run writes `run_manifest.json`
|
|
392
|
+
(command, settings, software versions, gates, and inputs and outputs
|
|
393
|
+
with SHA-256). `--gates-from` gates every sample on one population
|
|
394
|
+
(`--gate-population`) of a GUI session, template, `.wsp` or Gating-ML
|
|
395
|
+
file. `--gate-units data` takes `--gates` in intensities instead of
|
|
396
|
+
logicle units. The comparison CSV gains `p` (Mann-Whitney U) and `p_adj`
|
|
397
|
+
(Benjamini-Hochberg), as the GUI's differential abundance has.
|
|
398
|
+
- **Project archives.** File > Export project archive saves one .zip with
|
|
399
|
+
the session, its saved data and every sample's FCS file, to send or move
|
|
400
|
+
as one file. Open session opens it directly: it unpacks beside the zip
|
|
401
|
+
and relinks the samples there. Samples whose FCS file was not found are
|
|
402
|
+
listed when exporting.
|
|
403
|
+
- **Save session as.** Save (Ctrl+S) now writes back to the session you
|
|
404
|
+
opened or last saved, and asks for a name only the first time; Save
|
|
405
|
+
session as picks a new one. The window title shows the session's name.
|
|
406
|
+
- **Exploded view of a zoom or gate in layouts.** A layout plot whose zoom
|
|
407
|
+
hides part of its data shows the whole plot with the zoomed region
|
|
408
|
+
outlined, beside a magnified copy joined to it by connector lines, on the
|
|
409
|
+
page and in Export page and Export batch. Edit… sets it per plot (Auto,
|
|
410
|
+
Always when zoomed, Off), chooses the copy's side, and can magnify one of
|
|
411
|
+
the plot's gates (its events, outline and %) instead of the zoom.
|
|
412
|
+
|
|
413
|
+
### Changed
|
|
414
|
+
- **Nothing written inside the installed package.** PhenoGraph's scratch
|
|
415
|
+
files now go to a temporary folder per run that is removed afterwards, even
|
|
416
|
+
when the run fails (they used to collect in a `.phenograph_cache` folder
|
|
417
|
+
inside the package, which is read-only on a system Python). Saved gate
|
|
418
|
+
templates now go to `~/.openflo/templates`; templates saved by an older
|
|
419
|
+
OpenFlo inside the package still show in the Templates menu.
|
|
420
|
+
- **The editor window appears sooner.** It paints before matplotlib loads
|
|
421
|
+
and the plot area fills in right after, so the window shows in about
|
|
422
|
+
0.3 s instead of 0.7 s on a warm start (more on a cold disk).
|
|
423
|
+
- **`openflo-run --help` answers at once.** Help and argument errors no
|
|
424
|
+
longer load the scientific stack (0.07 s instead of 0.8 s); the console
|
|
425
|
+
script's entry point is now `openflo.cli_args:main`.
|
|
426
|
+
- **The window keeps answering while OpenFlo works.** Dragging a gate
|
|
427
|
+
redraws only its outline, and its counts are made in the background
|
|
428
|
+
after you let go (they used to be redone on every mouse move with gates
|
|
429
|
+
applied). Zooming or changing axes no longer rebuilds the Samples & Gates
|
|
430
|
+
tree. Trajectory, Marker expression, FMO gating, cell cycle, population
|
|
431
|
+
export, Sample QC and compensation optimisation run in the background
|
|
432
|
+
with a progress bar and Cancel; layout batch export shows how far it got
|
|
433
|
+
and stops on Cancel. Results are unchanged.
|
|
434
|
+
- **Gate rows in the Samples & Gates tree show the population.** Each row
|
|
435
|
+
reads the gate's name, its event count and its frequency of the parent
|
|
436
|
+
('Cells 2,796 · 69.9%') instead of its bounds, which were cut off at the
|
|
437
|
+
panel's width. An unnamed gate is named by its channels ('FSC-A x SSC-A')
|
|
438
|
+
or its cut ('FL1-A >= 1K'). The tree widens to its longest row and
|
|
439
|
+
scrolls sideways. A population that cannot be computed reads NA.
|
|
440
|
+
- **Colouring by cluster gives each cluster its own colour**, the colour of
|
|
441
|
+
its population in the tree, with a legend naming them. It used a
|
|
442
|
+
continuous scale, so neighbouring clusters looked alike.
|
|
443
|
+
- **Groups are named after the sample's own folder** when no 'Day N' folder
|
|
444
|
+
is above it: `synth/pbmc/` and `synth/compensation/` are two groups, no
|
|
445
|
+
longer both "synth", and the example data is no longer ".openflo". A
|
|
446
|
+
generic 'Blank Experiment with…' folder still defers to the one above it.
|
|
447
|
+
- **Samples are listed by name** once loading is done, not in the order
|
|
448
|
+
they finished loading.
|
|
449
|
+
- **Gates imported from a FlowJo workspace come in ticked**, like gates
|
|
450
|
+
drawn in OpenFlo. They came in unticked.
|
|
451
|
+
- **The Add FCS and Load CSV dialogs open in the folder last picked from,**
|
|
452
|
+
else the current folder, else the home folder; never the installed
|
|
453
|
+
package's own folder.
|
|
454
|
+
- **Plots are drawn the way flow papers draw them.** Scatter (FSC, SSC)
|
|
455
|
+
and Time open on a linear axis, so the cells no longer sit squeezed into
|
|
456
|
+
one corner of a log plot. Fluorescence opens on logicle, so events at or
|
|
457
|
+
below zero keep their own positions near 0 instead of piling up on the
|
|
458
|
+
axis. Plots open in pseudocolor, coloured with Turbo, a rainbow that is
|
|
459
|
+
close to perceptually uniform (View → Density colors switches back to the
|
|
460
|
+
classic rainbow or to Viridis). A channel whose scale a session already
|
|
461
|
+
saved keeps it.
|
|
462
|
+
- **Logicle width and arcsinh cofactor can be set per axis.** The axis
|
|
463
|
+
dialog (⚙ beside X and Y) offers Logicle, Arcsinh, Log and Linear, with
|
|
464
|
+
logicle's width W and arcsinh's cofactor. These change only how the axis
|
|
465
|
+
is drawn: gates select the same events, and the data is not
|
|
466
|
+
re-transformed. The setting is saved with the session, its tabs and
|
|
467
|
+
layout items.
|
|
468
|
+
- **Gates show their name and frequency on the plot.** Each gate is drawn
|
|
469
|
+
with a solid outline and labelled with its name (when it has one) and its
|
|
470
|
+
percent of the parent, one decimal. Quadrants are labelled in their outer
|
|
471
|
+
corners, and a population that cannot be computed reads NA. View → Gate
|
|
472
|
+
labels on plots turns the labels off.
|
|
473
|
+
- **One notation for axis ticks and percentages.** Every decade on an axis
|
|
474
|
+
reads as a power of ten (10², 10³, not "100" next to "10³"). Linear axes
|
|
475
|
+
read 50K and 100K. Frequencies in the Statistics table and the status bar
|
|
476
|
+
have one decimal (93.0, not 93 or 92.96). A gate whose parent is empty
|
|
477
|
+
reads NA instead of 0.00%.
|
|
478
|
+
- **No window hides its buttons.** Statistics, Methods & provenance,
|
|
479
|
+
Absolute counts, Preferences, FCS inspector, Expression, Frequencies,
|
|
480
|
+
Calibration and Voltage optimization opened at fixed sizes too small for
|
|
481
|
+
their content, and the button row (or Update, or Detect peaks) was simply
|
|
482
|
+
not shown. Every window now opens big enough for all its controls (on a
|
|
483
|
+
scaled display too), centred on the main window and on the screen; a
|
|
484
|
+
window made smaller shrinks its table or plot, not its buttons.
|
|
485
|
+
Preferences scrolls when the screen is too short and lists themes by
|
|
486
|
+
name; the layout editor's toolbar wraps onto two rows when narrow.
|
|
487
|
+
- **Statistics tells a parent from its child.** The Population column
|
|
488
|
+
shows each gate's own name, indented under its parent, in a column as
|
|
489
|
+
wide as the names; the exported CSV keeps the full path. Statistic
|
|
490
|
+
columns are as wide as their headings.
|
|
491
|
+
- **Sharp text on scaled Windows displays.** OpenFlo declares itself
|
|
492
|
+
DPI aware, so at 125 % or 150 % Windows no longer stretches a blurry
|
|
493
|
+
96-DPI image of every window.
|
|
494
|
+
- **One answer to "is this engine available?".** Help → Environment,
|
|
495
|
+
Compare embeddings, the Cluster dialog and the Pipeline all test an
|
|
496
|
+
engine by importing it (in a separate process, once per session), so a
|
|
497
|
+
package installed without its own dependencies is shown as "fails to
|
|
498
|
+
load", with the reason, everywhere, instead of being offered and then
|
|
499
|
+
producing nothing.
|
|
500
|
+
- **No stray untitled box over a window.** It was a hover tip left behind
|
|
501
|
+
when its window closed, or was busy, under the pointer. Tips now close
|
|
502
|
+
with their window and are not shown once the pointer has left.
|
|
503
|
+
|
|
504
|
+
### Added
|
|
505
|
+
- **Compensation can be applied to the whole acquisition batch.** Apply
|
|
506
|
+
reached only the highlighted sample, so a set of files took one Apply
|
|
507
|
+
each, and its tooltip said "every loaded sample". The Compensation window
|
|
508
|
+
now has "Apply to: this sample / this batch". The batch is the samples
|
|
509
|
+
acquired like the highlighted one, read from each file's keywords rather
|
|
510
|
+
than its folder: the same instrument (`$CYTSN`, else `$CYT`), acquisition
|
|
511
|
+
date (`$DATE`) and detector voltages (`$PnV`) on the matrix's channels,
|
|
512
|
+
and the same stored spillover matrix when both files carry one. The
|
|
513
|
+
window lists the batch, and hovering it says why each other sample was
|
|
514
|
+
left out (other voltages, another date, no keywords). A file without
|
|
515
|
+
these keywords is never guessed into a batch.
|
|
516
|
+
- **Tabs in the Samples & Gates tray (beta).** A tab is a saved view: its
|
|
517
|
+
samples and gates, their on/off states, and the plot's axes, type,
|
|
518
|
+
colouring, axis types and zoom. Selecting a tab shows and plots only its
|
|
519
|
+
members and restores its plot; "All" always holds every sample. + makes a
|
|
520
|
+
tab from the selected rows (or empty); right-click a tab to rename,
|
|
521
|
+
duplicate or delete it. In the tree's right-click menu, "Copy to tab" adds
|
|
522
|
+
the selected samples or gates to a tab (a gate brings its ancestors and
|
|
523
|
+
subtree), and "Apply to other tabs" (all, or chosen) pushes their on/off
|
|
524
|
+
state to other tabs. "Within a tab (choose samples)…" applies it to only
|
|
525
|
+
the samples you find and tick in one other tab, matching gates by
|
|
526
|
+
population name. Samples and gates can also be dragged onto a tab on the
|
|
527
|
+
strip: an arranged tab (samples from several groups, or its own order)
|
|
528
|
+
holds them in a Presort zone at the top of its tree, which grows as needed
|
|
529
|
+
and vanishes when empty; drag a row out of it to place it. Any other tab
|
|
530
|
+
takes them straight to the top of its stack. Items dragged back from the
|
|
531
|
+
Pipeline onto the tree or a tab join that tab. The main plot keeps your
|
|
532
|
+
zoom through every redraw of the same view (a gate edit, a toggle, a tab
|
|
533
|
+
switch) until Reset, and each tab keeps its own. Gates are shared: an edit shows in every tab holding
|
|
534
|
+
that sample. The tabs pop out with the tray. The layout editor's "last
|
|
535
|
+
displayed" view also reads the views saved in tabs.
|
|
536
|
+
- **Sessions save the tabs and the layout (schema v2).** `.flowsession`
|
|
537
|
+
gains `view_tabs` and `layout`; version-1 sessions upgrade on open (one
|
|
538
|
+
All tab, no layout). A session saved now does not open in an older
|
|
539
|
+
OpenFlo.
|
|
540
|
+
- **Layout editor (beta).** The side panel's Layout button (was "to be
|
|
541
|
+
added") opens a FlowJo-style editor of pages: plots of gated populations,
|
|
542
|
+
stats tables (Count, %Parent, %Total and per-channel Median / Mean /
|
|
543
|
+
GeoMean / CV / rCV), violin / box / bar charts across samples, and text
|
|
544
|
+
boxes. Drag to move, drag the corner to resize, double-click to edit; an
|
|
545
|
+
optional grid, and soft snapping to grid lines and to other items' edges,
|
|
546
|
+
corners and centres, with guides. Samples and gates dragged from the
|
|
547
|
+
Samples & Gates tree or the Pipeline (docked or popped out) land as plots,
|
|
548
|
+
shown as that population was last displayed (Preferences can make it the
|
|
549
|
+
current graph instead), or join the plot, table or chart they are dropped
|
|
550
|
+
on, so several samples and populations overlay in one plot. A plot keeps
|
|
551
|
+
the axis types and zoom it was taken with; when much of its data falls
|
|
552
|
+
outside, a Zoom to fit badge offers (never applies) a refit. Cluster
|
|
553
|
+
results (PhenoGraph, Leiden, FlowSOM) colour a plot by cluster and their
|
|
554
|
+
populations can be plotted and tabulated. A View zoom (Fit, 50-200%,
|
|
555
|
+
custom) sets the on-screen resolution; Export DPI defaults to 300 (150,
|
|
556
|
+
600, 1200 or custom). Pages can be added, renamed, duplicated, items copied
|
|
557
|
+
or moved between them, and pages imported from or sent to another
|
|
558
|
+
project's layout file. The layout re-applies to every sample, matching
|
|
559
|
+
populations by name; Batch export… writes every page per sample. The
|
|
560
|
+
mouse wheel scrolls the page (Ctrl+wheel zooms it, Shift+wheel scrolls
|
|
561
|
+
sideways); over the selected plot it zooms that plot around the cursor.
|
|
562
|
+
Holding the middle
|
|
563
|
+
button drags its view, and right-click has Center zoom here, Zoom in,
|
|
564
|
+
Zoom out and Zoom to fit; the view is kept with the plot. A cross-page
|
|
565
|
+
host in the left margin keeps copies of items dragged onto it, to drag
|
|
566
|
+
onto any page or place on every page; each is listed by number, kind,
|
|
567
|
+
populations, axes and the page it came from, and can be renamed. Drag
|
|
568
|
+
the host's edge to widen it; pointing at an entry outlines the items on
|
|
569
|
+
the page that are still true duplicates of it (same populations, axes,
|
|
570
|
+
zoom, colours...) and marks (◆) the tabs of other pages that hold one.
|
|
571
|
+
Every item has a lasting id (P1, S2, C3, T4), shown in its corner on
|
|
572
|
+
screen and in the host, so look-alike plots can be told apart. The toolbar reads left to
|
|
573
|
+
right: insert, edit, the sample shown, Export (its dpi on the button, 300
|
|
574
|
+
by default) and the Layout menu; the row below holds the page tabs, page
|
|
575
|
+
size, grid, snap and the on-screen zoom. A plot dragged
|
|
576
|
+
onto a stats table or chart supplies its samples (and its populations, if
|
|
577
|
+
it has none). Each layer's colour can be set per item; a default colour
|
|
578
|
+
list (layer 1 red, 2 blue, ...) fills in, and an override toggle (off by
|
|
579
|
+
default) makes every layer use that list. A population that cannot be
|
|
580
|
+
computed reads NA in tables, gets no bar (NA instead) and no violin, and
|
|
581
|
+
its plot says so; a measured empty population still reads 0. Layouts
|
|
582
|
+
save to `.oflayout` files (version 2; version-1 files open). Also under
|
|
583
|
+
Tools → Layout editor (beta)….
|
|
584
|
+
|
|
585
|
+
### Changed
|
|
586
|
+
- **Saving and reopening sessions is much faster.** A session keeps each
|
|
587
|
+
analysed sample's events beside it. They were CSV text, and formatting
|
|
588
|
+
every value as text was most of a save: about 10 s per 300,000-event,
|
|
589
|
+
24-channel sample, holding the windows for the 5-minute autosave. They
|
|
590
|
+
are now binary (`<session>_data/<sample>.npz`, every value and type kept
|
|
591
|
+
exactly): four such samples save in 0.5 s instead of 44 s, reopen in
|
|
592
|
+
0.6 s instead of about 6 s, and take 58 MB each instead of 136 MB.
|
|
593
|
+
Sessions with CSV sidecars still open, and are converted on their next
|
|
594
|
+
save. A column the binary format can't hold (a nullable or categorical
|
|
595
|
+
one) keeps that sample on CSV.
|
|
596
|
+
- **The 5-minute autosave no longer freezes the windows.** It now writes on
|
|
597
|
+
a background thread, as the close does; a close or Save started while it
|
|
598
|
+
is writing waits for it.
|
|
599
|
+
- **The first save after opening a session no longer rewrites every
|
|
600
|
+
sample.** The sidecars the session was opened from are remembered, so the
|
|
601
|
+
autosave and the close copy an unchanged one instead of encoding it again.
|
|
602
|
+
- **Faster analysis with identical results.** Each of these gives the same
|
|
603
|
+
numbers as before, bit for bit, checked against the previous code:
|
|
604
|
+
- FlowSOM training (and CytoNorm, which uses it) runs compiled with numba,
|
|
605
|
+
already installed with UMAP: about 14 s to 1.2 s per sample at the
|
|
606
|
+
defaults.
|
|
607
|
+
- The Statistics table splits large tables across CPU cores and computes
|
|
608
|
+
only the statistics asked for: 31 s to 10 s for 2 million events, 20
|
|
609
|
+
gates and 16 channels on 4 cores, faster with more.
|
|
610
|
+
- Leiden and Louvain neighbour searches run on several cores: 7.8 s to
|
|
611
|
+
2.6 s for 50,000 events on 4 cores. Ties between equally near events
|
|
612
|
+
resolve exactly as before.
|
|
613
|
+
- Exporting a population as FCS converts the events in one step: 9.4 s to
|
|
614
|
+
1.5 s for 2 million events and 16 channels, with about 1 GB less memory,
|
|
615
|
+
and a byte-identical file.
|
|
616
|
+
- Integer FCS files that store fewer bits than their words hold (10-bit
|
|
617
|
+
data in 16 bits, for example) load about 70x faster: 8.8 s to 0.12 s for
|
|
618
|
+
2 million events and 20 channels.
|
|
619
|
+
|
|
620
|
+
### Removed
|
|
621
|
+
- **Out-of-date developer files.** DESIGN_NOTES.md (last checked against the
|
|
622
|
+
code in July, before most of the current interface) and five one-off
|
|
623
|
+
scripts nothing used: four speed benchmarks and mutate_controls.py.
|
|
624
|
+
|
|
625
|
+
### Fixed
|
|
626
|
+
- **The public mirror's CI no longer fails its privacy gate.** That job
|
|
627
|
+
and the release build's gate step ran scripts/publish_public.py, which is
|
|
628
|
+
kept out of the mirror because it holds the private token list. Both
|
|
629
|
+
now skip on the mirror; the gate still runs here before every snapshot
|
|
630
|
+
and every PyPI upload.
|
|
631
|
+
- **Compare embeddings shows Run and Cancel on a 150 % display.** The
|
|
632
|
+
window took a fixed 420x360 and packed its buttons last, so larger text
|
|
633
|
+
squeezed the button row to half height on Windows. It now takes the size
|
|
634
|
+
its content asks for.
|
|
635
|
+
- **New windows stay on a busy machine's screen.** On a loaded Windows
|
|
636
|
+
PC a window could be fitted on opening and then put back where Windows
|
|
637
|
+
first placed it, past the bottom of a laptop screen (seen with Plate
|
|
638
|
+
view at 1366x768). The editor checks the place again just after.
|
|
639
|
+
- **Help > Report a problem reaches the issue tracker.** It, and Help's
|
|
640
|
+
documentation link, opened the private development repository, a 404 for
|
|
641
|
+
everyone else. They open openflo-public now, and a test fails on any link
|
|
642
|
+
to the private repository in what ships.
|
|
643
|
+
- **FCS files with common writer quirks open.** A file whose $ENDDATA is
|
|
644
|
+
one byte off, whose HEADER and TEXT disagree on where the data starts, or
|
|
645
|
+
that chains a second data set with $NEXTDATA was refused and reported as
|
|
646
|
+
"cut short" or "damaged". Each now loads (the first data set, for a
|
|
647
|
+
chained file) with a load warning naming the quirk; the compensation
|
|
648
|
+
readers and the FCS inspector read them too. A file that is really
|
|
649
|
+
damaged still fails, with a message that names the quirk when one is the
|
|
650
|
+
cause.
|
|
651
|
+
- **Clustering and the FlowSOM tree repeat with their seed.** igraph has no
|
|
652
|
+
number seed: `layout_fruchterman_reingold(seed=)` takes starting
|
|
653
|
+
positions, so the tree layout was drawn differently every time. It now
|
|
654
|
+
runs on a generator seeded from `seed`. Louvain left igraph on a fresh,
|
|
655
|
+
unseeded generator after each run, so `random.seed()` stopped controlling
|
|
656
|
+
igraph for the rest of the session; it now hands back the default.
|
|
657
|
+
PhenoGraph's seeded Leiden backend stays the default, as before.
|
|
658
|
+
- **Leiden noise reads as noise.** Its unassigned bucket imported as
|
|
659
|
+
"leiden -1" in a palette colour and the Populations menu left Leiden out;
|
|
660
|
+
it is grey and named "Unassigned (noise)", and the menu lists it (other
|
|
661
|
+
Leiden populations keep their names, such as "leiden 3").
|
|
662
|
+
- **`python -m openflo.inspect_fcs` lists the channel keywords** again
|
|
663
|
+
(flowio 1.x returns them lower-case, without the `$`).
|
|
664
|
+
- **The update check never offers a beta to someone on a final release**,
|
|
665
|
+
and without the `packaging` module a beta no longer sorts above its own
|
|
666
|
+
final release.
|
|
667
|
+
- **The README's licence note** said OpenFlo does not import igraph and
|
|
668
|
+
leidenalg (both GPL) directly; it does, and the note says so.
|
|
669
|
+
- **The Cluster dialog starts FlowSOM at 20 metaclusters, and says why.**
|
|
670
|
+
Asked for exactly as many metaclusters as there are populations, FlowSOM
|
|
671
|
+
merged a rare (1.5%) population into a neighbour (F1 0.22; 0.99 with 12).
|
|
672
|
+
The dialog now starts at 20 (was 10), notes "set above the populations
|
|
673
|
+
you expect" beside the field, and its hover tip explains the reason and
|
|
674
|
+
how to join extra metaclusters with an OR gate. **Behaviour change:**
|
|
675
|
+
FlowSOM runs from the dialog at its default now make 20 metaclusters, not
|
|
676
|
+
10. The CLI and the Python API keep 10.
|
|
677
|
+
- **A 30-channel recovery test for every clustering method.** Eight planted
|
|
678
|
+
populations in a lineage tree, one of them rare (1.5%): PhenoGraph, Leiden
|
|
679
|
+
and Louvain must recover all eight (ARI >= 0.95, each population F1 >=
|
|
680
|
+
0.9), FlowSOM the seven common ones, and the rare one when asked for more
|
|
681
|
+
metaclusters than populations. The same checks must fail on data with no
|
|
682
|
+
structure and on random labels.
|
|
683
|
+
- **macOS is tested on the public mirror.** A macOS job in ci.yml runs only
|
|
684
|
+
on openflo-public, where GitHub's macOS runners are free (they bill at ten
|
|
685
|
+
times Linux on the private repository), so each mirror refresh runs the
|
|
686
|
+
suite with the GUI on macOS.
|
|
687
|
+
- **The PyPI release waits for the tests.** A version tag ran only the type
|
|
688
|
+
check before building and publishing; it now runs the whole CI workflow
|
|
689
|
+
(tests with the GUI, type check, privacy gate, install checks) first.
|
|
690
|
+
- **A status message stays put after the gate tree rebuilds.** On Windows,
|
|
691
|
+
adding FMO gates (or an FMO refusal) could have its message replaced by the
|
|
692
|
+
selected gate's count, because the tree re-selecting its own row was taken
|
|
693
|
+
for a click.
|
|
694
|
+
- **The editor opens on Tk 9.** The drag-and-drop package pinned at 0.4.3
|
|
695
|
+
stopped OpenFlo from starting on any Python that ships Tk 9 (uv's 3.14
|
|
696
|
+
and 3.15 builds, python.org's macOS installer from 3.14.5). It is now
|
|
697
|
+
0.6.4, and if drag-and-drop still can't load, the editor opens without it
|
|
698
|
+
instead of not at all.
|
|
699
|
+
- **Identical groups keep p = 1 with SciPy 1.18.** SciPy 1.18 returns NaN
|
|
700
|
+
for a Mann-Whitney test where every value is the same, so a cluster or
|
|
701
|
+
population with the same share in both groups read NA in the comparison
|
|
702
|
+
CSV, differential abundance and group statistics. It is 1 again on every
|
|
703
|
+
SciPy.
|
|
704
|
+
- **Cluster populations of a sample reopened without its clustering read
|
|
705
|
+
NA, not 0.** A session whose processed data was not found reloads that
|
|
706
|
+
sample from its FCS file, without the cluster column: every cluster read
|
|
707
|
+
0 events under a group holding all of them. They now read NA, and the
|
|
708
|
+
load says which results were not found.
|
|
709
|
+
- **A session keeps its previous save.** Saving over a session keeps the
|
|
710
|
+
earlier version as `name.backup.flowsession`. A session that can't be read
|
|
711
|
+
says so in plain words and offers that backup, and resuming after a crash
|
|
712
|
+
skips a damaged autosave for the newest one that reads.
|
|
713
|
+
- **Save and close updates the session you opened.** It used to write only
|
|
714
|
+
the autosave, so the file you opened was left as it was at your last
|
|
715
|
+
save.
|
|
716
|
+
- **Problems found while loading are shown.** A renamed channel, an event
|
|
717
|
+
count that disagrees with the data, a spillover matrix that could not be
|
|
718
|
+
used, or a workspace population that was not imported went only to the
|
|
719
|
+
log or to a status line the next sample overwrote. They now appear
|
|
720
|
+
together in one "Notes from loading" window and are kept in the history.
|
|
721
|
+
- **Damaged or unusual FCS files.** A parameter without `$PnN` is named
|
|
722
|
+
`Ch<n>`; one without `$PnR` takes the range its `$PnB` allows (as FlowJo
|
|
723
|
+
does); two channels with one name load as `FL1-A` and `FL1-A (2)`; and a
|
|
724
|
+
cut-short or non-FCS file says so in plain words instead of showing a
|
|
725
|
+
parser error.
|
|
726
|
+
- **Spillover keywords that name markers.** A `$SPILLOVER` listing marker
|
|
727
|
+
names (`$PnS`) instead of detectors is matched to the detectors when each
|
|
728
|
+
marker belongs to exactly one, instead of leaving the sample
|
|
729
|
+
uncompensated. Values past the end of the matrix are reported.
|
|
730
|
+
- **CSV files in common layouts.** Load CSV detects semicolon, tab and bar
|
|
731
|
+
separators and decimal commas, skips `#` comment lines at the top, keeps
|
|
732
|
+
the first event of a file with no header row (columns `Ch1`, `Ch2`, ...),
|
|
733
|
+
and refuses a file with no numeric column in plain words.
|
|
734
|
+
- **Undo after compensation or a transform change.** Undo can't reverse
|
|
735
|
+
those, and it used to undo the gate change made before them without a
|
|
736
|
+
word. It now says it can't, and the next Undo goes on to the gate change.
|
|
737
|
+
Undo no longer brings back the gates of a removed sample.
|
|
738
|
+
- **Exported FCS files keep their keywords.** Every keyword from the source
|
|
739
|
+
that does not describe the file's layout is carried over (`$SRC`, `$OP`,
|
|
740
|
+
tube and well names and more; the source's `$FIL` as
|
|
741
|
+
`OPENFLO_SOURCE_FIL`), and the matrix the values were compensated with is
|
|
742
|
+
recorded as `OPENFLO_APPLIED_MATRIX`. Keywords about compensation are not
|
|
743
|
+
carried, so no reader compensates the values twice.
|
|
744
|
+
- **A session sample whose FCS file is missing is no longer deleted by the
|
|
745
|
+
next save.** Opening a session skipped a sample whose file had moved, and
|
|
746
|
+
the save or autosave after it wrote the session without it and its gates.
|
|
747
|
+
The sample is now kept offline and saved back unchanged, and after opening
|
|
748
|
+
OpenFlo offers to look for the missing files in a folder (and its
|
|
749
|
+
subfolders) and relinks them by file name.
|
|
750
|
+
- **A session's saved data cut short no longer loads part of a sample.** The
|
|
751
|
+
per-sample data beside a session is written whole or not at all, and one
|
|
752
|
+
that is damaged or holds fewer rows than recorded is rebuilt from the
|
|
753
|
+
sample's FCS file, with a warning.
|
|
754
|
+
- **Log-amplified and gain-adjusted FCS files load as intensities**
|
|
755
|
+
(behaviour change). Integer data with `$PnE` log amplification was read as
|
|
756
|
+
raw channel numbers and `$PnG` was ignored; both are now applied on load
|
|
757
|
+
and recorded in the history. A session holding such a file now reads it
|
|
758
|
+
as intensities. Float data is left as stored.
|
|
759
|
+
- **A gate on a channel a sample lacks reads NA with the reason**
|
|
760
|
+
(behaviour change). It used to admit every event, so the population read
|
|
761
|
+
100%. It now admits none and Statistics, the report and the tree show NA
|
|
762
|
+
("channel X is not in this sample").
|
|
763
|
+
- **FlowJo AND / OR / NOT gates are imported from and written to .wsp.**
|
|
764
|
+
They were dropped on import without a word, with everything under them.
|
|
765
|
+
An operand that can't be found reads NA with a warning.
|
|
766
|
+
- **Pipeline (beta) says when an embedding can't run.** TriMap was ticked by
|
|
767
|
+
default, and without the `[embed]` extra it was skipped with nothing but a
|
|
768
|
+
log line: the run ended "Done: 4 ok" with no TriMap output. PHATE, TriMap
|
|
769
|
+
and PaCMAP are now unticked and disabled in the panel when not installed
|
|
770
|
+
(the tooltip says how to install them), and a run that asks for one anyway,
|
|
771
|
+
or whose embedding fails or makes no plot, lists it in the run's summary.
|
|
772
|
+
- **The highlighted sample is always one on the plot.** After loading
|
|
773
|
+
several files the first was plotted but the last to arrive was
|
|
774
|
+
highlighted, so a gate drawn with "all shown" went to both and
|
|
775
|
+
compensation went to a sample not on screen. Now the plotted sample is the
|
|
776
|
+
highlighted one after a load, highlighting an unticked sample ticks it,
|
|
777
|
+
clicking a ☑/☐ box no longer moves the highlight, and unticking the
|
|
778
|
+
highlighted sample moves the highlight to one still plotted.
|
|
779
|
+
- **The Copy gates dialog shows its Copy button.** Its four buttons sat in
|
|
780
|
+
one row about 560 px wide inside a 420 px dialog, so Copy, packed last,
|
|
781
|
+
got no room and only appeared if you widened the window. Select all /
|
|
782
|
+
Deselect all and Copy / Cancel now sit on two rows of a 460 px dialog.
|
|
783
|
+
- **Copying gates no longer stacks duplicates.** Copying appended every
|
|
784
|
+
gate, so a sample that already held it (copied before, or drawn there with
|
|
785
|
+
"all shown") got a second, identical-looking row. A gate the target
|
|
786
|
+
already has is now reused; the same population drawn differently (same
|
|
787
|
+
kind, axes and name, under the same parent, and only one such) takes the
|
|
788
|
+
copied geometry in place, keeping its id, on/off state and children; the
|
|
789
|
+
status line counts both. Anything less certain is appended as before.
|
|
790
|
+
- **A FlowJo export names each unnamed gate the same in every sample.**
|
|
791
|
+
An unnamed gate was written under the editor's per-sample gate id, so
|
|
792
|
+
the same gate could be `g2` in one sample and `g3` in the next (any
|
|
793
|
+
sample that had once had a gate deleted numbered on from there). FlowJo
|
|
794
|
+
matches populations across samples by name, so its tables and group gates
|
|
795
|
+
didn't line up. An unnamed gate is now named for its axes (`FSC-A x
|
|
796
|
+
SSC-A`, or the channel of a 1-D gate), and siblings with the same name get
|
|
797
|
+
`(2)`, `(3)`. Before: 6-sample export, populations `g1`/`g2`/`g3` with
|
|
798
|
+
ctrl_d1 off by one. After: `FSC-A x SSC-A` / `FL1-A x FL2-A` in all six.
|
|
799
|
+
- **Closing a large session no longer freezes OpenFlo.** "Save and close"
|
|
800
|
+
saved on the window thread, rewriting every sample's processed-data CSV:
|
|
801
|
+
about a minute for a large session, with every window marked "Not
|
|
802
|
+
Responding" and no message, and each extra click on ✕ queued another full
|
|
803
|
+
save. The save now runs in the background behind a "Saving session… n of
|
|
804
|
+
N samples" window, extra clicks only bring that window forward, and a
|
|
805
|
+
sample's CSV is rewritten only when its data changed since the last save,
|
|
806
|
+
which also makes the 5-minute autosave quick when nothing changed.
|
|
807
|
+
- **Closing asks whether to save the session.** ✕ autosaved every time,
|
|
808
|
+
and a large session (every sample's data rewritten) froze every window
|
|
809
|
+
for up to a minute with no message, so the windows looked as if they
|
|
810
|
+
would not close; each further ✕ queued another save. It now asks: Save
|
|
811
|
+
and close, Close without saving, or Cancel. A second ✕ while closing is
|
|
812
|
+
ignored. (A stop-gap: making the save itself fast is its own change.)
|
|
813
|
+
- **The update offer asks Update or Cancel.** It asked Yes / No / Cancel,
|
|
814
|
+
and No opened the release page: three ways to say yes. The release notes
|
|
815
|
+
link is now in the question's text.
|
|
816
|
+
- **Export to FlowJo keeps gates on a channel of unknown scale.** A column
|
|
817
|
+
of an older OpenFlo CSV with no transform record has no transform to undo,
|
|
818
|
+
so its gates reached FlowJo in display units with only a log line (an
|
|
819
|
+
asinh cut at 4.0 became an intensity of 4.0). When the sample's raw FCS
|
|
820
|
+
can be read, the channel is now matched to it rank for rank, as FlowJo
|
|
821
|
+
will gate it, and the gate keeps its events (a cut exactly, a polygon to
|
|
822
|
+
within its re-traced edges). Without the FCS the gate is still written,
|
|
823
|
+
as stored. Either way a warning after the export names each such gate.
|
|
824
|
+
- **A sample on the same transform with other settings is put on the
|
|
825
|
+
editor's.** A library export on asinh cofactor 5 loaded beside samples on
|
|
826
|
+
the editor's asinh (cofactor 150) kept cofactor 5: the same events plotted
|
|
827
|
+
at median 4.45 beside 1.16, its axis labels were wrong, and the Expression
|
|
828
|
+
window pooled both scales into one violin. The parameters are now compared,
|
|
829
|
+
not just the method, for the first sample too. A restored session's gates
|
|
830
|
+
move with the data: a cut drawn on cofactor 5 held 380 of 800 events, and
|
|
831
|
+
without converting it held none after reopening.
|
|
832
|
+
- **A population that cannot be computed reads NA, not 0.** A gate whose
|
|
833
|
+
region is unknown (a FlowJo ellipse not converted, a boolean that lost an
|
|
834
|
+
operand, an ellipse whose covariance describes no ellipse) selects
|
|
835
|
+
nothing, and so does every gate under it or built on it. Statistics,
|
|
836
|
+
Frequencies and its comparisons, the report and the gate's status line
|
|
837
|
+
showed that as a measured 0 events. They now show NA with the reason,
|
|
838
|
+
Frequencies leaves it out as missing, and the tidy CSV writes NA.
|
|
839
|
+
- NOT or OR over such an ellipse now admits no events too; NOT over it
|
|
840
|
+
admitted every event.
|
|
841
|
+
- **A FlowJo gate imported onto a channel of unknown scale reads NA.** Its
|
|
842
|
+
coordinates are in FlowJo's linear units and cannot be converted to a
|
|
843
|
+
channel whose display scale is unknown (an older OpenFlo CSV with no
|
|
844
|
+
transform record). It was kept as is, comparing a linear cut against
|
|
845
|
+
values on another scale, with only a log warning. It is now kept but
|
|
846
|
+
selects nothing, and its population, everything under it and every
|
|
847
|
+
boolean built on it read NA with the reason.
|
|
848
|
+
- **`openflo-run`'s shared clustering and comparison files.**
|
|
849
|
+
- A run with one group removes an earlier two-group run's comparison
|
|
850
|
+
files (`compare_<A>_vs_<B>.csv`/`.png`, `compare_shared_clusters.csv`)
|
|
851
|
+
and says so, instead of leaving them as if it had made them. A file
|
|
852
|
+
that cannot be removed is named and the run exits 1.
|
|
853
|
+
- Channel labels match across samples despite common real spellings: a
|
|
854
|
+
fluor name at either end ('CD3 FL5' on FL3-A), Greek letters
|
|
855
|
+
('CD8α' = 'CD8a') and detector names that differ only in case
|
|
856
|
+
('FL7-A' / 'fl7-a'). Such channels were dropped before.
|
|
857
|
+
- Pooled and unpooled events follow one noise rule: each finite event
|
|
858
|
+
takes the label of its nearest labelled pooled event, so a sample's
|
|
859
|
+
"Unclustered (noise)" share no longer scales with how much of it was
|
|
860
|
+
pooled. Only rows with a non-finite marker value stay noise.
|
|
861
|
+
- The shared PhenoGraph's RAM check applies with the default
|
|
862
|
+
`--workers 1` too; with too little free RAM it runs on one core and
|
|
863
|
+
says why.
|
|
864
|
+
- **The compensation editor's Apply keeps what was computed on the
|
|
865
|
+
sample.** Apply replaced the sample's data with a fresh load of its FCS.
|
|
866
|
+
Clusters, embeddings, U: abundances and _pos flags were lost, so their
|
|
867
|
+
populations selected no events and gates on them selected every event. A
|
|
868
|
+
downsampled sample came back with all its events.
|
|
869
|
+
- Apply now re-compensates the sample's own events in place: every event
|
|
870
|
+
and column stays, and each channel keeps its transform.
|
|
871
|
+
- The status line names what was computed before the change and asks
|
|
872
|
+
you to re-run it.
|
|
873
|
+
- A sample opened from a CSV with no record of its compensation and no
|
|
874
|
+
FCS behind it is refused, with the reason. It used to fail with "could
|
|
875
|
+
not parse FCS".
|
|
876
|
+
- **A session with Leiden or FlowSOM populations can be saved.** Saving,
|
|
877
|
+
and the autosaves, failed with "Object of type int64 is not JSON
|
|
878
|
+
serializable".
|
|
879
|
+
- **Gates that cannot be evaluated select nothing, and say so.**
|
|
880
|
+
- A boolean gate over a boolean that lost an operand (or over a gate
|
|
881
|
+
under one) now admits no events. With the inner boolean empty, NOT over
|
|
882
|
+
it admitted every event, and OR with it was the other operand alone.
|
|
883
|
+
Clear, Cut, session restore, .wsp ingest and template apply now also
|
|
884
|
+
name the booleans built on a broken one.
|
|
885
|
+
- An ellipse whose covariance is singular or not positive definite
|
|
886
|
+
admits no events instead of every event. Exported to FlowJo it is still
|
|
887
|
+
the all-pass rectangle, and the warning says FlowJo will count every
|
|
888
|
+
event.
|
|
889
|
+
- **Open-sided gates are drawn in full on every view.** A quadrant, an
|
|
890
|
+
imported max-only range, or a polygon opened at an axis end drew only part
|
|
891
|
+
of its outline on a fluorescence channel's log and symlog views (no
|
|
892
|
+
outline at all on symlog). An open interval bound no longer draws a line
|
|
893
|
+
or stretches a linear view to ±1e12.
|
|
894
|
+
- **Editing overlapping polygons grabs the nearest vertex.** A click on one
|
|
895
|
+
polygon's corner took the first-drawn polygon's corner ~9 px away; the
|
|
896
|
+
nearest vertex (then the nearest edge) of all polygons now wins.
|
|
897
|
+
- **FMO gates are placed at the FMO's linear cutoff.** The FMO dialog took
|
|
898
|
+
the percentile in the FMO tube's own display coordinates and used it as a
|
|
899
|
+
gate value on the stained sample. An FMO on asinh cofactor 5 beside a
|
|
900
|
+
stained sample on cofactor 150 called 5.36% positive where 50.52% is
|
|
901
|
+
right; an FMO of unknown scale gave 0.0%.
|
|
902
|
+
- The cutoff is the FMO's percentile on its linear values, mapped into the
|
|
903
|
+
stained sample's display coordinates. With a parent gate selected, the
|
|
904
|
+
FMO is read through it in the stained sample's coordinates.
|
|
905
|
+
- An FMO or stained channel of unknown scale is refused, and the status
|
|
906
|
+
names the channel, the FMO and why.
|
|
907
|
+
- **A logicle scale inferred from the value range is marked as a guess.**
|
|
908
|
+
A column of an older OpenFlo CSV with no transform record, whose values
|
|
909
|
+
all lie in the logicle range, was taken as logicle. A dim channel on asinh
|
|
910
|
+
falls in that range too: Statistics reported a linear median of 1793.94
|
|
911
|
+
where 80.56 is right.
|
|
912
|
+
- The entry is kept as logicle but marked guessed, through re-saves,
|
|
913
|
+
session restore, re-transforms and pooled Workspace runs.
|
|
914
|
+
- Its statistics are titled "(linear, guessed logicle)" in the Statistics
|
|
915
|
+
window and its CSV. Expression and Group comparison name the samples
|
|
916
|
+
whose medians rest on a guess.
|
|
917
|
+
- **`marker_expression` names the samples it could not use.** A sample of
|
|
918
|
+
unknown scale went into `differential_test` as NaN and was dropped
|
|
919
|
+
without a word. The groups now list omitted and guessed samples, and each
|
|
920
|
+
result row carries `omitted_a/b` and `guessed_a/b`.
|
|
921
|
+
- **Compensation-control names.** The rule took any word ending in "comp"
|
|
922
|
+
("recomp", "precomp", "Decomp_1", "Autocomp", "TComp_1") as a compensation
|
|
923
|
+
control. It now names the bead brands written as one word (UltraComp,
|
|
924
|
+
OneComp, VersaComp, AbC, ArC). "Non-comp" and "No-comp" are samples.
|
|
925
|
+
|
|
9
926
|
## [2.6.2] - 2026-10-09
|
|
10
927
|
|
|
11
928
|
### Changed
|