Skip to content

Conversation

@lucas-wilkins
Copy link
Contributor

Reworked SasData classes

This introduces a new object, the Abscissa object, that describes how the axes data relates to ordinate data.

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

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

Code Health Improved (1 files improve in Code Health)

Gates Failed
New code is healthy (1 new file with code health below 9.00)
Enforce critical code health rules (1 file with Bumpy Road Ahead, Deep, Nested Complexity)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
New code is healthy Violations Code Health Impact
abscissa.py 3 rules 10.00 → 8.64 Suppress
Enforce critical code health rules Violations Code Health Impact
abscissa.py 2 critical rules 10.00 → 8.64 Suppress
View Improvements
File Code Health Impact Categories Improved
transforms.py 9.39 → 10.00 Deep, Nested Complexity

Quality Gate Profile: The Bare Minimum
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

@lucas-wilkins lucas-wilkins force-pushed the 148-refactor_24-sasdata-derived-objects branch from 31d7c10 to 78bcc6d Compare August 14, 2025 11:41
Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

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

Gates Failed
New code is healthy (1 new file with code health below 9.00)
Enforce critical code health rules (1 file with Bumpy Road Ahead, Deep, Nested Complexity)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
New code is healthy Violations Code Health Impact
abscissa.py 3 rules 10.00 → 8.64 Suppress
Enforce critical code health rules Violations Code Health Impact
abscissa.py 2 critical rules 10.00 → 8.64 Suppress

Quality Gate Profile: The Bare Minimum
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

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

Gates Failed
New code is healthy (1 new file with code health below 9.00)
Enforce critical code health rules (1 file with Bumpy Road Ahead, Deep, Nested Complexity)

Gates Passed
1 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
New code is healthy Violations Code Health Impact
abscissa.py 3 rules 10.00 → 8.64 Suppress
Enforce critical code health rules Violations Code Health Impact
abscissa.py 2 critical rules 10.00 → 8.64 Suppress

Quality Gate Profile: The Bare Minimum
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

Comment on lines +57 to +107
def determine(axis_data: list[Quantity[ArrayLike]], ordinate_data: Quantity[ArrayLike]) -> "Abscissa":
""" Get an Abscissa object that fits the combination of axes and data"""

# Different posibilites:
# 1: axes_data[i].shape == axes_data[j].shape == ordinate_data.shape
# 1a: axis_data[i] is 1D =>
# 1a-i: len(axes_data) == 1 => Grid type or Scatter type depending on sortedness
# 1a-ii: len(axes_data) != 1 => Scatter type
# 1b: axis_data[i] dimensionality matches len(axis_data) => Meshgrid type
# 1c: other => Error
# 2: (len(axes_data[0]), len(axes_data[1])... ) == ordinate_data.shape => Grid type
# 3: None of the above => Error

ordinate_shape = np.array(ordinate_data.value).shape
axis_arrays = [np.array(axis.value) for axis in axis_data]

# 1:
if all([axis.shape == ordinate_shape for axis in axis_arrays]):
# 1a:
if all([len(axis.shape)== 1 for axis in axis_arrays]):
# 1a-i:
if len(axis_arrays) == 1:
# Is it sorted
if is_increasing(axis_arrays[0]):
return GridAbscissa(axis_data)
else:
return ScatterAbscissa(axis_data)
# 1a-ii
else:
return ScatterAbscissa(axis_data)
# 1b
elif all([len(axis.shape) == len(axis_arrays) for axis in axis_arrays]):

return MeshgridAbscissa(axis_data)

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))

elif all([len(axis.shape)== 1 for axis in axis_arrays]) and \
tuple([axis.shape[0] for axis in axis_arrays]) == ordinate_shape:

# Require that they are sorted
if all([is_increasing(axis) for axis in axis_arrays]):

return GridAbscissa(axis_data)

else:
raise InterpretationError("Grid axes are not sorted")

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))

Choose a reason for hiding this comment

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

❌ New issue: Complex Method
Abscissa.determine has a cyclomatic complexity of 24, threshold = 9

Suppress

Comment on lines +57 to +107
def determine(axis_data: list[Quantity[ArrayLike]], ordinate_data: Quantity[ArrayLike]) -> "Abscissa":
""" Get an Abscissa object that fits the combination of axes and data"""

