Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring trait pipeline (1/2) #45

Closed
wants to merge 72 commits into from
Closed
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
c896369
Reorganizing the trait_map and modify ellipse, network functions.
Jul 20, 2023
f874be3
Update ellipse argument default setting.
Jul 20, 2023
c9f4931
Reorganize ellipse and network functions by reducing arguments.
Jul 24, 2023
98ce00c
Map convex hull traits
eberrigan Jul 25, 2023
d6bd4bb
Change primary to lateral when monocots is True
eberrigan Jul 25, 2023
4d7bc4d
Get tips x and y coordinates uses network map
eberrigan Jul 25, 2023
51d60ab
Change "stem" to "root"
eberrigan Jul 25, 2023
a73ebcd
Fix tip y map
eberrigan Jul 25, 2023
fc155f8
Change root width back to take lateral_pts
eberrigan Jul 25, 2023
ff9530d
Changing the order of positional arguments to match others (primary i…
eberrigan Jul 25, 2023
c6e58a3
Fix plotting for using sleap-io API
eberrigan Jul 26, 2023
1bd4ddd
Merge branch 'elizabeth/fix_plotting' into elizabeth/pipeline_cache
eberrigan Jul 26, 2023
25e1047
Make positional arguments consistent
eberrigan Jul 26, 2023
eb973bd
Refactor `get_base_xs` to use graph
eberrigan Jul 26, 2023
fd30b78
Map `scanline_intersection_counts` and use keyword arguments
eberrigan Jul 26, 2023
4b529ae
Refactor `get_base_ys`, `get_base_length`, and `base_ct_density` to u…
eberrigan Jul 27, 2023
296fcc7
Clean up dependencies. Fix tip_ys.
eberrigan Jul 27, 2023
8f8a39a
Refactor `get_root_lengths_max` for use with graph
eberrigan Jul 27, 2023
a25e8b9
Refactor `get_base_tip_dist` to make base and tip pts or all points o…
eberrigan Jul 27, 2023
01ea8bc
Delete `primary_depth`
eberrigan Jul 27, 2023
617f379
Delete traitsgraph
eberrigan Jul 27, 2023
383d454
Delete traitsgraph dependencies
eberrigan Jul 27, 2023
132ac7e
Refactor base-related traits to use graph optionally
eberrigan Jul 27, 2023
3f3967f
Delete traits graph dependency
eberrigan Jul 27, 2023
2f9465f
Use `get_primary_pts` from series class
eberrigan Jul 27, 2023
7cf6817
Delete `get_primary_depth` tests
eberrigan Jul 27, 2023
2f64aaf
Fix trait map for base traits
eberrigan Jul 28, 2023
a88dafc
Delete test for traitsgraph.py
eberrigan Jul 28, 2023
2294d14
Standardize trait definition in trait map
eberrigan Jul 31, 2023
7d4c612
Change "graph" to "trait"
eberrigan Jul 31, 2023
393ee9a
Fix docstrings in `get_bases`
eberrigan Aug 1, 2023
519ec93
Use `TraitDef` class
eberrigan Aug 1, 2023
2b54f73
Fix docstrings
eberrigan Aug 1, 2023
b3430da
Add argument to class `TraitDef` whether to include in csv or if scalar
eberrigan Aug 1, 2023
3b67c58
Change `attr` to `attrs`
eberrigan Aug 1, 2023
d352e86
Add `lengths.py` for length-related traits.
eberrigan Aug 1, 2023
676d055
Add `primary_max_length_pts` to trait definitions
eberrigan Aug 1, 2023
2d437fd
Add `pts_all_array` and `convex_hull` trait definitions
eberrigan Aug 2, 2023
1412c8a
Fix docstring
eberrigan Aug 2, 2023
0979969
Import base-related trait to `lengths.py`
eberrigan Aug 2, 2023
c00fa12
Make sure arrays of points are 2-dimensional
eberrigan Aug 2, 2023
2033e08
Streamline point-related functions
eberrigan Aug 2, 2023
f37a40c
Vectorize `get_node_ind`
eberrigan Aug 2, 2023
a603943
Add trait definitions until `lateral_lengths`
eberrigan Aug 2, 2023
716b670
Delete unnecessary code
eberrigan Aug 2, 2023
752d0a5
Merge branch 'main' into lin/pipeline_cache
Aug 2, 2023
72577c8
Merge remote-tracking branch 'origin/Elizabeth/pipeline_cache' into l…
Aug 2, 2023
6f04244
Use node_ind for `get_root_angle` function.
Aug 2, 2023
e21f57d
Modify base functions by assuming primary_pts as the primary_length_max.
Aug 2, 2023
a84b2f8
Modify argument pts as Optional in `get_base_tip_dist` function
Aug 2, 2023
e90a8eb
Modify argument pts as Optional in `get_grav_index` function
Aug 2, 2023
8cbce05
Draft the trait_definitions using the defined TraitDef class.
Aug 2, 2023
f9316ab
Uppercase the `get_root_angle` function arg description.
Aug 3, 2023
0143e14
Add test_lengths module for lengths-related functions.
Aug 3, 2023
1dbc7c4
Remove lengths-related functions from test_bases.
Aug 3, 2023
6e41394
Set pts as Optional argument for `get_grav_index` function.
Aug 3, 2023
43a5e90
Change the module name for importing lengths-related functions.
Aug 3, 2023
a08a2b6
Remove importing the points functions, only keep `get_all_pts_array`.
Aug 3, 2023
95519da
Test ellipse-related functions.
Aug 3, 2023
b6f0867
Redo the function `get_node_ind`.
Aug 4, 2023
8c249a8
Test function `get_node_ind`.
Aug 4, 2023
8b8c523
Angle function reset node_ind to array if only one value.
Aug 4, 2023
da05663
Angle function return nan if all Nan node, return value if single array.
Aug 4, 2023
bdf1ed4
Test angle functions.
Aug 4, 2023
c8aaad1
Add network_width_depth_ratio in trait_definitions.
Aug 4, 2023
555d5b0
Reorganize arguments of `get_network_distribution_ratio` function.
Aug 4, 2023
dff789c
Add `network_length` trait before calculating `network_solidity`.
Aug 4, 2023
2e8099a
Update `primary_root_length` function with calculated lengths.
Aug 4, 2023
38ed487
Update `get_network_solidity` function with calculated network_length.
Aug 4, 2023
6bd8bef
Test network-related functions.
Aug 4, 2023
e676d08
Test points function (`get_all_pts_array`).
Aug 4, 2023
81a52f7
Update and test scanline functions using calculated scanline counts.
Aug 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions sleap_roots/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
import sleap_roots.scanline
import sleap_roots.series
import sleap_roots.summary
import sleap_roots.traitsgraph
import sleap_roots.graphpipeline
from sleap_roots.graphpipeline import get_all_plants_traits
import sleap_roots.trait_pipeline
from sleap_roots.trait_pipeline import get_all_plants_traits
from sleap_roots.series import Series

# Define package version.
Expand Down
75 changes: 62 additions & 13 deletions sleap_roots/angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,88 @@
import math


def get_node_ind(pts: np.ndarray, proximal=True) -> np.ndarray:
"""Find nproximal/distal node index.
def get_node_ind(pts: np.ndarray, proximal: bool = True) -> np.ndarray:
"""Find proximal/distal node index.

Args:
pts: Numpy array of points of shape (instances, nodes, 2).
pts: Numpy array of points of shape (instances, nodes, 2) or (nodes, 2).
proximal: Boolean value, where true is proximal (default), false is distal.

Returns:
An array of shape (instances,) of proximal or distal node index.
"""
node_ind = []
for i in range(pts.shape[0]):
ind = 1 if proximal else pts.shape[1] - 1 # set initial proximal/distal node
while np.isnan(pts[i, ind]).any():
ind += 1 if proximal else -1
if (ind == pts.shape[1] and proximal) or (ind == 0 and not proximal):
break
node_ind.append(ind)
# Check if pts is a numpy array
if not isinstance(pts, np.ndarray):
raise TypeError("Input pts should be a numpy array.")

# Check if pts has 2 or 3 dimensions
if pts.ndim not in [2, 3]:
raise ValueError("Input pts should have 2 or 3 dimensions.")

# Check if the last dimension of pts has size 2
if pts.shape[-1] != 2:
raise ValueError(
"The last dimension of the input pts should have size 2,"
"representing x and y coordinates."
)

# Check if pts is 2D, if so, reshape to 3D
if pts.ndim == 2:
pts = pts[np.newaxis, ...]

# Identify where NaN values exist
nan_mask = np.isnan(pts).any(axis=-1)

# If only NaN values, return NaN
if nan_mask.all():
return np.nan

if proximal:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I tried to vectorize this but looks like I did it incorrectly. If it was better before you can change it back!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem! The current version also works and uses vectors instead of a for loop.

# For proximal, we want the first non-NaN node in the first half root
# get the first half nan mask (exclude the base node)
node_proximal = nan_mask[:, 1 : int((nan_mask.shape[1] + 1) / 2)]
# get the nearest non-Nan node index
node_ind = np.argmax(~node_proximal, axis=-1)
# if there is no non-Nan node, set value of 99
node_ind[node_proximal.all(axis=1)] = 99
node_ind = node_ind + 1 # adjust indices by adding one (base node)
else:
# For distal, we want the last non-NaN node in the last half root
# get the last half nan mask
node_distal = nan_mask[:, int(nan_mask.shape[1] / 2) :]
# get the farest non-Nan node
node_ind = (node_distal[:, ::-1] == False).argmax(axis=1)
node_ind[node_distal.all(axis=1)] = -95 # set value if no non-Nan node
node_ind = pts.shape[1] - node_ind - 1 # adjust indices by reversing

# reset indices of 0 (base node) if no non-Nan node
node_ind[node_ind == 100] = 0

# If pts was originally 2D, return a scalar instead of a single-element array
if pts.shape[0] == 1:
return node_ind[0]

# If only one root, return a scalar instead of a single-element array
if node_ind.shape[0] == 1:
return node_ind[0]

return node_ind


def get_root_angle(pts: np.ndarray, proximal=True, base_ind=0) -> np.ndarray:
def get_root_angle(
pts: np.ndarray, node_ind: np.ndarray, proximal: bool = True, base_ind=0
) -> np.ndarray:
"""Find angles for each root.

Args:
pts: Numpy array of points of shape (instances, nodes, 2).
node_ind: Primary or lateral root node index.
proximal: Boolean value, where true is proximal (default), false is distal.
base_ind: Index of base node in the skeleton (default: 0).

Returns:
An array of shape (instances,) of angles in degrees, modulo 360.
"""
node_ind = get_node_ind(pts, proximal) # get proximal or distal node index
angs_root = []
for i in range(len(node_ind)):
# filter out the cases if all nan nodes in last/first half part
Expand Down
Loading
Loading