Coverage for src/arcade_collection/convert/convert_to_contours.py: 100%
28 statements
« prev ^ index » next coverage.py v7.1.0, created at 2024-12-09 19:07 +0000
« prev ^ index » next coverage.py v7.1.0, created at 2024-12-09 19:07 +0000
1import tarfile
3import numpy as np
4from skimage import measure
6from arcade_collection.output.extract_tick_json import extract_tick_json
7from arcade_collection.output.get_location_voxels import get_location_voxels
9ROTATIONS = {
10 "top": (0, 1, 2),
11 "side1": (0, 2, 1),
12 "side2": (2, 1, 0),
13}
14"""Axis rotations for different contour views."""
17def convert_to_contours(
18 series_key: str,
19 locations_tar: tarfile.TarFile,
20 frame: int,
21 regions: list[str],
22 box: tuple[int, int, int],
23 indices: dict[str, list[int]],
24) -> dict[str, dict[str, dict[int, list]]]:
25 """
26 Convert data to iso-valued contours.
28 Contours are calculated using "marching squares" method. Note that these
29 contours follow the iso-values, which means that a single "square" voxel
30 will produce a diamond-shaped contour. For the exact outline of a set of
31 voxels, consider using ``extract_voxel_contours`` from the
32 ``abm_shape_collection`` package.
34 Parameters
35 ----------
36 series_key
37 Simulation series key.
38 locations_tar
39 Archive of location data.
40 frame
41 Frame number.
42 regions
43 List of regions.
44 box
45 Size of bounding box.
46 indices
47 Map of view to slice indices.
49 Returns
50 -------
51 :
52 Map of region, view, and index to contours.
53 """
55 locations = extract_tick_json(locations_tar, series_key, frame, "LOCATIONS")
57 contours: dict[str, dict[str, dict[int, list]]] = {
58 region: {view: {} for view in indices} for region in regions
59 }
61 for location in locations:
62 for region in regions:
63 array = np.zeros(box)
64 voxels = get_location_voxels(location, region if region != "DEFAULT" else None)
66 if len(voxels) == 0:
67 continue
69 array[tuple(np.transpose(voxels))] = 1
71 for view in indices:
72 array_rotated = np.moveaxis(array, [0, 1, 2], ROTATIONS[view])
74 for index in indices[view]:
75 array_slice = array_rotated[:, :, index]
77 if np.sum(array_slice) == 0:
78 continue
80 if index not in contours[region][view]:
81 contours[region][view][index] = []
83 array_contours = [
84 contour.tolist() for contour in measure.find_contours(array_slice)
85 ]
86 contours[region][view][index].extend(array_contours)
88 return contours