# Different posibilites:
# 1: axes_data[i].shape == axes_data[j].shape == ordinate_data.shape
# 1a: axis_data[i] is 1D =>
# 1a-i: len(axes_data) == 1 => Grid type or Scatter type depending on sortedness
# 1a-ii: len(axes_data) != 1 => Scatter type
# 1b: axis_data[i] dimensionality matches len(axis_data) => Meshgrid type
# 1c: other => Error
# 2: (len(axes_data[0]), len(axes_data[1])... ) == ordinate_data.shape => Grid type
# 3: None of the above => Error

ordinate_shape = np.array(ordinate_data.value).shape
axis_arrays = [np.array(axis.value) for axis in axis_data]

# 1:
if all([axis.shape == ordinate_shape for axis in axis_arrays]):
# 1a:
if all([len(axis.shape)== 1 for axis in axis_arrays]):
# 1a-i:
if len(axis_arrays) == 1:
# Is it sorted
if is_increasing(axis_arrays[0]):
return GridAbscissa(axis_data)
else:
return ScatterAbscissa(axis_data)
# 1a-ii
else:
return ScatterAbscissa(axis_data)
# 1b
elif all([len(axis.shape) == len(axis_arrays) for axis in axis_arrays]):

return MeshgridAbscissa(axis_data)

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))

elif all([len(axis.shape)== 1 for axis in axis_arrays]) and \
tuple([axis.shape[0] for axis in axis_arrays]) == ordinate_shape:

# Require that they are sorted
if all([is_increasing(axis) for axis in axis_arrays]):

return GridAbscissa(axis_data)

else:
raise InterpretationError("Grid axes are not sorted")

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))

Choose a reason for hiding this comment

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

❌ New issue: Bumpy Road Ahead
Abscissa.determine has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function

Suppress

Comment on lines +57 to +107
def determine(axis_data: list[Quantity[ArrayLike]], ordinate_data: Quantity[ArrayLike]) -> "Abscissa":
""" Get an Abscissa object that fits the combination of axes and data"""

# Different posibilites:
# 1: axes_data[i].shape == axes_data[j].shape == ordinate_data.shape
# 1a: axis_data[i] is 1D =>
# 1a-i: len(axes_data) == 1 => Grid type or Scatter type depending on sortedness
# 1a-ii: len(axes_data) != 1 => Scatter type
# 1b: axis_data[i] dimensionality matches len(axis_data) => Meshgrid type
# 1c: other => Error
# 2: (len(axes_data[0]), len(axes_data[1])... ) == ordinate_data.shape => Grid type
# 3: None of the above => Error

ordinate_shape = np.array(ordinate_data.value).shape
axis_arrays = [np.array(axis.value) for axis in axis_data]

# 1:
if all([axis.shape == ordinate_shape for axis in axis_arrays]):
# 1a:
if all([len(axis.shape)== 1 for axis in axis_arrays]):
# 1a-i:
if len(axis_arrays) == 1:
# Is it sorted
if is_increasing(axis_arrays[0]):
return GridAbscissa(axis_data)
else:
return ScatterAbscissa(axis_data)
# 1a-ii
else:
return ScatterAbscissa(axis_data)
# 1b
elif all([len(axis.shape) == len(axis_arrays) for axis in axis_arrays]):

return MeshgridAbscissa(axis_data)

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))

elif all([len(axis.shape)== 1 for axis in axis_arrays]) and \
tuple([axis.shape[0] for axis in axis_arrays]) == ordinate_shape:

# Require that they are sorted
if all([is_increasing(axis) for axis in axis_arrays]):

return GridAbscissa(axis_data)

else:
raise InterpretationError("Grid axes are not sorted")

else:
raise InterpretationError(Abscissa._determine_error_message(axis_arrays, ordinate_shape))

Choose a reason for hiding this comment

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

❌ New issue: Deep, Nested Complexity
Abscissa.determine has a nested complexity depth of 4, threshold = 4

Suppress

@DrPaulSharp DrPaulSharp force-pushed the refactor_24 branch 2 times, most recently from d4683bd to 3df6e01 Compare November 7, 2025 17:52
@DrPaulSharp DrPaulSharp force-pushed the refactor_24 branch 2 times, most recently from b32dbfe to 6f3b4af Compare December 9, 2025 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants