FlowCyPy 0.5.7__tar.gz → 0.5.8__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.
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/_version.py +2 -2
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/cytometer.py +111 -78
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/flow_cell.py +7 -7
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/noises.py +6 -1
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy.egg-info/PKG-INFO +1 -1
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy.egg-info/SOURCES.txt +2 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/PKG-INFO +1 -1
- flowcypy-0.5.8/developments/scripts/concentration_comparison.py +109 -0
- flowcypy-0.5.8/developments/scripts/dev_temp.py +96 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/density_plots/1_populations.py +2 -1
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/density_plots/2_populations.py +3 -2
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/density_plots/3_populations.py +2 -1
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/density_plots/custom_populations.py +2 -1
- flowcypy-0.5.8/docs/examples/tutorials/limit_of_detection.py +114 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/tutorials/workflow.py +2 -2
- flowcypy-0.5.8/docs/source/internal/objectives/main.rst +111 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/sg_execution_times.rst +16 -16
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_flow_cytometer.py +4 -4
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_peak_analyzer.py +2 -2
- flowcypy-0.5.7/developments/scripts/dev_temp.py +0 -154
- flowcypy-0.5.7/docs/source/internal/objectives/main.rst +0 -83
- {flowcypy-0.5.7 → flowcypy-0.5.8}/.flake8 +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/.github/dependabot.yml +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/.github/workflows/deploy_PyPi.yml +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/.github/workflows/deploy_anaconda.yml +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/.github/workflows/deploy_coverage.yml +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/.github/workflows/deploy_documentation.yml +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/.gitignore +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/__init__.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/classifier.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/coupling_mechanism/__init__.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/coupling_mechanism/empirical.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/coupling_mechanism/mie.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/coupling_mechanism/rayleigh.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/coupling_mechanism/uniform.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/detector.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/directories.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/__init__.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/base_class.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/delta.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/lognormal.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/normal.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/particle_size_distribution.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/uniform.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/distribution/weibull.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/event_correlator.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/helper.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/logger.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/particle_count.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/peak_locator/__init__.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/peak_locator/base_class.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/peak_locator/basic.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/peak_locator/derivative.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/peak_locator/moving_average.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/physical_constant.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/population.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/populations_instances.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/scatterer_collection.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/source.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/units.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy/utils.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy.egg-info/dependency_links.txt +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy.egg-info/requires.txt +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/FlowCyPy.egg-info/top_level.txt +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/LICENSE +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/README.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/Untitled.ipynb +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/doc/internship.pdf +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/create_images.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/data_analysis.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/dev_beads_analysis.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/dev_canto.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/dev_classifier.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/dev_shot_noise_check.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/dev_study_on_ri.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/dev_study_on_size.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/mat2csv.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/developments/scripts/profiler.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/Makefile +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/density_plots/README.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/extras/README.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/extras/distributions.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/extras/flow_cytometer_signal.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/extras/full_workflow.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/extras/scatterer_distribution.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/noise_sources/README.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/noise_sources/dark_current.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/noise_sources/shot_noise.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/noise_sources/thermal.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/examples/tutorials/README.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/distributions/Delta.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/distributions/LogNormal.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/distributions/Normal.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/distributions/RosinRammler.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/distributions/Uniform.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/distributions/Weibull.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/example_0.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/example_1.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/example_2.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/example_3.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/flow_cytometer.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/images/logo.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/make.bat +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/_static/default.css +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/_static/logo.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/_static/thumbnail.png +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/analysis.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/base.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/detector.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/distributions.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/flow_cell.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/flow_cytometer.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/peak_locator.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/scatterer.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code/source.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/code.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/conf.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/examples.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/index.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/core_components.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/getting_started.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/objectives/pre.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/objectives/stretch.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/prerequisites/index.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/prerequisites/mathematics.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/prerequisites/optics.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/prerequisites/programming.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/ressources.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal/tasks.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/internal.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/references.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/docs/source/theory.rst +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/meta.yaml +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/notebook.ipynb +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/pyproject.toml +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/setup.cfg +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/__init__.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_coupling_mechanism.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_detector_noise.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_distribution.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_extra.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_noises.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_peak_algorithm.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_population.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_scatterer_distribution.py +0 -0
- {flowcypy-0.5.7 → flowcypy-0.5.8}/tests/test_source.py +0 -0
|
@@ -76,6 +76,7 @@ class FlowCytometer:
|
|
|
76
76
|
self.detectors = detectors
|
|
77
77
|
self.coupling_mechanism = coupling_mechanism
|
|
78
78
|
self.background_power = background_power
|
|
79
|
+
self.plot = self.PlotInterface(self)
|
|
79
80
|
|
|
80
81
|
assert len(self.detectors) == 2, 'For now, FlowCytometer can only take two detectors for the analysis.'
|
|
81
82
|
assert self.detectors[0].name != self.detectors[1].name, 'Both detectors cannot have the same name'
|
|
@@ -85,7 +86,7 @@ class FlowCytometer:
|
|
|
85
86
|
Computes and assigns the optical coupling power for each particle-detection event.
|
|
86
87
|
|
|
87
88
|
This method evaluates the coupling between the scatterers in the flow cell and the detectors
|
|
88
|
-
using the specified detection mechanism. The computed coupling power is stored in the
|
|
89
|
+
using the specified detection mechanism. The computed coupling power is stored in the
|
|
89
90
|
`scatterer_collection` dataframe under detector-specific columns.
|
|
90
91
|
|
|
91
92
|
Updates
|
|
@@ -98,7 +99,7 @@ class FlowCytometer:
|
|
|
98
99
|
------
|
|
99
100
|
ValueError
|
|
100
101
|
If an invalid coupling mechanism is specified during initialization.
|
|
101
|
-
"""
|
|
102
|
+
"""
|
|
102
103
|
detection_mechanism = self._get_detection_mechanism()
|
|
103
104
|
|
|
104
105
|
for detector in self.detectors:
|
|
@@ -109,7 +110,7 @@ class FlowCytometer:
|
|
|
109
110
|
)
|
|
110
111
|
|
|
111
112
|
self.scatterer_collection.dataframe["detector: " + detector.name] = pint_pandas.PintArray(self.coupling_power, dtype=self.coupling_power.units)
|
|
112
|
-
|
|
113
|
+
|
|
113
114
|
self._generate_pulse_parameters()
|
|
114
115
|
|
|
115
116
|
def initialize_signal(self) -> None:
|
|
@@ -124,11 +125,11 @@ class FlowCytometer:
|
|
|
124
125
|
Each detector's `raw_signal` attribute is initialized with time-dependent values
|
|
125
126
|
based on the flow cell's runtime.
|
|
126
127
|
|
|
127
|
-
"""
|
|
128
|
+
"""
|
|
128
129
|
# Initialize the detectors
|
|
129
130
|
for detector in self.detectors:
|
|
130
131
|
detector.source = self.source
|
|
131
|
-
detector.init_raw_signal(run_time=self.flow_cell.run_time)
|
|
132
|
+
detector.init_raw_signal(run_time=self.flow_cell.run_time)
|
|
132
133
|
|
|
133
134
|
def simulate_pulse(self) -> None:
|
|
134
135
|
"""
|
|
@@ -260,84 +261,13 @@ class FlowCytometer:
|
|
|
260
261
|
)
|
|
261
262
|
|
|
262
263
|
self.pulse_dataframe = pd.DataFrame(columns=columns)
|
|
263
|
-
|
|
264
|
+
|
|
264
265
|
self.pulse_dataframe['Centers'] = self.scatterer_collection.dataframe['Time']
|
|
265
266
|
|
|
266
267
|
widths = self.source.waist / self.flow_cell.flow_speed * np.ones(self.scatterer_collection.n_events)
|
|
267
268
|
|
|
268
269
|
self.scatterer_collection.dataframe['Widths'] = pint_pandas.PintArray(widths, dtype=widths.units)
|
|
269
270
|
|
|
270
|
-
def plot(self, figure_size: tuple = (10, 6), add_peak_locator: bool = False, show: bool = True) -> None:
|
|
271
|
-
"""
|
|
272
|
-
Visualizes the raw signals for all detector channels along with the scatterer distribution.
|
|
273
|
-
|
|
274
|
-
Parameters
|
|
275
|
-
----------
|
|
276
|
-
figure_size : tuple, optional
|
|
277
|
-
Dimensions of the generated plot (default: (10, 6)).
|
|
278
|
-
add_peak_locator : bool, optional
|
|
279
|
-
If True, adds visual markers for detected signal peaks (default: False).
|
|
280
|
-
|
|
281
|
-
Effects
|
|
282
|
-
-------
|
|
283
|
-
Displays a multi-panel plot showing:
|
|
284
|
-
- Raw signals for each detector channel.
|
|
285
|
-
- Scatterer distribution along the time axis.
|
|
286
|
-
"""
|
|
287
|
-
logging.info("Plotting the signal for the different channels.")
|
|
288
|
-
|
|
289
|
-
n_detectors = len(self.detectors)
|
|
290
|
-
|
|
291
|
-
with plt.style.context(mps):
|
|
292
|
-
_, axes = plt.subplots(ncols=1, nrows=n_detectors + 1, figsize=figure_size, sharex=True, sharey=True, gridspec_kw={'height_ratios': [1, 1, 0.4]})
|
|
293
|
-
|
|
294
|
-
time_unit, signal_unit = self.detectors[0].plot(ax=axes[0], show=False, add_peak_locator=add_peak_locator)
|
|
295
|
-
self.detectors[1].plot(ax=axes[1], show=False, time_unit=time_unit, signal_unit=signal_unit, add_peak_locator=add_peak_locator)
|
|
296
|
-
|
|
297
|
-
axes[-1].get_yaxis().set_visible(False)
|
|
298
|
-
self.scatterer_collection.add_to_ax(axes[-1])
|
|
299
|
-
|
|
300
|
-
# Add legends to each subplot
|
|
301
|
-
for ax in axes:
|
|
302
|
-
ax.legend()
|
|
303
|
-
|
|
304
|
-
if show: # Display the plot
|
|
305
|
-
plt.show()
|
|
306
|
-
|
|
307
|
-
def plot_coupling_density(self, log_scale: bool = False, show: bool = True) -> None:
|
|
308
|
-
"""
|
|
309
|
-
Plots the density distribution of optical coupling in the FSC and SSC channels.
|
|
310
|
-
|
|
311
|
-
This method generates a joint plot showing the relationship between the signals from
|
|
312
|
-
the forward scatter ('detector: forward') and side scatter ('detector: side') detectors.
|
|
313
|
-
The plot is color-coded by particle population and can optionally display axes on a logarithmic scale.
|
|
314
|
-
|
|
315
|
-
Parameters
|
|
316
|
-
----------
|
|
317
|
-
log_scale : bool, optional
|
|
318
|
-
If True, applies a logarithmic scale to both the x and y axes of the plot (default: False).
|
|
319
|
-
show : bool, optional
|
|
320
|
-
If True, displays the plot immediately. If False, the plot is created but not displayed,
|
|
321
|
-
allowing for further customization or saving externally (default: True).
|
|
322
|
-
|
|
323
|
-
"""
|
|
324
|
-
with plt.style.context(mps):
|
|
325
|
-
joint_plot = sns.jointplot(
|
|
326
|
-
data=self.scatterer_collection.dataframe,
|
|
327
|
-
y='detector: side',
|
|
328
|
-
x='detector: forward',
|
|
329
|
-
hue="Population",
|
|
330
|
-
alpha=0.8,
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if log_scale:
|
|
335
|
-
joint_plot.ax_joint.set_xscale('log')
|
|
336
|
-
joint_plot.ax_joint.set_yscale('log')
|
|
337
|
-
|
|
338
|
-
if show: # Display the plot
|
|
339
|
-
plt.show()
|
|
340
|
-
|
|
341
271
|
def add_detector(self, **kwargs) -> Detector:
|
|
342
272
|
"""
|
|
343
273
|
Dynamically adds a new detector to the system configuration.
|
|
@@ -355,9 +285,112 @@ class FlowCytometer:
|
|
|
355
285
|
Effects
|
|
356
286
|
-------
|
|
357
287
|
- Appends the created detector to the `detectors` list.
|
|
358
|
-
"""
|
|
288
|
+
"""
|
|
359
289
|
detector = Detector(**kwargs)
|
|
360
290
|
|
|
361
291
|
self.detectors.append(detector)
|
|
362
292
|
|
|
363
293
|
return detector
|
|
294
|
+
|
|
295
|
+
class PlotInterface:
|
|
296
|
+
def __init__(self, cytometer):
|
|
297
|
+
self.cytometer = cytometer
|
|
298
|
+
|
|
299
|
+
def signals(self, figure_size: tuple = (10, 6), add_peak_locator: bool = False, show: bool = True) -> None:
|
|
300
|
+
"""
|
|
301
|
+
Visualizes the raw signals for all detector channels along with the scatterer distribution.
|
|
302
|
+
|
|
303
|
+
Parameters
|
|
304
|
+
----------
|
|
305
|
+
figure_size : tuple, optional
|
|
306
|
+
Dimensions of the generated plot (default: (10, 6)).
|
|
307
|
+
add_peak_locator : bool, optional
|
|
308
|
+
If True, adds visual markers for detected signal peaks (default: False).
|
|
309
|
+
|
|
310
|
+
Effects
|
|
311
|
+
-------
|
|
312
|
+
Displays a multi-panel plot showing:
|
|
313
|
+
- Raw signals for each detector channel.
|
|
314
|
+
- Scatterer distribution along the time axis.
|
|
315
|
+
"""
|
|
316
|
+
logging.info("Plotting the signal for the different channels.")
|
|
317
|
+
|
|
318
|
+
scatterer_collection = self.cytometer.scatterer_collection
|
|
319
|
+
detectors = self.cytometer.detectors
|
|
320
|
+
|
|
321
|
+
n_detectors = len(detectors)
|
|
322
|
+
|
|
323
|
+
with plt.style.context(mps):
|
|
324
|
+
_, axes = plt.subplots(ncols=1, nrows=n_detectors + 1, figsize=figure_size, sharex=True, sharey=True, gridspec_kw={'height_ratios': [1, 1, 0.4]})
|
|
325
|
+
|
|
326
|
+
time_unit, signal_unit = detectors[0].plot(ax=axes[0], show=False, add_peak_locator=add_peak_locator)
|
|
327
|
+
detectors[1].plot(ax=axes[1], show=False, time_unit=time_unit, signal_unit=signal_unit, add_peak_locator=add_peak_locator)
|
|
328
|
+
|
|
329
|
+
axes[-1].get_yaxis().set_visible(False)
|
|
330
|
+
scatterer_collection.add_to_ax(axes[-1])
|
|
331
|
+
|
|
332
|
+
# Add legends to each subplot
|
|
333
|
+
for ax in axes:
|
|
334
|
+
ax.legend()
|
|
335
|
+
|
|
336
|
+
if show: # Display the plot
|
|
337
|
+
plt.show()
|
|
338
|
+
|
|
339
|
+
def coupling_distribution(self, log_scale: bool = False, show: bool = True, equal_limits: bool = False, save_path: str = None) -> None:
|
|
340
|
+
"""
|
|
341
|
+
Plots the density distribution of optical coupling in the FSC and SSC channels.
|
|
342
|
+
|
|
343
|
+
This method generates a joint plot showing the relationship between the signals from
|
|
344
|
+
the forward scatter ('detector: forward') and side scatter ('detector: side') detectors.
|
|
345
|
+
The plot is color-coded by particle population and can optionally display axes on a logarithmic scale.
|
|
346
|
+
|
|
347
|
+
Parameters
|
|
348
|
+
----------
|
|
349
|
+
log_scale : bool, optional
|
|
350
|
+
If True, applies a logarithmic scale to both the x and y axes of the plot (default: False).
|
|
351
|
+
show : bool, optional
|
|
352
|
+
If True, displays the plot immediately. If False, the plot is created but not displayed,
|
|
353
|
+
allowing for further customization or saving externally (default: True).
|
|
354
|
+
equal_limits : bool, optional
|
|
355
|
+
If True, sets the same limits for both the x and y axes based on the maximum range
|
|
356
|
+
across both axes. If False, the limits are set automatically based on the data (default: False).
|
|
357
|
+
|
|
358
|
+
"""
|
|
359
|
+
scatterer_collection = self.cytometer.scatterer_collection
|
|
360
|
+
detector_0, detector_1 = self.cytometer.detectors
|
|
361
|
+
|
|
362
|
+
with plt.style.context(mps):
|
|
363
|
+
joint_plot = sns.jointplot(
|
|
364
|
+
data=scatterer_collection.dataframe,
|
|
365
|
+
x=f'detector: {detector_0.name}',
|
|
366
|
+
y=f'detector: {detector_1.name}',
|
|
367
|
+
hue="Population",
|
|
368
|
+
alpha=0.8,
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
if log_scale:
|
|
372
|
+
joint_plot.ax_joint.set_xscale('log')
|
|
373
|
+
joint_plot.ax_joint.set_yscale('log')
|
|
374
|
+
|
|
375
|
+
if equal_limits:
|
|
376
|
+
# Get data limits
|
|
377
|
+
x_data = scatterer_collection.dataframe[f'detector: {detector_0.name}']
|
|
378
|
+
y_data = scatterer_collection.dataframe[f'detector: {detector_1.name}']
|
|
379
|
+
|
|
380
|
+
x_min, x_max = x_data.min(), x_data.max()
|
|
381
|
+
y_min, y_max = y_data.min(), y_data.max()
|
|
382
|
+
|
|
383
|
+
# Find the overall min and max
|
|
384
|
+
overall_min = min(x_min, y_min)
|
|
385
|
+
overall_max = max(x_max, y_max)
|
|
386
|
+
|
|
387
|
+
# Set equal limits
|
|
388
|
+
joint_plot.ax_joint.set_xlim(overall_min, overall_max)
|
|
389
|
+
joint_plot.ax_joint.set_ylim(overall_min, overall_max)
|
|
390
|
+
|
|
391
|
+
if save_path:
|
|
392
|
+
joint_plot.figure.savefig(save_path, dpi=300, bbox_inches='tight')
|
|
393
|
+
print(f"Plot saved to {save_path}")
|
|
394
|
+
|
|
395
|
+
if show: # Display the plot
|
|
396
|
+
plt.show()
|
|
@@ -130,14 +130,14 @@ class FlowCell(object):
|
|
|
130
130
|
['Flow Area', f"{self.flow_area:.2f~#P}"],
|
|
131
131
|
['Total Time', f"{self.run_time:.2f~#P}"]
|
|
132
132
|
]
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
# def initialize(self, scatterer: Population | ScattererCollection) -> None:
|
|
135
135
|
# if isinstance(scatterer, Population):
|
|
136
136
|
# return self._initialize_population(scatterer)
|
|
137
137
|
|
|
138
138
|
# elif isinstance(scatterer, ScattererCollection):
|
|
139
139
|
# return self._initialize_scatterer_collection(scatterer)
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
def _initialize_population(self, population: Population) -> None:
|
|
142
142
|
population.dataframe = pandas.DataFrame()
|
|
143
143
|
|
|
@@ -164,13 +164,13 @@ class FlowCell(object):
|
|
|
164
164
|
scatterer : Scatterer
|
|
165
165
|
An instance of the Scatterer class that describes the scatterer collection being used.
|
|
166
166
|
|
|
167
|
-
"""
|
|
167
|
+
"""
|
|
168
168
|
self.scatterer_collection = scatterer_collection
|
|
169
169
|
|
|
170
170
|
for population in self.scatterer_collection.populations:
|
|
171
171
|
self._initialize_population(population)
|
|
172
172
|
population.dataframe.Size = population.dataframe.Size.pint.to(size_units)
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
if len(self.scatterer_collection.populations) != 0:
|
|
175
175
|
self.scatterer_collection.dataframe = pandas.concat(
|
|
176
176
|
[population.dataframe for population in self.scatterer_collection.populations],
|
|
@@ -195,7 +195,7 @@ class FlowCell(object):
|
|
|
195
195
|
index=multi_index
|
|
196
196
|
)
|
|
197
197
|
|
|
198
|
-
self.scatterer_collection.n_events = len(self.scatterer_collection.dataframe)
|
|
198
|
+
self.scatterer_collection.n_events = len(self.scatterer_collection.dataframe)
|
|
199
199
|
|
|
200
200
|
def distribute_time_linearly(self, sequential_population: bool = False) -> None:
|
|
201
201
|
"""
|
|
@@ -210,14 +210,14 @@ class FlowCell(object):
|
|
|
210
210
|
|
|
211
211
|
"""
|
|
212
212
|
# Generate linearly spaced time values across the flow cell runtime
|
|
213
|
-
linear_spacing = numpy.linspace(0, self.run_time, self.n_events)
|
|
213
|
+
linear_spacing = numpy.linspace(0, self.run_time, self.scatterer_collection.n_events)
|
|
214
214
|
|
|
215
215
|
# Optionally randomize the linear spacing
|
|
216
216
|
if not sequential_population:
|
|
217
217
|
numpy.random.shuffle(linear_spacing)
|
|
218
218
|
|
|
219
219
|
# Assign the linearly spaced or randomized times to the scatterer DataFrame
|
|
220
|
-
self.
|
|
220
|
+
self.scatterer_collection.dataframe.Time = PintArray(linear_spacing, dtype=self.scatterer_collection.dataframe.Time.pint.units)
|
|
221
221
|
|
|
222
222
|
def _generate_longitudinal_positions(self, population: Population) -> None:
|
|
223
223
|
r"""
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
class RestrictiveMeta(type):
|
|
2
|
+
def __setattr__(cls, name, value):
|
|
3
|
+
if not hasattr(cls, name):
|
|
4
|
+
raise AttributeError(f"Cannot set unknown class-level attribute '{name}' in {cls.__name__}.")
|
|
5
|
+
super().__setattr__(name, value)
|
|
1
6
|
|
|
2
7
|
|
|
3
|
-
class NoiseSetting:
|
|
8
|
+
class NoiseSetting(metaclass=RestrictiveMeta):
|
|
4
9
|
_instance = None
|
|
5
10
|
|
|
6
11
|
def __new__(cls, *args, **kwargs):
|
|
@@ -54,6 +54,7 @@ FlowCyPy/peak_locator/basic.py
|
|
|
54
54
|
FlowCyPy/peak_locator/derivative.py
|
|
55
55
|
FlowCyPy/peak_locator/moving_average.py
|
|
56
56
|
developments/doc/internship.pdf
|
|
57
|
+
developments/scripts/concentration_comparison.py
|
|
57
58
|
developments/scripts/create_images.py
|
|
58
59
|
developments/scripts/data_analysis.py
|
|
59
60
|
developments/scripts/dev_beads_analysis.py
|
|
@@ -82,6 +83,7 @@ docs/examples/noise_sources/dark_current.py
|
|
|
82
83
|
docs/examples/noise_sources/shot_noise.py
|
|
83
84
|
docs/examples/noise_sources/thermal.py
|
|
84
85
|
docs/examples/tutorials/README.rst
|
|
86
|
+
docs/examples/tutorials/limit_of_detection.py
|
|
85
87
|
docs/examples/tutorials/workflow.py
|
|
86
88
|
docs/images/example_0.png
|
|
87
89
|
docs/images/example_1.png
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
from FlowCyPy import FlowCytometer, ScattererCollection, EventCorrelator, Detector, GaussianBeam, FlowCell
|
|
4
|
+
from FlowCyPy import peak_locator
|
|
5
|
+
from FlowCyPy.units import particle, milliliter, nanometer, RIU, second, micrometer, millisecond, meter
|
|
6
|
+
from FlowCyPy.units import degree, watt, ampere, millivolt, ohm, kelvin, milliampere, megahertz, microvolt
|
|
7
|
+
from FlowCyPy.units import microsecond
|
|
8
|
+
from FlowCyPy.units import milliwatt, AU
|
|
9
|
+
from FlowCyPy import NoiseSetting
|
|
10
|
+
from FlowCyPy import Population, distribution
|
|
11
|
+
from FlowCyPy.population import Exosome, HDL
|
|
12
|
+
|
|
13
|
+
NoiseSetting.include_noises = True
|
|
14
|
+
|
|
15
|
+
np.random.seed(3)
|
|
16
|
+
|
|
17
|
+
source = GaussianBeam(
|
|
18
|
+
numerical_aperture=0.3 * AU, # Numerical aperture of the laser: 0.3
|
|
19
|
+
wavelength=488 * nanometer, # Laser wavelength: 800 nanometers
|
|
20
|
+
optical_power=100 * milliwatt # Laser optical power: 10 milliwatts
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
flow_cell = FlowCell(
|
|
24
|
+
source=source,
|
|
25
|
+
flow_speed=7.56 * meter / second, # Flow speed: 7.56 meters per second
|
|
26
|
+
flow_area=(10 * micrometer) ** 2, # Flow area: 10 x 10 micrometers
|
|
27
|
+
run_time=.2 * millisecond # Total simulation time: 0.3 milliseconds
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
scatterer = ScattererCollection(medium_refractive_index=1.33 * RIU) # Medium refractive index: 1.33
|
|
31
|
+
|
|
32
|
+
population_0 = Population(
|
|
33
|
+
name='Pop 0',
|
|
34
|
+
particle_count=100 * particle,
|
|
35
|
+
size=distribution.RosinRammler(characteristic_size=100 * nanometer, spread=4.5),
|
|
36
|
+
refractive_index=distribution.Normal(mean=1.39 * RIU, std_dev=0.02 * RIU)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
scatterer.add_population(population_0)
|
|
40
|
+
# scatterer.add_population(hdl)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
flow_cell.initialize(scatterer_collection=scatterer)
|
|
44
|
+
|
|
45
|
+
scatterer._log_properties()
|
|
46
|
+
|
|
47
|
+
source.print_properties() # Print the laser source properties
|
|
48
|
+
|
|
49
|
+
detector_0 = Detector(
|
|
50
|
+
name='side', # Detector name: Side scatter detector
|
|
51
|
+
phi_angle=90 * degree, # Angle: 90 degrees (Side Scatter)
|
|
52
|
+
numerical_aperture=.2 * AU, # Numerical aperture: 1.2
|
|
53
|
+
responsitivity=1 * ampere / watt, # Responsitivity: 1 ampere per watt
|
|
54
|
+
sampling_freq=60 * megahertz, # Sampling frequency: 60 MHz
|
|
55
|
+
saturation_level=0.04 * millivolt, # Saturation level: 2 millivolts
|
|
56
|
+
# n_bins='16bit', # Number of bins: 14-bit resolution
|
|
57
|
+
resistance=50 * ohm, # Detector resistance: 50 ohms
|
|
58
|
+
dark_current=0.1 * milliampere, # Dark current: 0.1 milliamps
|
|
59
|
+
temperature=300 * kelvin # Operating temperature: 300 Kelvin
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
detector_1 = Detector(
|
|
63
|
+
name='forward', # Detector name: Forward scatter detector
|
|
64
|
+
phi_angle=0 * degree, # Angle: 0 degrees (Forward Scatter)
|
|
65
|
+
numerical_aperture=.2 * AU, # Numerical aperture: 1.2
|
|
66
|
+
responsitivity=1 * ampere / watt, # Responsitivity: 1 ampere per watt
|
|
67
|
+
sampling_freq=60 * megahertz, # Sampling frequency: 60 MHz
|
|
68
|
+
saturation_level=0.04 * millivolt, # Saturation level: 2 millivolts
|
|
69
|
+
# n_bins='16bit', # Number of bins: 14-bit resolution
|
|
70
|
+
resistance=50 * ohm, # Detector resistance: 50 ohms
|
|
71
|
+
dark_current=0.1 * milliampere, # Dark current: 0.1 milliamps
|
|
72
|
+
temperature=300 * kelvin # Operating temperature: 300 Kelvin
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
detector_1.print_properties() # Print the properties of the forward scatter detector
|
|
77
|
+
|
|
78
|
+
cytometer = FlowCytometer( # Laser source used in the experiment
|
|
79
|
+
flow_cell=flow_cell, # Populations used in the experiment
|
|
80
|
+
background_power=0.0 * milliwatt,
|
|
81
|
+
detectors=[detector_0, detector_1] # List of detectors: Side scatter and Forward scatter
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
cytometer.run_coupling_analysis()
|
|
85
|
+
|
|
86
|
+
cytometer.initialize_signal()
|
|
87
|
+
|
|
88
|
+
cytometer.simulate_pulse()
|
|
89
|
+
|
|
90
|
+
cytometer.plot.signals()
|
|
91
|
+
|
|
92
|
+
algorithm = peak_locator.MovingAverage(
|
|
93
|
+
threshold=10 * microvolt, # Signal threshold: 0.1 mV
|
|
94
|
+
window_size=1 * microsecond, # Moving average window size: 1 µs
|
|
95
|
+
min_peak_distance=0.1 * microsecond # Minimum distance between peaks: 0.3 µs
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
detector_0.set_peak_locator(algorithm)
|
|
99
|
+
detector_1.set_peak_locator(algorithm)
|
|
100
|
+
|
|
101
|
+
cytometer.plot.signals(add_peak_locator=True)
|
|
102
|
+
|
|
103
|
+
analyzer = EventCorrelator(cytometer=cytometer)
|
|
104
|
+
|
|
105
|
+
analyzer.run_analysis(compute_peak_area=False)
|
|
106
|
+
|
|
107
|
+
analyzer.get_coincidence(margin=0.1 * microsecond)
|
|
108
|
+
|
|
109
|
+
analyzer.plot(log_plot=False)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from FlowCyPy import FlowCell
|
|
3
|
+
from FlowCyPy.units import meter, micrometer, millisecond, second, degree
|
|
4
|
+
from FlowCyPy import ScattererCollection
|
|
5
|
+
from FlowCyPy.units import particle, milliliter, nanometer, RIU, milliwatt, AU
|
|
6
|
+
from FlowCyPy import FlowCytometer
|
|
7
|
+
from FlowCyPy import Population, distribution
|
|
8
|
+
from FlowCyPy.detector import Detector
|
|
9
|
+
from FlowCyPy.units import ohm, megahertz, ampere, volt, kelvin, watt, microsecond, microvolt
|
|
10
|
+
from FlowCyPy import EventCorrelator, peak_locator
|
|
11
|
+
from FlowCyPy import GaussianBeam
|
|
12
|
+
from FlowCyPy import NoiseSetting
|
|
13
|
+
|
|
14
|
+
NoiseSetting.include_noises = False
|
|
15
|
+
|
|
16
|
+
np.random.seed(3)
|
|
17
|
+
|
|
18
|
+
source = GaussianBeam(
|
|
19
|
+
numerical_aperture=0.3 * AU,
|
|
20
|
+
wavelength=988 * nanometer,
|
|
21
|
+
optical_power=20 * milliwatt
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
flow_cell = FlowCell(
|
|
26
|
+
source=source,
|
|
27
|
+
flow_speed=7.56 * meter / second,
|
|
28
|
+
flow_area=(10 * micrometer) ** 2,
|
|
29
|
+
run_time=0.2 * millisecond
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
scatterer = ScattererCollection(medium_refractive_index=1.33 * RIU) # Medium refractive index of 1.33 (water)
|
|
34
|
+
|
|
35
|
+
lymphocyte = Population(
|
|
36
|
+
name='lymphocyte',
|
|
37
|
+
particle_count=200 * particle,
|
|
38
|
+
size=distribution.Normal(mean=14_000 * nanometer, std_dev=1000 * nanometer),
|
|
39
|
+
refractive_index=distribution.Normal(mean=1.39 * RIU, std_dev=0.001 * RIU)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
monocyte = Population(
|
|
44
|
+
name='monocyte',
|
|
45
|
+
particle_count=200 * particle,
|
|
46
|
+
size=distribution.Normal(mean=23_000 * nanometer, std_dev=1000 * nanometer),
|
|
47
|
+
refractive_index=distribution.Normal(mean=1.39 * RIU, std_dev=0.001 * RIU)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
scatterer.add_population(lymphocyte, monocyte)
|
|
52
|
+
|
|
53
|
+
flow_cell.initialize(scatterer_collection=scatterer)
|
|
54
|
+
|
|
55
|
+
scatterer.plot()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
detector_0 = Detector(
|
|
59
|
+
name='forward',
|
|
60
|
+
phi_angle=0 * degree,
|
|
61
|
+
numerical_aperture=.2 * AU,
|
|
62
|
+
responsitivity=1 * ampere / watt,
|
|
63
|
+
sampling_freq=60 * megahertz,
|
|
64
|
+
noise_level=0.0 * volt,
|
|
65
|
+
saturation_level=1600 * microvolt,
|
|
66
|
+
resistance=150 * ohm,
|
|
67
|
+
temperature=300 * kelvin,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
detector_1 = Detector(
|
|
72
|
+
name='side',
|
|
73
|
+
phi_angle=90 * degree,
|
|
74
|
+
numerical_aperture=.2 * AU,
|
|
75
|
+
responsitivity=1 * ampere / watt,
|
|
76
|
+
sampling_freq=60 * megahertz,
|
|
77
|
+
noise_level=0.0 * volt,
|
|
78
|
+
saturation_level=1600 * microvolt,
|
|
79
|
+
resistance=150 * ohm,
|
|
80
|
+
temperature=300 * kelvin,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
cytometer = FlowCytometer(
|
|
85
|
+
detectors=[detector_0, detector_1],
|
|
86
|
+
flow_cell=flow_cell
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
cytometer.run_coupling_analysis()
|
|
91
|
+
|
|
92
|
+
cytometer.initialize_signal()
|
|
93
|
+
|
|
94
|
+
cytometer.simulate_pulse()
|
|
95
|
+
|
|
96
|
+
cytometer.plot.coupling_distribution(log_scale=True, equal_limits=True)
|
|
@@ -60,6 +60,7 @@ flow_cell.initialize(scatterer_collection=scatterer) # Link populations to flow
|
|
|
60
60
|
scatterer._log_properties() # Display population properties
|
|
61
61
|
scatterer.plot() # Visualize the population distributions
|
|
62
62
|
|
|
63
|
+
# %%
|
|
63
64
|
# Add forward scatter detector
|
|
64
65
|
detector_0 = Detector(
|
|
65
66
|
name='forward', # Detector name: Forward scatter
|
|
@@ -106,7 +107,7 @@ cytometer.initialize_signal()
|
|
|
106
107
|
cytometer.simulate_pulse()
|
|
107
108
|
|
|
108
109
|
# Visualize the scatter signals from both detectors
|
|
109
|
-
cytometer.plot()
|
|
110
|
+
cytometer.plot.signals()
|
|
110
111
|
|
|
111
112
|
# %%
|
|
112
113
|
# Step 5: Analyzing Pulse Signals
|
|
@@ -62,6 +62,7 @@ scatterer.plot()
|
|
|
62
62
|
|
|
63
63
|
source.print_properties() # Print the laser source properties
|
|
64
64
|
|
|
65
|
+
# %%
|
|
65
66
|
# Step 5: Configure Detectors
|
|
66
67
|
# Side scatter detector
|
|
67
68
|
detector_0 = Detector(
|
|
@@ -109,7 +110,7 @@ cytometer.initialize_signal()
|
|
|
109
110
|
cytometer.simulate_pulse()
|
|
110
111
|
|
|
111
112
|
# Plot the results from both detectors
|
|
112
|
-
cytometer.plot()
|
|
113
|
+
cytometer.plot.signals()
|
|
113
114
|
|
|
114
115
|
# %%
|
|
115
116
|
# Step 5: Analyzing Pulse Signals
|
|
@@ -122,7 +123,7 @@ algorithm = peak_locator.MovingAverage(
|
|
|
122
123
|
detector_0.set_peak_locator(algorithm)
|
|
123
124
|
detector_1.set_peak_locator(algorithm)
|
|
124
125
|
|
|
125
|
-
cytometer.plot(add_peak_locator=True)
|
|
126
|
+
cytometer.plot.signals(add_peak_locator=True)
|
|
126
127
|
|
|
127
128
|
analyzer = EventCorrelator(cytometer=cytometer)
|
|
128
129
|
|
|
@@ -64,6 +64,7 @@ flow_cell.initialize(scatterer_collection=scatterer) # Link populations to flo
|
|
|
64
64
|
scatterer._log_properties() # Display population properties
|
|
65
65
|
scatterer.plot() # Visualize the population distributions
|
|
66
66
|
|
|
67
|
+
# %%
|
|
67
68
|
# Step 4: Simulating the Flow Cytometry Experiment
|
|
68
69
|
# Initialize the cytometer and configure detectors
|
|
69
70
|
# Add forward scatter detector
|
|
@@ -106,7 +107,7 @@ cytometer.initialize_signal()
|
|
|
106
107
|
cytometer.simulate_pulse()
|
|
107
108
|
|
|
108
109
|
# Visualize the scatter signals from both detectors
|
|
109
|
-
cytometer.plot()
|
|
110
|
+
cytometer.plot.signals()
|
|
110
111
|
|
|
111
112
|
# %%
|
|
112
113
|
# Step 5: Analyzing Pulse Signals
|
|
@@ -73,6 +73,7 @@ flow_cell.initialize(scatterer_collection=scatterer) # Link populations to flow
|
|
|
73
73
|
scatterer._log_properties() # Display population properties
|
|
74
74
|
scatterer.plot() # Visualize the population distributions
|
|
75
75
|
|
|
76
|
+
# %%
|
|
76
77
|
# Step 4: Simulating the Flow Cytometry Experiment
|
|
77
78
|
# Initialize the cytometer and configure detectors
|
|
78
79
|
# Add forward scatter detector
|
|
@@ -115,7 +116,7 @@ cytometer.initialize_signal()
|
|
|
115
116
|
cytometer.simulate_pulse()
|
|
116
117
|
|
|
117
118
|
# Visualize the scatter signals from both detectors
|
|
118
|
-
cytometer.plot()
|
|
119
|
+
cytometer.plot.signals()
|
|
119
120
|
|
|
120
121
|
# %%
|
|
121
122
|
# Step 5: Analyzing Pulse Signals
|