Source code for tyssue.topology.monolayer_topology

import logging

import numpy as np

from ..geometry.bulk_geometry import MonolayerGeometry
from ..geometry.utils import rotation_matrix
from .bulk_topology import cell_division as bulk_division
from .bulk_topology import get_division_vertices

logger = logging.getLogger(name=__name__)


[docs]def cell_division(monolayer, mother, orientation="vertical", psi=None): """ Divides the cell mother in the monolayer. Parameters ---------- * monolayer: a :class:`Monolayer` instance * mother: int, the index of the cell to devide * orientation: str, {"vertical" | "horizontal" | "apical"} if "horizontal", performs a division in the equatorial plane of the cell. If "vertical" (the default), performs a division along the basal-apical axis of the cell. If "apical", performs a division cutting the apical face perpendicularly to its principal axis * psi: float, default 0 extra rotation angle of the division plane around the basal-apical plane Returns ------- * daughter: int, the index of the daughter cell """ ab_axis = MonolayerGeometry.basal_apical_axis(monolayer, mother) if orientation == "horizontal": plane_normal = np.asarray(ab_axis) elif orientation == "vertical": plane_normal = _vertical_plane_normal(ab_axis, psi=psi) elif orientation == "apical": rcoords = ["r" + c for c in monolayer.coords] apical_pos = monolayer.edge_df.loc[ (monolayer.edge_df["cell"] == mother) & (monolayer.edge_df["segment"] == "apical"), rcoords, ] _, _, vh = np.linalg.svd(apical_pos) plane_normal = vh[0, :] else: raise ValueError( f"""orientation argument not understood, should be either "horizontal", "vertical" or "apical", not {orientation}""" ) vertices, mother_verts, daughter_verts = get_division_vertices( monolayer, mother=mother, plane_normal=plane_normal, return_all=True ) daughter = bulk_division( monolayer, mother, MonolayerGeometry, vertices, mother_verts, daughter_verts ) # Correct segment assignations for the septum septum = monolayer.face_df.index[-2:] septum_edges = monolayer.edge_df.index[-2 * len(vertices) :] if orientation == "vertical": monolayer.face_df.loc[septum, "segment"] = "lateral" monolayer.edge_df.loc[septum_edges, "segment"] = "lateral" _assign_vert_segment(monolayer, vertices) elif orientation == "horizontal": monolayer.face_df.loc[septum[0], "segment"] = "apical" monolayer.face_df.loc[septum[1], "segment"] = "basal" monolayer.edge_df.loc[septum_edges[: len(vertices)], "segment"] = "apical" monolayer.edge_df.loc[septum_edges[len(vertices) :], "segment"] = "basal" monolayer.vert_df.loc[vertices, "segment"] = "apical" return daughter
def _vertical_plane_normal(ab_axis, psi=None): # Find the simplest vector perpendicular to the ab_axis perp_axis = np.array([-ab_axis[1], ab_axis[0], 0]) if psi is None: psi = np.random.uniform(0, np.pi) # rotate of an arbitrary angle return np.dot(rotation_matrix(psi, ab_axis), perp_axis) def _assign_vert_segment(monolayer, vertices): for v in vertices: segs = set(monolayer.edge_df[monolayer.edge_df["srce"] == v]["segment"]) if "apical" in segs: monolayer.vert_df.loc[v, "segment"] = "apical" elif "basal" in segs: monolayer.vert_df.loc[v, "segment"] = "basal" else: monolayer.vert_df.loc[v, "segment"] = "lateral"
[docs]def find_basal_edge(monolayer, apical_edge): """Returns the basal edge parallel to the apical edge passed in argument. Parameters ---------- monolayer: a :class:`Monolayer` instance """ srce, trgt, cell = monolayer.edge_df.loc[apical_edge, ["srce", "trgt", "cell"]] cell_edges = monolayer.edge_df[monolayer.edge_df["cell"] == cell] srce_segment = monolayer.vert_df.loc[cell_edges["srce"].values, "segment"] srce_segment.index = cell_edges.index trgt_segment = monolayer.vert_df.loc[cell_edges["trgt"].values, "segment"] trgt_segment.index = cell_edges.index try: (b_trgt,) = cell_edges[ (srce_segment == "apical") & (trgt_segment == "basal") & (cell_edges["srce"] == srce) ]["trgt"] (b_srce,) = cell_edges[ (srce_segment == "basal") & (trgt_segment == "apical") & (cell_edges["trgt"] == trgt) ]["srce"] (b_edge,) = cell_edges[ (cell_edges["srce"] == b_srce) & (cell_edges["trgt"] == b_trgt) ].index except ValueError: b_edge = None return b_edge