Esempio n. 1
0
class FeatureBase(object):
    nodes: 'LCMSFeatureTreeList'

    def __init__(self, nodes):
        self.nodes = LCMSFeatureTreeList(nodes)

    def find_time(self, time_point):
        return self.nodes.find_time(time_point)
Esempio n. 2
0
 def __init__(self, nodes):
     self.nodes = LCMSFeatureTreeList(nodes)
Esempio n. 3
0
 def clone(self, deep=False):
     return LCMSFeatureTreeList(node.clone(deep=deep) for node in self)
Esempio n. 4
0
 def truncate_after(self, time):
     _, i = self.nodes.find_time(time)
     if self.nodes[i].time < time:
         i += 1
     self.nodes = LCMSFeatureTreeList(self.nodes[:i])
     self._invalidate()
Esempio n. 5
0
class LCMSFeature(FeatureBase):
    created_at = "new"

    def __init__(self, nodes=None, adducts=None, used_as_adduct=None, feature_id=None):
        if nodes is None:
            nodes = []
        if adducts is None:
            adducts = []
        if used_as_adduct is None:
            used_as_adduct = []
        if feature_id is None:
            feature_id = uid()

        FeatureBase.__init__(self, nodes)
        self._total_intensity = None
        self._mz = None
        self._last_mz = 0.0
        self._times = None
        self._peaks = None
        self._start_time = None
        self._end_time = None
        self.adducts = adducts
        self.used_as_adduct = used_as_adduct
        self.feature_id = feature_id
        self._peak_averager = RunningWeightedAverage()
        if len(self) > 0:
            self._feed_peak_averager()

    def _feed_peak_averager(self):
        for node in self:
            self._peak_averager.update(node.members)

    def invalidate(self, reaverage=False):
        self._invalidate(reaverage)

    def _invalidate(self, reaverage=False):
        self._total_intensity = None
        self._last_mz = self._mz if self._mz is not None else 0.
        self._mz = None
        self._times = None
        self._peaks = None
        self._start_time = None
        self._end_time = None

        if reaverage:
            self._peak_averager = RunningWeightedAverage()
            if len(self) > 0:
                self._feed_peak_averager()

    @property
    def total_signal(self):
        if self._total_intensity is None:
            total = 0.
            for node in self.nodes:
                total += node.total_intensity()
            self._total_intensity = total
        return self._total_intensity

    @property
    def intensity(self):
        return self.total_signal

    @property
    def neutral_mass(self):
        return self.mz

    @property
    def mz(self):
        if self._mz is None:
            best_mz = self._peak_averager.current_mean
            self._last_mz = self._mz = best_mz
        return self._mz

    @property
    def times(self):
        if self._times is None:
            self._times = np.array(
                [node.time for node in self.nodes])
        return self._times

    @property
    def peaks(self):
        if self._peaks is None:
            self._peaks = tuple(node.peaks for node in self.nodes)
        return self._peaks

    @property
    def start_time(self):
        if self._start_time is None:
            self._start_time = self.nodes[0].time
        return self._start_time

    @property
    def end_time(self):
        if self._end_time is None:
            self._end_time = self.nodes[-1].time
        return self._end_time

    def overlaps_in_time(self, interval):
        cond = ((self.start_time <= interval.start_time and self.end_time >= interval.end_time) or (
            self.start_time >= interval.start_time and self.end_time <= interval.end_time) or (
            self.start_time >= interval.start_time and self.end_time >= interval.end_time and
            self.start_time <= interval.end_time) or (
            self.start_time <= interval.start_time and self.end_time >= interval.start_time) or (
            self.start_time <= interval.end_time and self.end_time >= interval.end_time))
        return cond

    def spans_in_time(self, time):
        return self.start_time <= time <= self.end_time

    def as_arrays(self):
        rts = np.array(
            [node.time for node in self.nodes], dtype=np.float64)
        signal = np.array([node.total_intensity()
                           for node in self.nodes], dtype=np.float64)
        return rts, signal

    def __len__(self):
        return len(self.nodes)

    def __repr__(self):
        return "%s(%0.4f, %0.2f, %0.2f)" % (
            self.__class__.__name__, self.mz, self.start_time, self.end_time)

    def _copy_chunk(self, nodes, *args, **kwargs):
        x = self.__class__(LCMSFeatureTreeList(nodes))
        x.used_as_adduct = list(self.used_as_adduct)
        return x

    def split_at(self, time):
        _, i = self.nodes.find_time(time)
        if self.nodes[i].time < time:
            i += 1
        return LCMSFeature(self.nodes[:i]), LCMSFeature(self.nodes[i:])

    def split_sparse(self, delta_rt=1.):
        chunks = []
        current_chunk = []
        last_rt = self.nodes[0].time

        for node in self.nodes:
            if (node.time - last_rt) > delta_rt:
                x = self._copy_chunk(current_chunk)

                chunks.append(x)
                current_chunk = []

            last_rt = node.time
            current_chunk.append(node)

        x = self._copy_chunk(current_chunk)

        chunks.append(x)
        for chunk in chunks:
            chunk.created_at = self.created_at

        for member in chunks:
            for other in chunks:
                if member == other:
                    continue
                assert not member.overlaps_in_time(other)

        return chunks

    def truncate_before(self, time):
        _, i = self.nodes.find_time(time)
        if self.nodes[i].time < time:
            i += 1
        self.nodes = LCMSFeatureTreeList(self.nodes[i:])
        self._invalidate()

    def truncate_after(self, time):
        _, i = self.nodes.find_time(time)
        if self.nodes[i].time < time:
            i += 1
        self.nodes = LCMSFeatureTreeList(self.nodes[:i])
        self._invalidate()

    def clone(self, deep=False, cls=None):
        if cls is None:
            cls = self.__class__
        c = cls(self.nodes.clone(deep=deep), list(
            self.adducts), list(self.used_as_adduct))
        c.feature_id = self.feature_id
        c.created_at = self.created_at
        return c

    def insert_node(self, node):
        self._peak_averager.update(node.members)
        self.nodes.insert_node(node)
        self._invalidate()

    def insert(self, peak, time):
        self._peak_averager.add(peak)
        self.nodes.insert(time, [peak])
        self._invalidate()

    def merge(self, other):
        new = self.clone()
        for node in other.nodes:
            node = node.clone()
            new.insert_node(node)
        new.created_at = "merge"
        return new

    @property
    def apex_time(self):
        rt, intensity = self.as_arrays()
        return rt[np.argmax(intensity)]

    def __iter__(self):
        return iter(self.nodes)

    def __eq__(self, other):
        if other is None:
            return False
        if len(self) != len(other):
            return False
        else:
            if abs(self.start_time - other.start_time) > 1e-4:
                return False
            elif abs(self.end_time - other.end_time) > 1e-4:
                return False
            else:
                for a, b in zip(self, other):
                    if a != b:
                        return False
                return True

    def __ne__(self, other):
        return not (self == other)

    def __hash__(self):
        return hash((self.mz, self.start_time, self.end_time))

    def __getitem__(self, i):
        return self.nodes[i]
