I have a function:
def aspect_good(angle: float, planet1_good: bool, planet2_good: bool):
"""
Decides if the angle represents a good aspect.
NOTE: returns None if the angle doesn't represent an aspect.
"""
if 112 <= angle <= 128 or 52 <= angle <= 68:
return True
elif 174 <= angle <= 186 or 84 <= angle <= 96:
return False
elif 0 <= angle <= 8 and planet1_good and planet2_good:
return True
elif 0 <= angle <= 6:
return False
else:
return None
I want to vectorize it, such that instead of passing one value for each argument I could pass in numpy arrays. The signature would look like this:
def aspect_good(
angles: np.ndarray[float],
planet1_good: np.ndarray[bool],
planet2_good: np.ndarray[bool],
) -> np.array[bool | None]:
I'm not sure how to do it though, I could convert each if, elif statement:
((112 <= angles) & (angles <= 128)) | ((52 <= angles) & (angles <= 68))
((174 <= angles) & (angles <= 186)) | ((84 <= angles) & (angles <= 96))
((0 <= angles) & (angles <= 8)) & planets1_good & planets2_good
((0 <= angles) & (angles <= 6))
# how to convert the 'else' statement?
But I'm not really sure how to connect them now. Can somebody please help? I don't have a lot of experience with numpy, maybe it has some useful functions to do this.
UPDATE
Big thanks to everybody, and especially to @Mad Physicist.
So, I can use this:
def aspect_good(angles: np.typing.ArrayLike, planets1_good: np.typing.ArrayLike, planets2_good: np.typing.ArrayLike) -> np.typing.NDArray:
"""
Decides if the angle represents a good aspect.
"""
result = np.full_like(angle, -1, dtype=np.int8)
false_mask = np.abs(angle % 90) <= 6
result[false_mask] = 0
true_mask = np.abs(angle % 60) <= 8
result[true_mask] = 1
return result
This is awesome! Kudos to Mad Physicist, the solution is so beautiful and simple, even simpler than what I had before. Have a happy life, good sir!
np.arrayof True, False, None.Nonedoesn't mean an error, nor does it meanFalse. There is a clear distinction betweenFalseandNonein my app, as it says in the function docs "None means the angle is nor good nor bad"booldtype array can only have True/False values. An integer one could have more. Object dtype could contain theNonevalues (in factnp.empty(3, object)returns an array full ofNone). But you can't do further logic on an array containingNone. Anp.mamasked array could mark some values as "not valid". That in effect uses 2 bool arrays, thedataand themask(valid/invalid).