FlowCyPy 0.5.6__tar.gz → 0.5.7__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.6 → flowcypy-0.5.7}/FlowCyPy/_version.py +2 -2
- flowcypy-0.5.7/FlowCyPy/cytometer.py +363 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/event_correlator.py +0 -19
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/particle_count.py +24 -10
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/population.py +5 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/populations_instances.py +27 -11
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/scatterer_collection.py +3 -7
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy.egg-info/PKG-INFO +2 -2
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy.egg-info/SOURCES.txt +12 -17
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy.egg-info/requires.txt +1 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/PKG-INFO +2 -2
- flowcypy-0.5.7/developments/scripts/data_analysis.py +43 -0
- flowcypy-0.5.7/developments/scripts/dev_classifier.py +149 -0
- flowcypy-0.5.7/developments/scripts/dev_temp.py +154 -0
- flowcypy-0.5.7/developments/scripts/mat2csv.py +65 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/density_plots/1_populations.py +6 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/density_plots/2_populations.py +9 -2
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/density_plots/3_populations.py +11 -3
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/density_plots/custom_populations.py +7 -2
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/extras/flow_cytometer_signal.py +7 -2
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/extras/full_workflow.py +6 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/extras/scatterer_distribution.py +3 -3
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/tutorials/workflow.py +8 -4
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal.rst +1 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/sg_execution_times.rst +12 -12
- {flowcypy-0.5.6 → flowcypy-0.5.7}/pyproject.toml +1 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_coupling_mechanism.py +2 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_flow_cytometer.py +12 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_peak_analyzer.py +6 -1
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_population.py +1 -3
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_scatterer_distribution.py +31 -3
- flowcypy-0.5.6/.condarc +0 -37
- flowcypy-0.5.6/.readthedocs.yml +0 -35
- flowcypy-0.5.6/FlowCyPy/cytometer.py +0 -198
- flowcypy-0.5.6/FlowCyPy/plottings.py +0 -270
- flowcypy-0.5.6/FlowCyPy/report.py +0 -236
- flowcypy-0.5.6/developments/dev_classifier.py +0 -140
- flowcypy-0.5.6/developments/get_started.md +0 -23
- flowcypy-0.5.6/developments/image.png +0 -0
- flowcypy-0.5.6/developments/output_file.prof +0 -0
- flowcypy-0.5.6/developments/test.pdf +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/.flake8 +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/.github/dependabot.yml +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/.github/workflows/deploy_PyPi.yml +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/.github/workflows/deploy_anaconda.yml +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/.github/workflows/deploy_coverage.yml +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/.github/workflows/deploy_documentation.yml +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/.gitignore +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/__init__.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/classifier.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/coupling_mechanism/__init__.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/coupling_mechanism/empirical.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/coupling_mechanism/mie.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/coupling_mechanism/rayleigh.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/coupling_mechanism/uniform.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/detector.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/directories.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/__init__.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/base_class.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/delta.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/lognormal.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/normal.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/particle_size_distribution.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/uniform.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/distribution/weibull.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/flow_cell.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/helper.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/logger.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/noises.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/peak_locator/__init__.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/peak_locator/base_class.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/peak_locator/basic.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/peak_locator/derivative.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/peak_locator/moving_average.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/physical_constant.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/source.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/units.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy/utils.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy.egg-info/dependency_links.txt +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/FlowCyPy.egg-info/top_level.txt +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/LICENSE +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/README.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/Untitled.ipynb +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/doc}/internship.pdf +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/scripts}/create_images.py +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/scripts}/dev_beads_analysis.py +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/scripts}/dev_canto.py +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/scripts}/dev_shot_noise_check.py +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/scripts}/dev_study_on_ri.py +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/scripts}/dev_study_on_size.py +0 -0
- {flowcypy-0.5.6/developments → flowcypy-0.5.7/developments/scripts}/profiler.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/Makefile +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/density_plots/README.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/extras/README.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/extras/distributions.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/noise_sources/README.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/noise_sources/dark_current.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/noise_sources/shot_noise.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/noise_sources/thermal.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/examples/tutorials/README.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/distributions/Delta.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/distributions/LogNormal.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/distributions/Normal.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/distributions/RosinRammler.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/distributions/Uniform.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/distributions/Weibull.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/example_0.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/example_1.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/example_2.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/example_3.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/flow_cytometer.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/images/logo.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/make.bat +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/_static/default.css +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/_static/logo.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/_static/thumbnail.png +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/analysis.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/base.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/detector.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/distributions.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/flow_cell.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/flow_cytometer.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/peak_locator.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/scatterer.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code/source.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/code.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/conf.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/examples.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/index.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/core_components.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/getting_started.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/objectives/main.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/objectives/pre.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/objectives/stretch.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/prerequisites/index.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/prerequisites/mathematics.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/prerequisites/optics.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/prerequisites/programming.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/ressources.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/internal/tasks.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/references.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/docs/source/theory.rst +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/meta.yaml +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/notebook.ipynb +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/setup.cfg +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/__init__.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_detector_noise.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_distribution.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_extra.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_noises.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_peak_algorithm.py +0 -0
- {flowcypy-0.5.6 → flowcypy-0.5.7}/tests/test_source.py +0 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
from typing import List, Callable, Optional
|
|
8
|
+
from MPSPlots.styles import mps
|
|
9
|
+
from FlowCyPy.flow_cell import FlowCell
|
|
10
|
+
from FlowCyPy.detector import Detector
|
|
11
|
+
import pandas as pd
|
|
12
|
+
import pint_pandas
|
|
13
|
+
from FlowCyPy.units import Quantity, milliwatt
|
|
14
|
+
from FlowCyPy.logger import SimulationLogger
|
|
15
|
+
import seaborn as sns
|
|
16
|
+
|
|
17
|
+
# Set up logging configuration
|
|
18
|
+
logging.basicConfig(
|
|
19
|
+
level=logging.INFO,
|
|
20
|
+
format='%(levelname)s - %(message)s'
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class FlowCytometer:
|
|
25
|
+
"""
|
|
26
|
+
A simulation class for modeling flow cytometer signals, including Forward Scatter (FSC) and Side Scatter (SSC) channels.
|
|
27
|
+
|
|
28
|
+
The FlowCytometer class integrates optical and flow dynamics to simulate signal generation in a flow cytometer.
|
|
29
|
+
It handles particle distributions, flow cell properties, laser source configurations, and detector behavior to
|
|
30
|
+
replicate realistic cytometry conditions. This includes the generation of synthetic signal pulses for each
|
|
31
|
+
particle event and noise modeling for accurate signal representation.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
flow_cell : FlowCell
|
|
36
|
+
The flow cell object representing the fluidic and optical environment through which particles travel.
|
|
37
|
+
detectors : List[Detector]
|
|
38
|
+
A list of `Detector` objects representing the detectors used to measure optical signals (e.g., FSC and SSC). Exactly two detectors must be provided.
|
|
39
|
+
coupling_mechanism : str, optional
|
|
40
|
+
The scattering mechanism used to couple the signal from the particles to the detectors.
|
|
41
|
+
Supported mechanisms include: 'mie' (default): Mie scattering, 'rayleigh': Rayleigh scattering, 'uniform': Uniform signal coupling, 'empirical': Empirical data-driven coupling
|
|
42
|
+
background_power : Quantity, optional
|
|
43
|
+
The background optical power added to the detector signal. Defaults to 0 milliwatts.
|
|
44
|
+
|
|
45
|
+
Attributes
|
|
46
|
+
----------
|
|
47
|
+
flow_cell : FlowCell
|
|
48
|
+
The flow cell instance representing the system environment.
|
|
49
|
+
scatterer_collection : ScattererCollection
|
|
50
|
+
A collection of particles or scatterers passing through the flow cytometer.
|
|
51
|
+
source : GaussianBeam
|
|
52
|
+
The laser beam source providing illumination to the flow cytometer.
|
|
53
|
+
detectors : List[Detector]
|
|
54
|
+
The detectors used to collect and process signals from the scatterers.
|
|
55
|
+
coupling_mechanism : str
|
|
56
|
+
The selected mechanism for signal coupling.
|
|
57
|
+
background_power : Quantity
|
|
58
|
+
The optical background power added to the detector signals.
|
|
59
|
+
|
|
60
|
+
Raises
|
|
61
|
+
------
|
|
62
|
+
AssertionError
|
|
63
|
+
If the number of detectors provided is not exactly two, or if both detectors share the same name.
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
flow_cell: FlowCell,
|
|
69
|
+
detectors: List[Detector],
|
|
70
|
+
coupling_mechanism: Optional[str] = 'mie',
|
|
71
|
+
background_power: Optional[Quantity] = 0 * milliwatt):
|
|
72
|
+
|
|
73
|
+
self.flow_cell = flow_cell
|
|
74
|
+
self.scatterer_collection = flow_cell.scatterer_collection
|
|
75
|
+
self.source = flow_cell.source
|
|
76
|
+
self.detectors = detectors
|
|
77
|
+
self.coupling_mechanism = coupling_mechanism
|
|
78
|
+
self.background_power = background_power
|
|
79
|
+
|
|
80
|
+
assert len(self.detectors) == 2, 'For now, FlowCytometer can only take two detectors for the analysis.'
|
|
81
|
+
assert self.detectors[0].name != self.detectors[1].name, 'Both detectors cannot have the same name'
|
|
82
|
+
|
|
83
|
+
def run_coupling_analysis(self) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Computes and assigns the optical coupling power for each particle-detection event.
|
|
86
|
+
|
|
87
|
+
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
|
+
`scatterer_collection` dataframe under detector-specific columns.
|
|
90
|
+
|
|
91
|
+
Updates
|
|
92
|
+
-------
|
|
93
|
+
scatterer_collection.dataframe : pandas.DataFrame
|
|
94
|
+
Adds columns for each detector, labeled as "detector: <detector_name>", containing the computed
|
|
95
|
+
coupling power for all particle events.
|
|
96
|
+
|
|
97
|
+
Raises
|
|
98
|
+
------
|
|
99
|
+
ValueError
|
|
100
|
+
If an invalid coupling mechanism is specified during initialization.
|
|
101
|
+
"""
|
|
102
|
+
detection_mechanism = self._get_detection_mechanism()
|
|
103
|
+
|
|
104
|
+
for detector in self.detectors:
|
|
105
|
+
self.coupling_power = detection_mechanism(
|
|
106
|
+
source=self.source,
|
|
107
|
+
detector=detector,
|
|
108
|
+
scatterer=self.scatterer_collection
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
self.scatterer_collection.dataframe["detector: " + detector.name] = pint_pandas.PintArray(self.coupling_power, dtype=self.coupling_power.units)
|
|
112
|
+
|
|
113
|
+
self._generate_pulse_parameters()
|
|
114
|
+
|
|
115
|
+
def initialize_signal(self) -> None:
|
|
116
|
+
"""
|
|
117
|
+
Initializes the raw signal for each detector based on the source and flow cell configuration.
|
|
118
|
+
|
|
119
|
+
This method prepares the detectors for signal capture by associating each detector with the
|
|
120
|
+
light source and generating a time-dependent raw signal placeholder.
|
|
121
|
+
|
|
122
|
+
Effects
|
|
123
|
+
-------
|
|
124
|
+
Each detector's `raw_signal` attribute is initialized with time-dependent values
|
|
125
|
+
based on the flow cell's runtime.
|
|
126
|
+
|
|
127
|
+
"""
|
|
128
|
+
# Initialize the detectors
|
|
129
|
+
for detector in self.detectors:
|
|
130
|
+
detector.source = self.source
|
|
131
|
+
detector.init_raw_signal(run_time=self.flow_cell.run_time)
|
|
132
|
+
|
|
133
|
+
def simulate_pulse(self) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Simulates the generation of optical signal pulses for each particle event.
|
|
136
|
+
|
|
137
|
+
This method calculates Gaussian signal pulses based on particle positions, coupling power, and
|
|
138
|
+
widths. It adds the generated pulses, background power, and noise components (thermal and dark current)
|
|
139
|
+
to each detector's raw signal.
|
|
140
|
+
|
|
141
|
+
Notes
|
|
142
|
+
-----
|
|
143
|
+
- Adds Gaussian pulses to each detector's `raw_signal`.
|
|
144
|
+
- Includes noise and background power in the simulated signals.
|
|
145
|
+
- Updates detector dataframes with captured signal information.
|
|
146
|
+
|
|
147
|
+
Raises
|
|
148
|
+
------
|
|
149
|
+
ValueError
|
|
150
|
+
If the scatterer collection lacks required data columns ('Widths', 'Time').
|
|
151
|
+
"""
|
|
152
|
+
logging.debug("Starting pulse simulation.")
|
|
153
|
+
|
|
154
|
+
_widths = self.scatterer_collection.dataframe['Widths'].values
|
|
155
|
+
_centers = self.scatterer_collection.dataframe['Time'].values
|
|
156
|
+
|
|
157
|
+
for detector in self.detectors:
|
|
158
|
+
_coupling_power = self.scatterer_collection.dataframe["detector: " + detector.name].values
|
|
159
|
+
|
|
160
|
+
# Generate noise components
|
|
161
|
+
detector._add_thermal_noise_to_raw_signal()
|
|
162
|
+
|
|
163
|
+
detector._add_dark_current_noise_to_raw_signal()
|
|
164
|
+
|
|
165
|
+
# Broadcast the time array to the shape of (number of signals, len(detector.time))
|
|
166
|
+
time_grid = np.expand_dims(detector.dataframe.Time.values.numpy_data, axis=0) * _centers.units
|
|
167
|
+
|
|
168
|
+
centers = np.expand_dims(_centers.numpy_data, axis=1) * _centers.units
|
|
169
|
+
widths = np.expand_dims(_widths.numpy_data, axis=1) * _widths.units
|
|
170
|
+
|
|
171
|
+
# Compute the Gaussian for each height, center, and width using broadcasting
|
|
172
|
+
power_gaussians = _coupling_power[:, np.newaxis] * np.exp(- (time_grid - centers) ** 2 / (2 * widths ** 2))
|
|
173
|
+
|
|
174
|
+
total_power = np.sum(power_gaussians, axis=0) + self.background_power
|
|
175
|
+
|
|
176
|
+
# Sum all the Gaussians and add them to the detector.raw_signal
|
|
177
|
+
detector._add_optical_power_to_raw_signal(optical_power=total_power)
|
|
178
|
+
|
|
179
|
+
detector.capture_signal()
|
|
180
|
+
|
|
181
|
+
self._log_statistics()
|
|
182
|
+
|
|
183
|
+
def _log_statistics(self) -> SimulationLogger:
|
|
184
|
+
"""
|
|
185
|
+
Logs and displays key statistics about the simulated events.
|
|
186
|
+
|
|
187
|
+
This includes metrics such as:
|
|
188
|
+
- Total number of events processed.
|
|
189
|
+
- Average time between events.
|
|
190
|
+
- First and last event times.
|
|
191
|
+
- Minimum time intervals between events.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
SimulationLogger
|
|
196
|
+
An instance of the logger containing all recorded statistics.
|
|
197
|
+
|
|
198
|
+
Effects
|
|
199
|
+
-------
|
|
200
|
+
Outputs formatted tables to the console or log file, depending on the logger's configuration.
|
|
201
|
+
"""
|
|
202
|
+
logger = SimulationLogger(cytometer=self)
|
|
203
|
+
|
|
204
|
+
logger.log_statistics(include_totals=True, table_format="fancy_grid")
|
|
205
|
+
|
|
206
|
+
return logger
|
|
207
|
+
|
|
208
|
+
def _get_detection_mechanism(self) -> Callable:
|
|
209
|
+
"""
|
|
210
|
+
Retrieves the detection mechanism function for signal coupling based on the selected method.
|
|
211
|
+
|
|
212
|
+
Supported Coupling Mechanisms
|
|
213
|
+
-----------------------------
|
|
214
|
+
- 'mie': Mie scattering.
|
|
215
|
+
- 'rayleigh': Rayleigh scattering.
|
|
216
|
+
- 'uniform': Uniform scattering.
|
|
217
|
+
- 'empirical': Empirical (data-driven) scattering.
|
|
218
|
+
|
|
219
|
+
Returns
|
|
220
|
+
-------
|
|
221
|
+
Callable
|
|
222
|
+
A function that computes the detected signal for scatterer sizes and particle distributions.
|
|
223
|
+
|
|
224
|
+
Raises
|
|
225
|
+
------
|
|
226
|
+
ValueError
|
|
227
|
+
If an unsupported coupling mechanism is specified.
|
|
228
|
+
"""
|
|
229
|
+
from FlowCyPy import coupling_mechanism
|
|
230
|
+
|
|
231
|
+
# Determine which coupling mechanism to use and compute the corresponding factors
|
|
232
|
+
match self.coupling_mechanism.lower():
|
|
233
|
+
case 'rayleigh':
|
|
234
|
+
return coupling_mechanism.rayleigh.compute_detected_signal
|
|
235
|
+
case 'uniform':
|
|
236
|
+
return coupling_mechanism.uniform.compute_detected_signal
|
|
237
|
+
case 'mie':
|
|
238
|
+
return coupling_mechanism.mie.compute_detected_signal
|
|
239
|
+
case 'empirical':
|
|
240
|
+
return coupling_mechanism.empirical.compute_detected_signal
|
|
241
|
+
case _:
|
|
242
|
+
raise ValueError("Invalid coupling mechanism. Choose 'rayleigh' or 'uniform'.")
|
|
243
|
+
|
|
244
|
+
def _generate_pulse_parameters(self) -> None:
|
|
245
|
+
"""
|
|
246
|
+
Generates and assigns random Gaussian pulse parameters for each particle event.
|
|
247
|
+
|
|
248
|
+
The generated parameters include:
|
|
249
|
+
- Centers: The time at which each pulse occurs.
|
|
250
|
+
- Widths: The standard deviation (spread) of each pulse in seconds.
|
|
251
|
+
|
|
252
|
+
Effects
|
|
253
|
+
-------
|
|
254
|
+
scatterer_collection.dataframe : pandas.DataFrame
|
|
255
|
+
Adds a 'Widths' column with computed pulse widths for each particle.
|
|
256
|
+
Uses the flow speed and beam waist to calculate pulse widths.
|
|
257
|
+
"""
|
|
258
|
+
columns = pd.MultiIndex.from_product(
|
|
259
|
+
[[p.name for p in self.detectors], ['Centers', 'Heights']]
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
self.pulse_dataframe = pd.DataFrame(columns=columns)
|
|
263
|
+
|
|
264
|
+
self.pulse_dataframe['Centers'] = self.scatterer_collection.dataframe['Time']
|
|
265
|
+
|
|
266
|
+
widths = self.source.waist / self.flow_cell.flow_speed * np.ones(self.scatterer_collection.n_events)
|
|
267
|
+
|
|
268
|
+
self.scatterer_collection.dataframe['Widths'] = pint_pandas.PintArray(widths, dtype=widths.units)
|
|
269
|
+
|
|
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
|
+
def add_detector(self, **kwargs) -> Detector:
|
|
342
|
+
"""
|
|
343
|
+
Dynamically adds a new detector to the system configuration.
|
|
344
|
+
|
|
345
|
+
Parameters
|
|
346
|
+
----------
|
|
347
|
+
**kwargs : dict
|
|
348
|
+
Keyword arguments passed to the `Detector` constructor.
|
|
349
|
+
|
|
350
|
+
Returns
|
|
351
|
+
-------
|
|
352
|
+
Detector
|
|
353
|
+
The newly added detector instance.
|
|
354
|
+
|
|
355
|
+
Effects
|
|
356
|
+
-------
|
|
357
|
+
- Appends the created detector to the `detectors` list.
|
|
358
|
+
"""
|
|
359
|
+
detector = Detector(**kwargs)
|
|
360
|
+
|
|
361
|
+
self.detectors.append(detector)
|
|
362
|
+
|
|
363
|
+
return detector
|
|
@@ -8,7 +8,6 @@ from FlowCyPy.units import second
|
|
|
8
8
|
import warnings
|
|
9
9
|
from FlowCyPy.cytometer import FlowCytometer
|
|
10
10
|
from FlowCyPy.logger import EventCorrelatorLogger
|
|
11
|
-
from FlowCyPy.report import Report
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class EventCorrelator:
|
|
@@ -224,21 +223,3 @@ class EventCorrelator:
|
|
|
224
223
|
|
|
225
224
|
if show:
|
|
226
225
|
plt.show()
|
|
227
|
-
|
|
228
|
-
def generate_report(self, filename: str) -> None:
|
|
229
|
-
"""
|
|
230
|
-
Generates a detailed report summarizing the analysis, including peak features
|
|
231
|
-
and detected events.
|
|
232
|
-
|
|
233
|
-
Parameters
|
|
234
|
-
----------
|
|
235
|
-
filename : str
|
|
236
|
-
The filename where the report will be saved.
|
|
237
|
-
"""
|
|
238
|
-
report = Report(
|
|
239
|
-
flow_cell=self.cytometer.scatterer.flow_cell,
|
|
240
|
-
scatterer=self.cytometer.scatterer,
|
|
241
|
-
analyzer=self
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
report.generate_report()
|
|
@@ -27,14 +27,17 @@ class ParticleCount:
|
|
|
27
27
|
ValueError
|
|
28
28
|
If the input value does not have the expected dimensionality.
|
|
29
29
|
"""
|
|
30
|
+
if isinstance(value, ParticleCount):
|
|
31
|
+
self = value
|
|
32
|
+
return
|
|
33
|
+
|
|
30
34
|
if value.check(particle):
|
|
31
35
|
# Fixed number of particles
|
|
32
36
|
self.num_particles = value.to(particle)
|
|
33
|
-
|
|
37
|
+
|
|
34
38
|
elif value.check(particle / liter):
|
|
35
39
|
# Concentration of particles
|
|
36
40
|
self.concentration = value.to(particle / liter)
|
|
37
|
-
self.num_particles = None
|
|
38
41
|
else:
|
|
39
42
|
raise ValueError(
|
|
40
43
|
"Value must have dimensions of either 'particles' or 'particles per unit volume'."
|
|
@@ -61,10 +64,10 @@ class ParticleCount:
|
|
|
61
64
|
"""
|
|
62
65
|
flow_volume = flow_area * flow_speed * run_time
|
|
63
66
|
|
|
64
|
-
if self
|
|
65
|
-
return self.num_particles
|
|
66
|
-
elif self.concentration is not None:
|
|
67
|
+
if hasattr(self, 'concentration'):
|
|
67
68
|
return (self.concentration * flow_volume).to(particle)
|
|
69
|
+
elif hasattr(self, 'num_particles'):
|
|
70
|
+
return self.num_particles
|
|
68
71
|
else:
|
|
69
72
|
raise ValueError("Either a number of particles or a concentration must be defined.")
|
|
70
73
|
|
|
@@ -87,7 +90,7 @@ class ParticleCount:
|
|
|
87
90
|
Quantity
|
|
88
91
|
The particle flux in particles per second (particle/second).
|
|
89
92
|
"""
|
|
90
|
-
if self
|
|
93
|
+
if hasattr(self, 'num_particles'):
|
|
91
94
|
return self.num_particles / run_time
|
|
92
95
|
|
|
93
96
|
flow_volume_per_second = (flow_speed * flow_area).to(liter / second)
|
|
@@ -95,8 +98,19 @@ class ParticleCount:
|
|
|
95
98
|
return particle_flux
|
|
96
99
|
|
|
97
100
|
def __repr__(self):
|
|
98
|
-
if self
|
|
99
|
-
return f"{self.num_particles}"
|
|
100
|
-
elif self.concentration is not None:
|
|
101
|
+
if hasattr(self, 'concentration'):
|
|
101
102
|
return f"{self.concentration}"
|
|
102
|
-
|
|
103
|
+
else:
|
|
104
|
+
return f"{self.num_particles}"
|
|
105
|
+
|
|
106
|
+
def __truediv__(self, factor: float):
|
|
107
|
+
if hasattr(self, 'concentration'):
|
|
108
|
+
self.concentration /= factor
|
|
109
|
+
else:
|
|
110
|
+
self.num_particles /= factor
|
|
111
|
+
|
|
112
|
+
def __mul__(self, factor: float):
|
|
113
|
+
if hasattr(self, 'concentration'):
|
|
114
|
+
self.concentration *= factor
|
|
115
|
+
else:
|
|
116
|
+
self.num_particles *= factor
|
|
@@ -38,13 +38,14 @@ class Population(PropertiesReport):
|
|
|
38
38
|
name: str
|
|
39
39
|
refractive_index: Union[distribution.Base, Quantity]
|
|
40
40
|
size: Union[distribution.Base, Quantity]
|
|
41
|
-
particle_count: ParticleCount
|
|
41
|
+
particle_count: ParticleCount | Quantity
|
|
42
42
|
|
|
43
43
|
def __post_init__(self):
|
|
44
44
|
"""
|
|
45
45
|
Automatically converts all Quantity attributes to their base SI units (i.e., without any prefixes).
|
|
46
46
|
This strips units like millimeter to meter, kilogram to gram, etc.
|
|
47
47
|
"""
|
|
48
|
+
self.particle_count = ParticleCount(self.particle_count)
|
|
48
49
|
# Convert all Quantity attributes to base SI units (without any prefixes)
|
|
49
50
|
for attr_name, attr_value in vars(self).items():
|
|
50
51
|
if isinstance(attr_value, Quantity):
|
|
@@ -131,5 +132,8 @@ class Population(PropertiesReport):
|
|
|
131
132
|
return value
|
|
132
133
|
|
|
133
134
|
raise TypeError(f"suze must be of type Quantity or distribution.Base, but got {type(value)}")
|
|
135
|
+
|
|
136
|
+
def dilute(self, factor: float) -> None:
|
|
137
|
+
self.particle_count /= factor
|
|
134
138
|
|
|
135
139
|
from FlowCyPy.populations_instances import * # noqa F403
|
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
from FlowCyPy.units import Quantity, nanometer, RIU, micrometer
|
|
1
|
+
from FlowCyPy.units import Quantity, nanometer, RIU, micrometer, particle
|
|
2
2
|
from FlowCyPy.population import Population
|
|
3
3
|
from FlowCyPy import distribution
|
|
4
4
|
|
|
5
|
+
class CallablePopulationMeta(type):
|
|
6
|
+
def __getattr__(cls, attr):
|
|
7
|
+
raise AttributeError(f"{cls.__name__} must be called as {cls.__name__}() to access its population instance.")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CallablePopulation(metaclass=CallablePopulationMeta):
|
|
11
|
+
def __init__(self, name, size_dist, ri_dist):
|
|
12
|
+
self._name = name
|
|
13
|
+
self._size_distribution = size_dist
|
|
14
|
+
self._ri_distribution = ri_dist
|
|
15
|
+
|
|
16
|
+
def __call__(self, particle_count: Quantity = 1 * particle):
|
|
17
|
+
return Population(
|
|
18
|
+
particle_count=particle_count,
|
|
19
|
+
name=self._name,
|
|
20
|
+
size=self._size_distribution,
|
|
21
|
+
refractive_index=self._ri_distribution,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Define populations
|
|
5
26
|
_populations = (
|
|
6
27
|
('Exosome', 70 * nanometer, 2.0, 1.39 * RIU, 0.02 * RIU),
|
|
7
28
|
('MicroVesicle', 400 * nanometer, 1.5, 1.39 * RIU, 0.02 * RIU),
|
|
@@ -13,7 +34,7 @@ _populations = (
|
|
|
13
34
|
('CellularDebris', 3 * micrometer, 1.0, 1.40 * RIU, 0.03 * RIU),
|
|
14
35
|
)
|
|
15
36
|
|
|
16
|
-
|
|
37
|
+
# Dynamically create population classes
|
|
17
38
|
for (name, size, size_spread, ri, ri_spread) in _populations:
|
|
18
39
|
size_distribution = distribution.RosinRammler(
|
|
19
40
|
characteristic_size=size,
|
|
@@ -25,19 +46,14 @@ for (name, size, size_spread, ri, ri_spread) in _populations:
|
|
|
25
46
|
std_dev=ri_spread
|
|
26
47
|
)
|
|
27
48
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
refractive_index=ri_distribution,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
locals()[name] = population
|
|
49
|
+
# Create a class dynamically for each population
|
|
50
|
+
cls = type(name, (CallablePopulation,), {})
|
|
51
|
+
globals()[name] = cls(name, size_distribution, ri_distribution)
|
|
35
52
|
|
|
36
53
|
|
|
54
|
+
# Helper function for microbeads
|
|
37
55
|
def get_microbeads(size: Quantity, refractive_index: Quantity, name: str) -> Population:
|
|
38
|
-
|
|
39
56
|
size_distribution = distribution.Delta(position=size)
|
|
40
|
-
|
|
41
57
|
ri_distribution = distribution.Delta(position=refractive_index)
|
|
42
58
|
|
|
43
59
|
microbeads = Population(
|
|
@@ -130,7 +130,7 @@ class ScattererCollection(PropertiesReport):
|
|
|
130
130
|
|
|
131
131
|
logger.log_properties(table_format="fancy_grid")
|
|
132
132
|
|
|
133
|
-
def add_population(self, population: Population
|
|
133
|
+
def add_population(self, *population: Population) -> 'ScattererCollection':
|
|
134
134
|
"""
|
|
135
135
|
Adds a population to the ScattererCollection instance with the specified attributes.
|
|
136
136
|
|
|
@@ -142,8 +142,6 @@ class ScattererCollection(PropertiesReport):
|
|
|
142
142
|
The size distribution of the population.
|
|
143
143
|
refractive_index : BaseDistribution
|
|
144
144
|
The refractive index distribution of the population.
|
|
145
|
-
particle_count : ParticleCount
|
|
146
|
-
The concentration or number of particle of the population. Must have the dimensionality of 'particles per liter'.
|
|
147
145
|
|
|
148
146
|
Returns
|
|
149
147
|
-------
|
|
@@ -155,9 +153,7 @@ class ScattererCollection(PropertiesReport):
|
|
|
155
153
|
ValueError
|
|
156
154
|
If the concentration does not have the expected dimensionality.
|
|
157
155
|
"""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
self.populations.append(population)
|
|
156
|
+
self.populations.extend(population)
|
|
161
157
|
return population
|
|
162
158
|
|
|
163
159
|
def _add_population(self, name: str, size: BaseDistribution, refractive_index: BaseDistribution, concentration: Quantity) -> 'ScattererCollection':
|
|
@@ -300,4 +296,4 @@ class ScattererCollection(PropertiesReport):
|
|
|
300
296
|
|
|
301
297
|
def dilute(self, factor: float) -> None:
|
|
302
298
|
for population in self.populations:
|
|
303
|
-
population.
|
|
299
|
+
population.dilute(factor)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: FlowCyPy
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.7
|
|
4
4
|
Summary: A package for flow-cytometry simulations.
|
|
5
5
|
Author-email: Martin Poinsinet de Sivry-Houle <martin.poinsinet.de.sivry@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -54,7 +54,7 @@ Provides-Extra: testing
|
|
|
54
54
|
Requires-Dist: pytest>=0.6; extra == "testing"
|
|
55
55
|
Requires-Dist: pytest-cov>=2.0; extra == "testing"
|
|
56
56
|
Requires-Dist: pytest-json-report==1.5.0; extra == "testing"
|
|
57
|
-
Requires-Dist: coverage==7.6.
|
|
57
|
+
Requires-Dist: coverage==7.6.10; extra == "testing"
|
|
58
58
|
Provides-Extra: documentation
|
|
59
59
|
Requires-Dist: numpydoc==1.8.0; extra == "documentation"
|
|
60
60
|
Requires-Dist: sphinx>=5.1.1; extra == "documentation"
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
.condarc
|
|
2
1
|
.flake8
|
|
3
2
|
.gitignore
|
|
4
|
-
.readthedocs.yml
|
|
5
3
|
LICENSE
|
|
6
4
|
README.rst
|
|
7
5
|
Untitled.ipynb
|
|
@@ -26,10 +24,8 @@ FlowCyPy/logger.py
|
|
|
26
24
|
FlowCyPy/noises.py
|
|
27
25
|
FlowCyPy/particle_count.py
|
|
28
26
|
FlowCyPy/physical_constant.py
|
|
29
|
-
FlowCyPy/plottings.py
|
|
30
27
|
FlowCyPy/population.py
|
|
31
28
|
FlowCyPy/populations_instances.py
|
|
32
|
-
FlowCyPy/report.py
|
|
33
29
|
FlowCyPy/scatterer_collection.py
|
|
34
30
|
FlowCyPy/source.py
|
|
35
31
|
FlowCyPy/units.py
|
|
@@ -57,19 +53,18 @@ FlowCyPy/peak_locator/base_class.py
|
|
|
57
53
|
FlowCyPy/peak_locator/basic.py
|
|
58
54
|
FlowCyPy/peak_locator/derivative.py
|
|
59
55
|
FlowCyPy/peak_locator/moving_average.py
|
|
60
|
-
developments/
|
|
61
|
-
developments/
|
|
62
|
-
developments/
|
|
63
|
-
developments/
|
|
64
|
-
developments/
|
|
65
|
-
developments/
|
|
66
|
-
developments/
|
|
67
|
-
developments/
|
|
68
|
-
developments/
|
|
69
|
-
developments/
|
|
70
|
-
developments/
|
|
71
|
-
developments/profiler.py
|
|
72
|
-
developments/test.pdf
|
|
56
|
+
developments/doc/internship.pdf
|
|
57
|
+
developments/scripts/create_images.py
|
|
58
|
+
developments/scripts/data_analysis.py
|
|
59
|
+
developments/scripts/dev_beads_analysis.py
|
|
60
|
+
developments/scripts/dev_canto.py
|
|
61
|
+
developments/scripts/dev_classifier.py
|
|
62
|
+
developments/scripts/dev_shot_noise_check.py
|
|
63
|
+
developments/scripts/dev_study_on_ri.py
|
|
64
|
+
developments/scripts/dev_study_on_size.py
|
|
65
|
+
developments/scripts/dev_temp.py
|
|
66
|
+
developments/scripts/mat2csv.py
|
|
67
|
+
developments/scripts/profiler.py
|
|
73
68
|
docs/Makefile
|
|
74
69
|
docs/make.bat
|
|
75
70
|
docs/examples/density_plots/1_populations.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: FlowCyPy
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.7
|
|
4
4
|
Summary: A package for flow-cytometry simulations.
|
|
5
5
|
Author-email: Martin Poinsinet de Sivry-Houle <martin.poinsinet.de.sivry@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -54,7 +54,7 @@ Provides-Extra: testing
|
|
|
54
54
|
Requires-Dist: pytest>=0.6; extra == "testing"
|
|
55
55
|
Requires-Dist: pytest-cov>=2.0; extra == "testing"
|
|
56
56
|
Requires-Dist: pytest-json-report==1.5.0; extra == "testing"
|
|
57
|
-
Requires-Dist: coverage==7.6.
|
|
57
|
+
Requires-Dist: coverage==7.6.10; extra == "testing"
|
|
58
58
|
Provides-Extra: documentation
|
|
59
59
|
Requires-Dist: numpydoc==1.8.0; extra == "documentation"
|
|
60
60
|
Requires-Dist: sphinx>=5.1.1; extra == "documentation"
|