From fec5f404865dce73ecc033969fd07face9250d54 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Mon, 30 Jun 2025 16:50:39 +0200 Subject: [PATCH 1/9] added proper imports --- src/LineageTree/__init__.py | 4 +- src/LineageTree/loaders.py | 78 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/LineageTree/__init__.py b/src/LineageTree/__init__.py index 1cc42b72..be6d7401 100644 --- a/src/LineageTree/__init__.py +++ b/src/LineageTree/__init__.py @@ -4,6 +4,7 @@ from .loaders import ( read_from_ASTEC, read_from_binary, + read_from_bmf, read_from_csv, read_from_mamut_xml, read_from_mastodon, @@ -21,10 +22,11 @@ "read_from_txt_for_celegans_BAO", "read_from_ASTEC", "read_from_binary", + "read_from_bmf", "read_from_csv", "read_from_mamut_xml", "read_from_mastodon_csv", "read_from_mastodon", "read_from_txt_for_celegans", "read_from_txt_for_celegans_CAO", -) +) \ No newline at end of file diff --git a/src/LineageTree/loaders.py b/src/LineageTree/loaders.py index 79e6ad7e..c0e22ed2 100644 --- a/src/LineageTree/loaders.py +++ b/src/LineageTree/loaders.py @@ -1,7 +1,9 @@ +import binarymeshformat as bmf import csv import os import pickle as pkl import struct +import trimesh import xml.etree.ElementTree as ET from pathlib import Path from warnings import warn @@ -93,6 +95,82 @@ } +def _load_trimesh_from_bmfmesh(bmfmesh, pos_multipliers, translation): + + points = np.array(bmfmesh.positions).reshape(-1, 3)[:,::-1] + triangles = np.array(bmfmesh.triangles).reshape(-1, 3) + + pos_multipliers = np.array(pos_multipliers, dtype=float) + translation = np.array(translation, dtype=float) + points = points * pos_multipliers + translation + + return trimesh.Trimesh(points, triangles) + + +def read_from_bmf( + file_path: str, + store_meshes: bool = False, + pos_multipliers: tuple[float, float, float] = (1.0, 1.0, 1.0), + translation: tuple[float, float, float] = (0.0, 0.0, 0.0), + name: None | str = None, +) -> lineageTree: + """Read a lineage tree from a bmf file. + + Parameters + ---------- + file_path : str + path to the bmf file + store_meshes : bool, default=False + whether to stores the meshes in the LineageTree or not. + pos_multipliers : tuple of float, default=(1.0, 1.0, 1.0) + multipliers for the x, y, z coordinates + translation : tuple of float, default=(0.0, 0.0, 0.0) + translation for the x, y, z coordinates + name : None or str, optional + The name attribute of the lineageTree file. If given a non-empty string, the value of the attribute + will be the name attribute, otherwise the name will be the stem of the file path. + + Returns + ------- + lineageTree + lineage tree + """ + + tracks = bmf.loadMeshTracks(file_path) + predecessor = {} + times = {} + pos = {} + lT_mesh = {} + cell_id = 1 + for track in tracks: + pred = None + for t, mesh in track.meshes.items(): + mesh = _load_trimesh_from_bmfmesh(mesh, pos_multipliers, translation) + pos[cell_id] = mesh.center_mass + + if store_meshes: + lT_mesh[cell_id] = mesh + + predecessor[cell_id] = (pred,) + pred = cell_id + times[cell_id] = t + + cell_id += 1 + + kwargs = {"mesh": lT_mesh} if store_meshes else {} + + lT = lineageTree( + predecessor=predecessor, + time=times, + pos=pos, + root_leaf_value=[(None,)], + name=name if name else Path(file_path).stem, + **kwargs, + ) + + return lT + + def read_from_csv( file_path: str, z_mult: float, From 4430ed30ef14c5d751bacb51d0e2e760957d92c4 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Mon, 30 Jun 2025 16:51:10 +0200 Subject: [PATCH 2/9] improved readability --- src/LineageTree/lineageTree.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/LineageTree/lineageTree.py b/src/LineageTree/lineageTree.py index 1a778dbc..b748bff1 100644 --- a/src/LineageTree/lineageTree.py +++ b/src/LineageTree/lineageTree.py @@ -1222,11 +1222,9 @@ def get_idx3d(self, t: int) -> tuple[KDTree, np.ndarray]: self.kdtrees = {} if t not in self.kdtrees: - data_corres = {} - data = [] + data = np.zeros((len(to_check_self), len(next(iter(self.pos.values()))))) for i, C in enumerate(to_check_self): - data.append(tuple(self.pos[C])) - data_corres[i] = C + data[i] = self.pos[C] idx3d = KDTree(data) self.kdtrees[t] = idx3d else: From f41d2f53a780a07a2739d3ca968ed1b95d8e5e6b Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Fri, 22 Aug 2025 20:27:31 +0200 Subject: [PATCH 3/9] updated test dependencies --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 10fdd821..cc56efdc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,6 +60,7 @@ doc = [ test = [ "pytest", "pytest-cov", + "binarymeshformat" ] [project.urls] From 15d2159e48f1df0e959f65ffc526943328cee839 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Fri, 22 Aug 2025 20:30:11 +0200 Subject: [PATCH 4/9] added test dependencies --- pyproject.toml | 3 ++- src/LineageTree/loaders.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cc56efdc..26bc525b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,8 @@ doc = [ test = [ "pytest", "pytest-cov", - "binarymeshformat" + "binarymeshformat", + "trimesh", ] [project.urls] diff --git a/src/LineageTree/loaders.py b/src/LineageTree/loaders.py index 4e5d9498..e68769d4 100644 --- a/src/LineageTree/loaders.py +++ b/src/LineageTree/loaders.py @@ -135,7 +135,7 @@ def read_from_bmf( lineageTree lineage tree """ - + # TODO: add check that binarymeshformat and trimesh are installed tracks = bmf.loadMeshTracks(file_path) predecessor = {} times = {} From 99eea6ae8904c8868666127b6247758661c03d28 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Tue, 26 Aug 2025 16:07:58 +0200 Subject: [PATCH 5/9] updated naming --- src/lineagetree/_io/_loaders.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lineagetree/_io/_loaders.py b/src/lineagetree/_io/_loaders.py index eed244e5..796ec395 100644 --- a/src/lineagetree/_io/_loaders.py +++ b/src/lineagetree/_io/_loaders.py @@ -116,7 +116,7 @@ def read_from_bmf( pos_multipliers: tuple[float, float, float] = (1.0, 1.0, 1.0), translation: tuple[float, float, float] = (0.0, 0.0, 0.0), name: None | str = None, -) -> lineageTree: +) -> LineageTree: """Read a lineage tree from a bmf file. Parameters @@ -130,12 +130,12 @@ def read_from_bmf( translation : tuple of float, default=(0.0, 0.0, 0.0) translation for the x, y, z coordinates name : None or str, optional - The name attribute of the lineageTree file. If given a non-empty string, the value of the attribute + The name attribute of the LineageTree file. If given a non-empty string, the value of the attribute will be the name attribute, otherwise the name will be the stem of the file path. Returns ------- - lineageTree + LineageTree lineage tree """ # TODO: add check that binarymeshformat and trimesh are installed @@ -162,7 +162,7 @@ def read_from_bmf( kwargs = {"mesh": lT_mesh} if store_meshes else {} - lT = lineageTree( + lT = LineageTree( predecessor=predecessor, time=times, pos=pos, From 68305a8eb7ba12cd940a34561514a54516612b70 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Sun, 14 Sep 2025 17:37:22 +0200 Subject: [PATCH 6/9] moved dependencies to "meshes" optional --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 8f704062..639f7f83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,8 @@ doc = [ test = [ "pytest", "pytest-cov", +] +meshes = [ "binarymeshformat", "trimesh", ] From 41641d809279e1808eae6de77e8bc221464105b8 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Sun, 14 Sep 2025 18:50:39 +0200 Subject: [PATCH 7/9] removed trimesh dependency --- pyproject.toml | 1 - src/lineagetree/_io/_loaders.py | 16 +++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 639f7f83..5685e0c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,6 @@ test = [ ] meshes = [ "binarymeshformat", - "trimesh", ] [project.urls] diff --git a/src/lineagetree/_io/_loaders.py b/src/lineagetree/_io/_loaders.py index 796ec395..f2fbf48f 100644 --- a/src/lineagetree/_io/_loaders.py +++ b/src/lineagetree/_io/_loaders.py @@ -5,7 +5,6 @@ import os import pickle as pkl import struct -import trimesh import xml.etree.ElementTree as ET from pathlib import Path from warnings import warn @@ -98,16 +97,19 @@ } -def _load_trimesh_from_bmfmesh(bmfmesh, pos_multipliers, translation): +def _load_meshdict_from_bmfmesh(bmfmesh, pos_multipliers, translation): - points = np.array(bmfmesh.positions).reshape(-1, 3)[:,::-1] - triangles = np.array(bmfmesh.triangles).reshape(-1, 3) + vertices = np.array(bmfmesh.positions).reshape(-1, 3)[:,::-1] + faces = np.array(bmfmesh.triangles).reshape(-1, 3) pos_multipliers = np.array(pos_multipliers, dtype=float) translation = np.array(translation, dtype=float) - points = points * pos_multipliers + translation + vertices = vertices * pos_multipliers + translation - return trimesh.Trimesh(points, triangles) + return { # could be a class + 'vertices': vertices, + 'faces': faces + } def read_from_bmf( @@ -148,7 +150,7 @@ def read_from_bmf( for track in tracks: pred = None for t, mesh in track.meshes.items(): - mesh = _load_trimesh_from_bmfmesh(mesh, pos_multipliers, translation) + mesh = _load_meshdict_from_bmfmesh(mesh, pos_multipliers, translation) pos[cell_id] = mesh.center_mass if store_meshes: From c263d9ee21dd5faa82e9aecfc2461bd0d7b38f16 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Sun, 14 Sep 2025 19:07:29 +0200 Subject: [PATCH 8/9] added dependency to test env --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 5685e0c7..46688f72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ doc = [ test = [ "pytest", "pytest-cov", + "binarymeshformat", ] meshes = [ "binarymeshformat", From 0e94bc825de5b40616711b2af3409add652af014 Mon Sep 17 00:00:00 2001 From: jules-vanaret Date: Fri, 19 Sep 2025 16:16:37 +0200 Subject: [PATCH 9/9] made binarymeshformat mandatory --- pyproject.toml | 5 +---- src/lineagetree/_io/_loaders.py | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 46688f72..095fbb73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ dependencies = [ "edist", "svgwrite", "Micro-Mastodon-Reader", + "binarymeshformat", ] [project.optional-dependencies] @@ -59,10 +60,6 @@ doc = [ test = [ "pytest", "pytest-cov", - "binarymeshformat", -] -meshes = [ - "binarymeshformat", ] [project.urls] diff --git a/src/lineagetree/_io/_loaders.py b/src/lineagetree/_io/_loaders.py index f2fbf48f..c91c8976 100644 --- a/src/lineagetree/_io/_loaders.py +++ b/src/lineagetree/_io/_loaders.py @@ -140,7 +140,6 @@ def read_from_bmf( LineageTree lineage tree """ - # TODO: add check that binarymeshformat and trimesh are installed tracks = bmf.loadMeshTracks(file_path) predecessor = {} times = {}