Source code for cytoflow.operations.ratio

#!/usr/bin/env python3.8
# coding: latin-1

# (c) Massachusetts Institute of Technology 2015-2018
# (c) Brian Teague 2018-2022
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <>.


Creates a new "channel" that is the ratio of the measurements in two other
channels.  `ratio` has one class:

`RatioOp` -- applies the operation.

import numpy as np

from traits.api import (HasStrictTraits, Str, Constant, provides)

import cytoflow.utility as util
from .i_operation import IOperation

[docs]@provides(IOperation) class RatioOp(HasStrictTraits): """ Create a new "channel" from the ratio of two other channels. Attributes ---------- name : Str The operation name. Also becomes the name of the new channel. numerator : Str The channel that is the numerator of the ratio. denominator : Str The channel that is the denominator of the ratio. Examples -------- >>> ratio_op = flow.RatioOp() >>> ratio_op.numerator = "FITC-A" >>> ex5 = ratio_op.apply(ex4) """ # traits id = Constant('') friendly_id = Constant("Ratio") name = Str numerator = Str denominator = Str
[docs] def apply(self, experiment): """Applies the ratio operation to an experiment Parameters ---------- experiment : `Experiment` the `Experiment` to which this operation is applied Returns ------- Experiment a new experiment with the new ratio channel The new channel also has the following new metadata: - **numerator** : Str What was the numerator channel for the new one? - **denominator** : Str What was the denominator channel for the new one? """ if experiment is None: raise util.CytoflowOpError('experiment', "No experiment specified") # make sure name got set! if not raise util.CytoflowOpError('name', "Must specify a name for the derived channel") if self.numerator not in experiment.channels: raise util.CytoflowOpError('numerator', "Channel {0} not in the experiment" .format(self.numerator)) if self.denominator not in experiment.channels: raise util.CytoflowOpError('denominator', "Channel {0} not in the experiment" .format(self.denominator)) if != util.sanitize_identifier( raise util.CytoflowOpError('name', "Name can only contain letters, numbers and underscores." .format( if in experiment.channels: raise util.CytoflowOpError('name', "New channel {0} is already in the experiment" .format( new_experiment = experiment.clone(deep = False) new_experiment.add_channel(, experiment[self.numerator] / experiment[self.denominator])[np.inf, -np.inf], np.nan, inplace = True) = True) new_experiment.history.append(self.clone_traits(transient = lambda t: True)) new_experiment.metadata[]['numerator'] = self.numerator new_experiment.metadata[]['denominator'] = self.denominator return new_experiment