Esempio n. 6
0
 def _copy_chunk(self, nodes, *args, **kwargs):
     x = self.__class__(LCMSFeatureTreeList(nodes))
     x.used_as_adduct = list(self.used_as_adduct)
     return x
Esempio n. 7
0
 def truncate_before(self, time: float):
     _, i = self.nodes.find_time(time)
     if self.nodes[i].time < time:
         i += 1
     self.nodes = LCMSFeatureTreeList(self.nodes[i:])
     self._invalidate()
 def __init__(self, nodes):
     self.nodes = LCMSFeatureTreeList(nodes)
class FeatureBase(object):
    def __init__(self, nodes):
        self.nodes = LCMSFeatureTreeList(nodes)

    def find_time(self, time_point):
        return self.nodes.find_time(time_point)
 def truncate_after(self, time):
     _, i = self.nodes.find_time(time)
     if self.nodes[i].time < time:
         i += 1
     self.nodes = LCMSFeatureTreeList(self.nodes[:i])
     self._invalidate()
class LCMSFeature(FeatureBase):
    created_at = "new"

    def __init__(self, nodes=None, adducts=None, used_as_adduct=None, feature_id=None):
        if nodes is None:
            nodes = []
        if adducts is None:
            adducts = []
        if used_as_adduct is None:
            used_as_adduct = []
        if feature_id is None:
            feature_id = uid()

        FeatureBase.__init__(self, nodes)
        self._total_intensity = None
        self._mz = None
        self._last_mz = 0.0
        self._times = None
        self._peaks = None
        self._start_time = None
        self._end_time = None
        self.adducts = adducts
        self.used_as_adduct = used_as_adduct
        self.feature_id = feature_id
        self._peak_averager = RunningWeightedAverage()
        if len(self) > 0:
            self._feed_peak_averager()

    def _feed_peak_averager(self):
        for node in self:
            self._peak_averager.update(node.members)

    def invalidate(self, reaverage=False):
        self._invalidate(reaverage)

    def _invalidate(self, reaverage=False):
        self._total_intensity = None
        self._last_mz = self._mz if self._mz is not None else 0.
        self._mz = None
        self._times = None
        self._peaks = None
        self._start_time = None
        self._end_time = None

        if reaverage:
            self._peak_averager = RunningWeightedAverage()
            if len(self) > 0:
                self._feed_peak_averager()

    @property
    def total_signal(self):
        if self._total_intensity is None:
            total = 0.
            for node in self.nodes:
                total += node.total_intensity()
            self._total_intensity = total
        return self._total_intensity

    @property
    def intensity(self):
        return self.total_signal

    @property
    def neutral_mass(self):
        return self.mz

    @property
    def mz(self):
        if self._mz is None:
            best_mz = self._peak_averager.current_mean
            self._last_mz = self._mz = best_mz
        return self._mz

    @property
    def times(self):
        if self._times is None:
            self._times = np.array(
                [node.time for node in self.nodes])
        return self._times

    @property
    def peaks(self):
        if self._peaks is None:
            self._peaks = tuple(node.peaks for node in self.nodes)
        return self._peaks

    @property
    def start_time(self):
        if self._start_time is None:
            self._start_time = self.nodes[0].time
        return self._start_time

    @property
    def end_time(self):
        if self._end_time is None:
            self._end_time = self.nodes[-1].time
        return self._end_time

    def overlaps_in_time(self, interval):
        cond = ((self.start_time <= interval.start_time and self.end_time >= interval.end_time) or (
            self.start_time >= interval.start_time and self.end_time <= interval.end_time) or (
            self.start_time >= interval.start_time and self.end_time >= interval.end_time and
            self.start_time <= interval.end_time) or (
            self.start_time <= interval.start_time and self.end_time >= interval.start_time) or (
            self.start_time <= interval.end_time and self.end_time >= interval.end_time))
        return cond

    def as_arrays(self):
        rts = np.array(
            [node.time for node in self.nodes], dtype=np.float64)
        signal = np.array([node.total_intensity()
                           for node in self.nodes], dtype=np.float64)
        return rts, signal

    def __len__(self):
        return len(self.nodes)

    def __repr__(self):
        return "%s(%0.4f, %0.2f, %0.2f)" % (
            self.__class__.__name__, self.mz, self.start_time, self.end_time)

    def _copy_chunk(self, nodes, *args, **kwargs):
        x = self.__class__(LCMSFeatureTreeList(nodes))
        x.used_as_adduct = list(self.used_as_adduct)
        return x

    def split_at(self, time):
        _, i = self.nodes.find_time(time)
        if self.nodes[i].time < time:
            i += 1
        return LCMSFeature(self.nodes[:i]), LCMSFeature(self.nodes[i:])

    def split_sparse(self, delta_rt=1.):
        chunks = []
        current_chunk = []
        last_rt = self.nodes[0].time

        for node in self.nodes:
            if (node.time - last_rt) > delta_rt:
                x = self._copy_chunk(current_chunk)

                chunks.append(x)
                current_chunk = []

            last_rt = node.time
            current_chunk.append(node)

        x = self._copy_chunk(current_chunk)

        chunks.append(x)
        for chunk in chunks:
            chunk.created_at = self.created_at

        for member in chunks:
            for other in chunks:
                if member == other:
                    continue
                assert not member.overlaps_in_time(other)

        return chunks

    def truncate_before(self, time):
        _, i = self.nodes.find_time(time)
        if self.nodes[i].time < time:
            i += 1
        self.nodes = LCMSFeatureTreeList(self.nodes[i:])
        self._invalidate()

    def truncate_after(self, time):
        _, i = self.nodes.find_time(time)
        if self.nodes[i].time < time:
            i += 1
        self.nodes = LCMSFeatureTreeList(self.nodes[:i])
        self._invalidate()

    def clone(self, deep=False, cls=None):
        if cls is None:
            cls = self.__class__
        c = cls(self.nodes.clone(deep=deep), list(
            self.adducts), list(self.used_as_adduct))
        c.feature_id = self.feature_id
        c.created_at = self.created_at
        return c

    def insert_node(self, node):
        self._peak_averager.update(node.members)
        self.nodes.insert_node(node)
        self._invalidate()

    def insert(self, peak, time):
        self._peak_averager.add(peak)
        self.nodes.insert(time, [peak])
        self._invalidate()

    def merge(self, other):
        new = self.clone()
        for node in other.nodes:
            node = node.clone()
            new.insert_node(node)
        new.created_at = "merge"
        return new

    @property
    def apex_time(self):
        rt, intensity = self.as_arrays()
        return rt[np.argmax(intensity)]

    def __iter__(self):
        return iter(self.nodes)

    def __eq__(self, other):
        if other is None:
            return False
        if len(self) != len(other):
            return False
        else:
            if abs(self.start_time - other.start_time) > 1e-4:
                return False
            elif abs(self.end_time - other.end_time) > 1e-4:
                return False
            else:
                for a, b in zip(self, other):
                    if a != b:
                        return False
                return True

    def __ne__(self, other):
        return not (self == other)

    def __hash__(self):
        return hash((self.mz, self.start_time, self.end_time))

    def __getitem__(self, i):
        return self.nodes[i]