diff --git a/src/agora/io/signal.py b/src/agora/io/signal.py index cc8520890563c5edcff67028bed379946bf91dc3..20b6d8ba848aeefa550c3260e43f475dd3fec21a 100644 --- a/src/agora/io/signal.py +++ b/src/agora/io/signal.py @@ -20,7 +20,9 @@ class Signal(BridgeH5): """ Fetch data from h5 files for post-processing. - Signal assumes that the metadata and data are accessible to perform time-adjustments and apply previously recorded post-processes. + Signal assumes that the metadata and data are accessible to + perform time-adjustments and apply previously recorded + post-processes. """ def __init__(self, file: t.Union[str, Path]): diff --git a/src/aliby/pipeline.py b/src/aliby/pipeline.py index 6e37bac203f9283223e633a3b8c5c157289a1694..526388837c8a54408024e757645754010c0fc3af 100644 --- a/src/aliby/pipeline.py +++ b/src/aliby/pipeline.py @@ -592,41 +592,6 @@ class Pipeline(ProcessABC): ) return (traps_above_nthresh & traps_above_athresh).mean() - # FIXME: Remove this functionality. It used to be for - # older hdf5 file formats. - def _load_config_from_file( - self, - filename: Path, - process_from: t.Dict[str, int], - trackers_state: t.List, - overwrite: t.Dict[str, bool], - ): - with h5py.File(filename, "r") as f: - for k in process_from.keys(): - if not overwrite[k]: - process_from[k] = self.legacy_get_last_tp[k](f) - process_from[k] += 1 - return process_from, trackers_state, overwrite - - # FIXME: Remove this functionality. It used to be for - # older hdf5 file formats. - @staticmethod - def legacy_get_last_tp(step: str) -> t.Callable: - """Get last time-point in different ways depending - on which step we are using - - To support segmentation in aliby < v0.24 - TODO Deprecate and replace with State method - """ - switch_case = { - "tiler": lambda f: f["trap_info/drifts"].shape[0] - 1, - "baby": lambda f: f["cell_info/timepoint"][-1], - "extraction": lambda f: f[ - "extraction/general/None/area/timepoint" - ][-1], - } - return switch_case[step] - def _setup_pipeline( self, image_id: int ) -> t.Tuple[ @@ -682,7 +647,6 @@ class Pipeline(ProcessABC): step: self.step_sequence.index(ow_id) < i for i, step in enumerate(self.step_sequence, 1) } - # set up directory = config["general"]["directory"] trackers_state: t.List[np.ndarray] = [] @@ -722,7 +686,7 @@ class Pipeline(ProcessABC): ) config["tiler"] = steps["tiler"].parameters.to_dict() except Exception: - self._log(f"Overwriting tiling data") + self._log("Overwriting tiling data") if config["general"]["use_explog"]: meta.run() diff --git a/src/postprocessor/core/processor.py b/src/postprocessor/core/processor.py index 76be13cd9f7e6e339e2a5d02570ac5c21cccc8f8..ec9bcd0413fd030e94cdf44543b52866b93d66e1 100644 --- a/src/postprocessor/core/processor.py +++ b/src/postprocessor/core/processor.py @@ -139,7 +139,7 @@ class PostProcessor(ProcessABC): for k in dicted_params.keys(): if not isinstance(dicted_params[k], dict): dicted_params[k] = dicted_params[k].to_dict() - # merger and picker + # initialise merger and picker self.merger = Merger( MergerParameters.from_dict(dicted_params["merger"]) ) @@ -147,12 +147,12 @@ class PostProcessor(ProcessABC): PickerParameters.from_dict(dicted_params["picker"]), cells=Cells.from_source(filename), ) - # processes, such as buddings + # get processes, such as buddings self.classfun = { process: get_process(process) for process, _ in parameters["targets"]["processes"] } - # parameters for the process in classfun + # get parameters for the processes in classfun self.parameters_classfun = { process: get_parameters(process) for process, _ in parameters["targets"]["processes"] diff --git a/src/postprocessor/core/reshapers/buddings.py b/src/postprocessor/core/reshapers/buddings.py index 4398b9478c62a896322c7ce8fd39ee6500bc6641..ba9fe2fc3afd22b5f099710fb929ea8c06d1c1e9 100644 --- a/src/postprocessor/core/reshapers/buddings.py +++ b/src/postprocessor/core/reshapers/buddings.py @@ -13,25 +13,18 @@ from postprocessor.core.lineageprocess import ( class buddingsParameters(LineageProcessParameters): - """ - Parameter class to obtain budding events. - - Define the location of lineage information in the h5 file. - - """ + """Give the location of lineage information in the h5 file.""" _defaults = {"lineage_location": "postprocessing/lineage_merged"} class buddings(LineageProcess): """ - Calculate buddings in a trap assuming one mother per trap. + Generate a dataframe of budding events. - Return a pandas series with the buddings. + We assume one mother per trap. - We define a budding event as when a bud is first identified. - - This bud may not be considered a bud until later in the experiment. + A bud may not be considered a bud until later in the experiment. """ def __init__(self, parameters: buddingsParameters): @@ -41,38 +34,48 @@ class buddings(LineageProcess): def run( self, signal: pd.DataFrame, lineage: np.ndarray = None ) -> pd.DataFrame: - """TODO.""" + """ + Generate dataframe of budding events. + + Find daughters for mothers in a Signal for which we have lineage data. + Create a dataframe indicating the time each daughter first appears. + + We use the data from Signal only to find when the daughters appear, by + their first non-NaN value. + """ + # lineage is (trap, mother, daughter) lineage = lineage or self.lineage - # select traps and mother cells in a given signal + # select traps and mothers in the signal that have lineage data traps_mothers: t.Dict[tuple, list] = { - tuple(mo): [] for mo in lineage[:, :2] if tuple(mo) in signal.index + tuple(trap_mo): [] + for trap_mo in lineage[:, :2] + if tuple(trap_mo) in signal.index } + # find daughters for these traps and mothers for trap, mother, daughter in lineage: if (trap, mother) in traps_mothers.keys(): traps_mothers[(trap, mother)].append(daughter) + # sub dataframe of signal for the selected mothers mothers = signal.loc[ set(signal.index).intersection(traps_mothers.keys()) ] - # create a new dataframe with dimensions (n_mother_cells * n_timepoints) + # a new dataframe with dimensions (n_mother_cells * n_tps) buddings = pd.DataFrame( np.zeros((mothers.shape[0], signal.shape[1])).astype(bool), index=mothers.index, columns=signal.columns, ) buddings.columns.names = ["timepoint"] - # get time of first appearance for every cell using Pandas + # get time of first non-NaN value of signal for every mother using Pandas fvi = signal.apply(lambda x: x.first_valid_index(), axis=1) # fill the budding events - for mother_id, daughters in traps_mothers.items(): - daughters_idx = set( - fvi.loc[ - fvi.index.intersection( - list(product((mother_id[0],), daughters)) - ) - ].values - ).difference({0}) - buddings.loc[ - mother_id, - daughters_idx, - ] = True + for trap_mother_id, daughters in traps_mothers.items(): + times_of_bud_appearance = fvi.loc[ + fvi.index.intersection( + list(product((trap_mother_id[0],), daughters)) + ) + ].values + # ignore zeros - ignore buds in first image + daughters_idx = set(times_of_bud_appearance).difference({0}) + buddings.loc[trap_mother_id, daughters_idx] = True return buddings