From 89a62047f85cac63894e9d761b7e203ea080e66a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Al=C3=A1n=20Mu=C3=B1oz?= <amuoz@ed.ac.uk>
Date: Wed, 16 Jun 2021 19:56:14 +0100
Subject: [PATCH] bugfixes everywhere

Former-commit-id: 9642c99b5623ba9b46bcba2cbff45afbc26450f2
---
 core/functions/test_hdf.py | 12 ++++++++----
 core/functions/tracks.py   |  7 +++++--
 core/io/signal.py          |  4 +++-
 core/processes/merger.py   | 24 ++++++++++++++++++++----
 core/processes/picker.py   | 33 +++++++++++++++++----------------
 core/processor.py          | 23 ++++++++++++++++-------
 6 files changed, 69 insertions(+), 34 deletions(-)

diff --git a/core/functions/test_hdf.py b/core/functions/test_hdf.py
index 683c005b..5bd3b1a1 100644
--- a/core/functions/test_hdf.py
+++ b/core/functions/test_hdf.py
@@ -5,11 +5,15 @@ from core.cells import Cells
 import pandas as pd
 
 # f = h5py.File("/home/alan/Documents/sync_docs/PhD/tmp/DO6MS2_003store.h5")
-f = h5py.File(
-    "/shared_libs/pipeline-core/scripts/data/20191026_ss_experiments_01/DO6MS2_003store.h5"
-)
+fname = "/shared_libs/pipeline-core/scripts/data/20191026_ss_experiments_01/DO6MS2_003store.h5"
+f = h5py.File(fname)
 tracks = f["/extraction/general/None/area"][()]
-cell = Cells.from_source("/home/alan/Documents/sync_docs/PhD/tmp/DO6MS2_003store.h5")
+cell = Cells.from_source(fname)
 from postprocessor.core.processes.picker import Picker, PickerParameters
 
 picker = Picker(cells=cell, parameters=PickerParameters.default())
+
+from postprocessor.core.processor import PostProcessor, PostProParameters
+
+pp = PostProcessor(filename=fname, parameters=PostProParameters.default())
+pp.run()
diff --git a/core/functions/tracks.py b/core/functions/tracks.py
index ecc4e0f5..2895b676 100644
--- a/core/functions/tracks.py
+++ b/core/functions/tracks.py
@@ -47,7 +47,7 @@ def max_nonstop_ntps(track: pd.Series) -> int:
 
 
 def get_tracks_ntps(tracks: pd.DataFrame) -> pd.Series:
-    return tracks.apply(get_ntps, axis=1)
+    return tracks.apply(max_ntps, axis=1)
 
 
 def get_avg_gr(track: pd.Series) -> int:
@@ -56,7 +56,7 @@ def get_avg_gr(track: pd.Series) -> int:
 
     :param tracks: Series with volume and timepoints as indices
     """
-    ntps = get_ntps(track)
+    ntps = max_ntps(track)
     vals = track.dropna().values
     gr = (vals[-1] - vals[0]) / ntps
     return gr
@@ -138,6 +138,9 @@ def get_joint_ids(merging_seqs) -> dict:
     output {a:a, b:a, c:a, d:a}
 
     """
+    if not merging_seqs:
+        return {}
+
     targets, origins = list(zip(*merging_seqs))
     static_tracks = set(targets).difference(origins)
 
diff --git a/core/io/signal.py b/core/io/signal.py
index 5f3e8c6d..91907bd5 100644
--- a/core/io/signal.py
+++ b/core/io/signal.py
@@ -1,3 +1,5 @@
+import pandas as pd
+
 from postprocessor.core.io.base import BridgeH5
 
 
@@ -12,7 +14,7 @@ class Signal(BridgeH5):
     def __getitem__(self, dataset):
         dset = self._hdf[dataset][()]
         attrs = self._hdf[dataset].attrs
-        first_dataset = "/" + dataset.split("/")[0] + "/"
+        first_dataset = dataset.split("/")[1] + "/"
         timepoints = self._hdf[first_dataset].attrs["processed_timepoints"]
 
         if "cell_label" in self._hdf[dataset].attrs:
