cardiac-geometriesx 0.4.7__tar.gz → 0.10.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cardiac_geometriesx-0.4.7/src/cardiac_geometriesx.egg-info → cardiac_geometriesx-0.10.5}/PKG-INFO +14 -7
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/README.md +5 -1
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/pyproject.toml +10 -7
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometries/__init__.py +2 -2
- cardiac_geometriesx-0.10.5/src/cardiac_geometries/aha.py +240 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometries/cli.py +513 -329
- cardiac_geometriesx-0.10.5/src/cardiac_geometries/fibers/__init__.py +72 -0
- cardiac_geometriesx-0.10.5/src/cardiac_geometries/fibers/cylinder.py +125 -0
- cardiac_geometriesx-0.10.5/src/cardiac_geometries/fibers/cylinder_flat.py +164 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometries/fibers/lv_ellipsoid.py +2 -1
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometries/fibers/slab.py +53 -20
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometries/fibers/utils.py +46 -36
- cardiac_geometriesx-0.10.5/src/cardiac_geometries/geometry.py +650 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometries/gui.py +0 -2
- cardiac_geometriesx-0.10.5/src/cardiac_geometries/mesh.py +1451 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometries/utils.py +226 -45
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5/src/cardiac_geometriesx.egg-info}/PKG-INFO +14 -7
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometriesx.egg-info/SOURCES.txt +4 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometriesx.egg-info/requires.txt +7 -4
- cardiac_geometriesx-0.10.5/tests/test_cli.py +212 -0
- cardiac_geometriesx-0.10.5/tests/test_refinement.py +100 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/tests/test_save_load.py +7 -5
- cardiac_geometriesx-0.4.7/src/cardiac_geometries/fibers/__init__.py +0 -4
- cardiac_geometriesx-0.4.7/src/cardiac_geometries/geometry.py +0 -197
- cardiac_geometriesx-0.4.7/src/cardiac_geometries/mesh.py +0 -912
- cardiac_geometriesx-0.4.7/tests/test_cli.py +0 -95
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/LICENSE +0 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/setup.cfg +0 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometriesx.egg-info/dependency_links.txt +0 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometriesx.egg-info/entry_points.txt +0 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometriesx.egg-info/not-zip-safe +0 -0
- {cardiac_geometriesx-0.4.7 → cardiac_geometriesx-0.10.5}/src/cardiac_geometriesx.egg-info/top_level.txt +0 -0
{cardiac_geometriesx-0.4.7/src/cardiac_geometriesx.egg-info → cardiac_geometriesx-0.10.5}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cardiac-geometriesx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.5
|
|
4
4
|
Summary: A python library for cardiac geometries
|
|
5
5
|
Author-email: Henrik Finsberg <henriknf@simula.no>
|
|
6
6
|
License: MIT
|
|
@@ -9,12 +9,12 @@ Keywords: cardiac,geometry
|
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: fenics-dolfinx>=0.
|
|
15
|
+
Requires-Dist: fenics-dolfinx>=0.9.0
|
|
16
16
|
Requires-Dist: structlog
|
|
17
|
-
Requires-Dist: cardiac-geometries-core
|
|
17
|
+
Requires-Dist: cardiac-geometries-core>=0.4
|
|
18
18
|
Requires-Dist: rich-click
|
|
19
19
|
Requires-Dist: adios4dolfinx
|
|
20
20
|
Requires-Dist: scifem
|
|
@@ -26,14 +26,17 @@ Requires-Dist: pre-commit; extra == "dev"
|
|
|
26
26
|
Requires-Dist: twine; extra == "dev"
|
|
27
27
|
Requires-Dist: wheel; extra == "dev"
|
|
28
28
|
Provides-Extra: docs
|
|
29
|
-
Requires-Dist: jupyter-book; extra == "docs"
|
|
29
|
+
Requires-Dist: jupyter-book<2.0; extra == "docs"
|
|
30
30
|
Requires-Dist: jupytext; extra == "docs"
|
|
31
31
|
Requires-Dist: jupyter; extra == "docs"
|
|
32
|
-
Requires-Dist: pyvista[all]>=0.
|
|
32
|
+
Requires-Dist: pyvista[all]>=0.45.0; extra == "docs"
|
|
33
|
+
Requires-Dist: vtk>=9.5.0; extra == "docs"
|
|
33
34
|
Requires-Dist: trame-vuetify; extra == "docs"
|
|
34
35
|
Requires-Dist: ipywidgets; extra == "docs"
|
|
35
36
|
Requires-Dist: fenicsx-ldrb; extra == "docs"
|
|
36
37
|
Requires-Dist: ukb-atlas; extra == "docs"
|
|
38
|
+
Requires-Dist: sphinx-codeautolink; extra == "docs"
|
|
39
|
+
Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
37
40
|
Provides-Extra: test
|
|
38
41
|
Requires-Dist: pre-commit; extra == "test"
|
|
39
42
|
Requires-Dist: pytest; extra == "test"
|
|
@@ -77,7 +80,11 @@ To install the package you can use `pip`
|
|
|
77
80
|
```
|
|
78
81
|
python3 -m pip install cardiac-geometriesx
|
|
79
82
|
```
|
|
80
|
-
however, this assumes that you already have `dolfinx` pre-installed. You can also use
|
|
83
|
+
however, this assumes that you already have `dolfinx` pre-installed. You can also use `conda`
|
|
84
|
+
```
|
|
85
|
+
conda install -c conda-forge cardiac-geometriesx
|
|
86
|
+
```
|
|
87
|
+
or the provided docker image
|
|
81
88
|
```
|
|
82
89
|
docker pull ghcr.io/computationalphysiology/cardiac-geometriesx:latest
|
|
83
90
|
```
|
|
@@ -26,7 +26,11 @@ To install the package you can use `pip`
|
|
|
26
26
|
```
|
|
27
27
|
python3 -m pip install cardiac-geometriesx
|
|
28
28
|
```
|
|
29
|
-
however, this assumes that you already have `dolfinx` pre-installed. You can also use
|
|
29
|
+
however, this assumes that you already have `dolfinx` pre-installed. You can also use `conda`
|
|
30
|
+
```
|
|
31
|
+
conda install -c conda-forge cardiac-geometriesx
|
|
32
|
+
```
|
|
33
|
+
or the provided docker image
|
|
30
34
|
```
|
|
31
35
|
docker pull ghcr.io/computationalphysiology/cardiac-geometriesx:latest
|
|
32
36
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cardiac-geometriesx"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.10.5"
|
|
8
8
|
description = "A python library for cardiac geometries"
|
|
9
9
|
authors = [{name = "Henrik Finsberg", email = "henriknf@simula.no"}]
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -15,11 +15,11 @@ classifiers = [
|
|
|
15
15
|
]
|
|
16
16
|
keywords = ["cardiac", "geometry"]
|
|
17
17
|
urls = {Homepage = "https://github.com/finsberg/cardiac-geometriesx" }
|
|
18
|
-
requires-python = ">=3.
|
|
18
|
+
requires-python = ">=3.10"
|
|
19
19
|
dependencies = [
|
|
20
|
-
"fenics-dolfinx>=0.
|
|
20
|
+
"fenics-dolfinx>=0.9.0",
|
|
21
21
|
"structlog",
|
|
22
|
-
"cardiac-geometries-core",
|
|
22
|
+
"cardiac-geometries-core>=0.4",
|
|
23
23
|
"rich-click",
|
|
24
24
|
"adios4dolfinx",
|
|
25
25
|
"scifem",
|
|
@@ -39,14 +39,17 @@ dev = [
|
|
|
39
39
|
"wheel",
|
|
40
40
|
]
|
|
41
41
|
docs = [
|
|
42
|
-
"jupyter-book",
|
|
42
|
+
"jupyter-book<2.0",
|
|
43
43
|
"jupytext",
|
|
44
44
|
"jupyter",
|
|
45
|
-
"pyvista[all]>=0.
|
|
45
|
+
"pyvista[all]>=0.45.0",
|
|
46
|
+
"vtk>=9.5.0",
|
|
46
47
|
"trame-vuetify",
|
|
47
48
|
"ipywidgets",
|
|
48
49
|
"fenicsx-ldrb",
|
|
49
50
|
"ukb-atlas",
|
|
51
|
+
"sphinx-codeautolink",
|
|
52
|
+
"sphinx-copybutton",
|
|
50
53
|
]
|
|
51
54
|
test = [
|
|
52
55
|
"pre-commit",
|
|
@@ -177,7 +180,7 @@ tag = true
|
|
|
177
180
|
sign_tags = false
|
|
178
181
|
tag_name = "v{new_version}"
|
|
179
182
|
tag_message = "Bump version: {current_version} → {new_version}"
|
|
180
|
-
current_version = "0.
|
|
183
|
+
current_version = "0.10.5"
|
|
181
184
|
|
|
182
185
|
|
|
183
186
|
[[tool.bumpversion.files]]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from . import cli, fibers, geometry, mesh, utils
|
|
1
|
+
from . import aha, cli, fibers, geometry, mesh, utils
|
|
2
2
|
from .geometry import Geometry
|
|
3
3
|
|
|
4
|
-
__all__ = ["mesh", "fibers", "geometry", "Geometry", "utils", "cli"]
|
|
4
|
+
__all__ = ["mesh", "fibers", "geometry", "Geometry", "utils", "cli", "aha"]
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import dolfinx
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def focal(r_long_endo: float | np.ndarray, r_short_endo: float | np.ndarray) -> float | np.ndarray:
|
|
6
|
+
"""Calculate the focal distance for a prolate ellipsoid
|
|
7
|
+
|
|
8
|
+
Parameters
|
|
9
|
+
----------
|
|
10
|
+
r_long_endo : float | np.ndarray
|
|
11
|
+
Radius of the long axis of the endocardium
|
|
12
|
+
r_short_endo : float | np.ndarray
|
|
13
|
+
Radius of the short axis of the endocardium"
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
float | np.ndarray
|
|
18
|
+
The focal distance for the prolate ellipsoid
|
|
19
|
+
"""
|
|
20
|
+
return np.sqrt(r_long_endo**2 - r_short_endo**2)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def full_arctangent(x, y) -> float | np.ndarray:
|
|
24
|
+
"""Compute the full arctangent in [0, 2pi]
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
x : float | np.ndarray
|
|
29
|
+
y : float | np.ndarray
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
float | np.ndarray
|
|
34
|
+
The angle in [0, 2pi]
|
|
35
|
+
"""
|
|
36
|
+
t = np.arctan2(x, y)
|
|
37
|
+
return np.where(t < 0, t + 2 * np.pi, t)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def cartesian_to_prolate_ellipsoidal(
|
|
41
|
+
x: float | np.ndarray,
|
|
42
|
+
y: float | np.ndarray,
|
|
43
|
+
z: float | np.ndarray,
|
|
44
|
+
a: float | np.ndarray,
|
|
45
|
+
) -> tuple[float | np.ndarray, float | np.ndarray, float | np.ndarray]:
|
|
46
|
+
"""Convert Cartesian coordinates to prolate ellipsoidal coordinates
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
x : float | np.ndarray
|
|
51
|
+
y : float | np.ndarray
|
|
52
|
+
z : float | np.ndarray
|
|
53
|
+
a : float | np.ndarray
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
tuple[float | np.ndarray, float | np.ndarray, float | np.ndarray]
|
|
58
|
+
The prolate ellipsoidal coordinates (nu, mu, phi)
|
|
59
|
+
"""
|
|
60
|
+
b1 = np.sqrt((x + a) ** 2 + y**2 + z**2)
|
|
61
|
+
b2 = np.sqrt((x - a) ** 2 + y**2 + z**2)
|
|
62
|
+
|
|
63
|
+
sigma = 1 / (2.0 * a) * (b1 + b2)
|
|
64
|
+
tau = 1 / (2.0 * a) * (b1 - b2)
|
|
65
|
+
phi = full_arctangent(z, y)
|
|
66
|
+
nu = np.arccosh(sigma)
|
|
67
|
+
mu = np.arccos(tau)
|
|
68
|
+
return nu, mu, phi
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get_level(region: int, mu: np.ndarray | float, mu_base: float, dmu: float) -> np.ndarray | bool:
|
|
72
|
+
"""Get the level set for a given AHA region.
|
|
73
|
+
|
|
74
|
+
Notes
|
|
75
|
+
-----
|
|
76
|
+
The regions are defined as follows:
|
|
77
|
+
- Regions 1-6: Basal (mu_base <= mu <= mu_base + dmu)
|
|
78
|
+
- Regions 7-12: Midventricular (mu_base + dmu < mu <= mu_base + 2 * dmu)
|
|
79
|
+
- Regions 13-16: Apical (mu_base + 2 * dmu < mu <= mu_base + 3 * dmu)
|
|
80
|
+
- Region 17: Apex (mu > mu_base + 3 * dmu)
|
|
81
|
+
This function returns a boolean array indicating whether
|
|
82
|
+
each mu value belongs to the specified region.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
region : int
|
|
87
|
+
The AHA region (1-17)
|
|
88
|
+
mu : np.ndarray | float
|
|
89
|
+
The mu coordinate(s)
|
|
90
|
+
mu_base : float
|
|
91
|
+
The base value of mu for segmentation
|
|
92
|
+
dmu : float
|
|
93
|
+
The segmentation width
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
np.ndarray | bool
|
|
97
|
+
The level set for the given AHA region
|
|
98
|
+
"""
|
|
99
|
+
if 1 <= region <= 6:
|
|
100
|
+
return np.logical_and(mu_base <= mu, mu <= mu_base + dmu)
|
|
101
|
+
elif 7 <= region <= 12:
|
|
102
|
+
return np.logical_and(mu_base + dmu < mu, mu <= mu_base + 2 * dmu)
|
|
103
|
+
elif 13 <= region <= 16:
|
|
104
|
+
return np.logical_and(mu_base + 2 * dmu < mu, mu <= mu_base + 3 * dmu)
|
|
105
|
+
else:
|
|
106
|
+
return mu > mu_base + 3 * dmu
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def get_sector(region: int, phi: np.ndarray | float) -> np.ndarray | bool:
|
|
110
|
+
if region in (1, 7):
|
|
111
|
+
return np.logical_and(0 < phi, phi <= np.pi / 3)
|
|
112
|
+
elif region in (2, 8):
|
|
113
|
+
return np.logical_and(np.pi / 3 < phi, phi <= 2 * np.pi / 3)
|
|
114
|
+
elif region in (3, 9):
|
|
115
|
+
return np.logical_and(2 * np.pi / 3 < phi, phi <= np.pi)
|
|
116
|
+
elif region in (4, 10):
|
|
117
|
+
return np.logical_and(np.pi < phi, phi <= 4 * np.pi / 3)
|
|
118
|
+
elif region in (5, 11):
|
|
119
|
+
return np.logical_and(4 * np.pi / 3 < phi, phi <= 5 * np.pi / 3)
|
|
120
|
+
elif region in (6, 12):
|
|
121
|
+
return np.logical_and(5 * np.pi / 3 < phi, phi <= 2 * np.pi)
|
|
122
|
+
elif region == 13:
|
|
123
|
+
return np.logical_and(0 < phi, phi <= np.pi / 2)
|
|
124
|
+
elif region == 14:
|
|
125
|
+
return np.logical_and(np.pi / 2 < phi, phi <= np.pi)
|
|
126
|
+
elif region == 15:
|
|
127
|
+
return np.logical_and(np.pi < phi, phi <= 3 * np.pi / 2)
|
|
128
|
+
elif region == 16:
|
|
129
|
+
return np.logical_and(3 * np.pi / 2 < phi, phi <= 2 * np.pi)
|
|
130
|
+
else:
|
|
131
|
+
# 17 APEX
|
|
132
|
+
return np.ones_like(phi, dtype=bool)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def find_region_entities(
|
|
136
|
+
mu: np.ndarray, phi: np.ndarray, mu_base: float, region: int, dmu: float
|
|
137
|
+
) -> np.ndarray:
|
|
138
|
+
"""Find the entities belonging to a given AHA region.
|
|
139
|
+
|
|
140
|
+
Parameters
|
|
141
|
+
----------
|
|
142
|
+
mu : np.ndarray
|
|
143
|
+
The mu coordinate(s)
|
|
144
|
+
phi : np.ndarray
|
|
145
|
+
The phi coordinate(s)
|
|
146
|
+
mu_base : float
|
|
147
|
+
The base value of mu for segmentation
|
|
148
|
+
region : int
|
|
149
|
+
The AHA region (1-17)
|
|
150
|
+
dmu : float
|
|
151
|
+
The segmentation width
|
|
152
|
+
|
|
153
|
+
Returns
|
|
154
|
+
-------
|
|
155
|
+
np.ndarray
|
|
156
|
+
The indices of entities belonging to the specified AHA region
|
|
157
|
+
"""
|
|
158
|
+
level = get_level(region=region, mu=mu, mu_base=mu_base, dmu=dmu)
|
|
159
|
+
sector = get_sector(region=region, phi=phi)
|
|
160
|
+
return np.where(np.logical_and(level, sector))[0]
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def lv_aha(
|
|
164
|
+
mesh: dolfinx.mesh.Mesh,
|
|
165
|
+
r_long_endo: float,
|
|
166
|
+
r_short_endo: float,
|
|
167
|
+
mu_base: float,
|
|
168
|
+
dmu_factor: float = 1 / 4,
|
|
169
|
+
) -> tuple[dolfinx.mesh.MeshTags, dict[str, tuple[int, int]]]:
|
|
170
|
+
"""Generate AHA segments for idealized LV ellipsoid
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
mesh : dolfinx.mesh.Mesh
|
|
175
|
+
The LV ellipsoidal mesh
|
|
176
|
+
r_long_endo : float
|
|
177
|
+
Radius of the long axis of the endocardium
|
|
178
|
+
r_short_endo : float
|
|
179
|
+
Radius of the short axis of the endocardium
|
|
180
|
+
mu_base : float
|
|
181
|
+
Base value of mu for segmentation
|
|
182
|
+
dmu_factor : float, optional
|
|
183
|
+
Factor to determine the segmentation width, by default 1/4
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
tuple[dolfinx.mesh.MeshTags, dict[str, tuple[int, int]]]
|
|
188
|
+
A tuple with the MeshTags object containing the cell tags
|
|
189
|
+
for the AHA segments and a dictionary with the marker
|
|
190
|
+
names and corresponding (tag, dim) values
|
|
191
|
+
"""
|
|
192
|
+
assert mesh.topology.dim == 3, "AHA segmentation only implemented for 3D geometries"
|
|
193
|
+
foc = focal(r_long_endo=r_long_endo, r_short_endo=r_short_endo)
|
|
194
|
+
mu_base = abs(mu_base)
|
|
195
|
+
x, y, z = dolfinx.mesh.compute_midpoints(
|
|
196
|
+
mesh,
|
|
197
|
+
3,
|
|
198
|
+
entities=np.arange(mesh.topology.index_map(mesh.topology.dim).size_local, dtype=np.int32),
|
|
199
|
+
).T
|
|
200
|
+
|
|
201
|
+
dmu = (np.pi - mu_base) * dmu_factor
|
|
202
|
+
_, mu, phi = cartesian_to_prolate_ellipsoidal(x, y, z, a=foc)
|
|
203
|
+
entities = [
|
|
204
|
+
find_region_entities(mu=mu, phi=phi, mu_base=mu_base, region=region, dmu=dmu)
|
|
205
|
+
for region in range(1, 18)
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
values = [np.full(len(e), i + 1, dtype=np.int32) for i, e in enumerate(entities)]
|
|
209
|
+
|
|
210
|
+
cell_tags = dolfinx.mesh.meshtags(
|
|
211
|
+
mesh,
|
|
212
|
+
3,
|
|
213
|
+
np.hstack(entities),
|
|
214
|
+
np.hstack(values),
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
markers = {}
|
|
218
|
+
i = 1
|
|
219
|
+
|
|
220
|
+
for level in ["BASAL", "MID", "APICAL"]:
|
|
221
|
+
for sector in [
|
|
222
|
+
"ANTERIOR",
|
|
223
|
+
"ANTEROSEPTAL",
|
|
224
|
+
"SEPTAL",
|
|
225
|
+
"INFERIOR",
|
|
226
|
+
"POSTERIOR",
|
|
227
|
+
"LATERAL",
|
|
228
|
+
]:
|
|
229
|
+
if level == "APICAL" and sector in ("ANTEROSEPTAL", "POSTERIOR"):
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
markers["-".join((level, sector))] = (i, 3)
|
|
233
|
+
i += 1
|
|
234
|
+
|
|
235
|
+
markers["APEX"] = (17, 3)
|
|
236
|
+
|
|
237
|
+
return cell_tags, markers
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def biv_aha(): ...
|