diff --git a/core/processes/merger.py b/core/processes/merger.py
index 5c27dd0b..51a91bf9 100644
--- a/core/processes/merger.py
+++ b/core/processes/merger.py
@@ -1,4 +1,8 @@
-class MergerParameters:
+from postprocessor.core.processes.base import ParametersABC, ProcessABC
+from postprocessor.core.functions.tracks import clean_tracks, merge_tracks, join_tracks
+
+
+class MergerParameters(ParametersABC):
     """
     :param tol: float or int threshold of average (prediction error/std) necessary
         to consider two tracks the same. If float is fraction of first track,
@@ -26,14 +30,26 @@ class MergerParameters:
 
         self.min_avg_delta = min_avg_delta
 
+    @classmethod
+    def default(cls):
+        return cls.from_dict(
+            {
+                "smooth": False,
+                "tolerance": 0.1,
+                "window": 5,
+                "degree": 3,
+                "min_avg_delta": 0.9,
+            }
+        )
+
 
-class Merger:
+class Merger(ProcessABC):
     """
     TODO Integrate functions/tracks.py inside this class?
     """
 
     def __init__(self, parameters):
-        self.parameters = parameters
+        super().__init__(parameters)
 
     def run(self, signal):
-        merged, joint_pairs = merge_tracks(signal, min_len=self.window + 1)
+        merged, joint_pairs = merge_tracks(signal)  # , min_len=self.window + 1)
diff --git a/core/processes/picker.py b/core/processes/picker.py
index 9342ff17..367a88a1 100644
--- a/core/processes/picker.py
+++ b/core/processes/picker.py
@@ -88,7 +88,7 @@ class Picker(ProcessABC):
         return signals.loc[idx]
 
     def pick_by_condition(self, signals):
-        idx = switch_case(self.condition[0], signals, self.condition[1])
+        idx = self.switch_case(self.condition[0], signals, self.condition[1])
         return signals.loc[idx]
 
     def run(self, signals):
@@ -96,22 +96,23 @@ class Picker(ProcessABC):
             self.signals = getattr(self, "pick_by_" + alg)(signals)
         return self.signals
 
+    @staticmethod
+    def switch_case(
+        condition: str,
+        signals: pd.DataFrame,
+        threshold: Union[float, int],
+    ):
+        threshold_asint = _as_int(threshold, signals.shape[1])
+        case_mgr = {
+            "present": signals.apply(max_ntps, axis=1) > threshold_asint,
+            "nonstoply_present": signals.apply(max_nonstop_ntps, axis=1)
+            > threshold_asint,
+            "quantile": [np.quantile(signals.values[signals.notna()], threshold)],
+        }
+        return case_mgr[condition]
+
 
-def as_int(threshold: Union[float, int], ntps: int):
+def _as_int(threshold: Union[float, int], ntps: int):
     if type(threshold) is float:
         threshold = threshold / ntps
     return threshold
-
-
-def switch_case(
-    condition: str,
-    signals: pd.DataFrame,
-    threshold: Union[float, int],
-):
-    threshold_asint = as_int(threshold, signals.shape[1])
-    case_mgr = {
-        "present": signals.apply(max_ntps, axis=1) > threshold_asint,
-        "nonstoply_present": signals.apply(max_nonstop_ntps, axis=1) > threshold_asint,
-        "quantile": [np.quantile(signals.values[signals.notna()], threshold)],
-    }
-    return case_mgr[condition]
diff --git a/core/processor.py b/core/processor.py
index 9e433076..41e3c630 100644
--- a/core/processor.py
+++ b/core/processor.py
@@ -42,25 +42,34 @@ class PostProParameters(ParametersABC):
                 },
             )
 
+    def to_dict(self):
+        return {k: _if_dict(v) for k, v in self.__dict__()}
+
 
 class PostProcessor:
-    def __init__(self, fname, parameters, signals):
+    def __init__(self, filename, parameters):
         self.parameters = parameters
-        self._signals = Signals(fname)
-        self._writer = Writer(fname)
+        self._signals = Signal(filename)
+        self._writer = Writer(filename)
 
         self.datasets = parameters["datasets"]
         self.merger = Merger(parameters["merger"])
         self.picker = Picker(
-            parameters=parameters["picker"], cell=Cells.from_source(fname)
+            parameters=parameters["picker"], cells=Cells.from_source(filename)
         )
         self.processes = [
             self.get_process(process) for process in parameters["processes"]
         ]
 
     def run(self):
-        self.merger.run(signals[self.datasets["merger"]])
-        self.picker.run(signals[self.datasets["picker"]])
+        self.merger.run(self._signals[self.datasets["merger"]])
+        self.picker.run(self._signals[self.datasets["picker"]])
         for process, dataset in zip(self.processes, self.datasets["processes"]):
-            process_result = process.run(signals.get_dataset(dataset))
+            process_result = process.run(self._signals.get_dataset(dataset))
             self.writer.write(process_result, dataset)
+
+
+def _ifdict(item):
+    if hasattr(item, "to_dict"):
+        item = item.to_dict()
+    return item
-- 
GitLab