Steps tendency#176
Conversation
92352de to
088f660
Compare
088f660 to
2759f2d
Compare
- Rename is_string -> is_categorical so booleans are treated like strings (held as a zero-order-hold step rather than coerced to float and interpolated) - Reject mixing categorical (string/boolean) and numeric values within a single waveform, since the gaps between them cannot be interpolated - Document the constant tendency value types (float/int/categorical) in the docs
np.full preserved int dtype for integer constants, so get_value() (the time=None path) returned an int64 array while the explicit-time path upcast to float. Force float for numeric values; categorical values (str/bool) keep their native dtype.
A piecewise-constant tendency that holds each value from its breakpoint until the next, supporting non-numeric (string/boolean) values. Registered as 'steps'. - start is inferred from the first breakpoint; an explicit end/duration may be given so the final value is held for a real duration (defaults to the last time) - shared time/value validation and start/end resolution are factored out of PiecewiseLinearTendency via overridable _coerce_value / _resolve_time_bounds hooks, so the steps tendency only overrides what genuinely differs
2759f2d to
2ff4794
Compare
| from waveform_editor.tendencies.piecewise import PiecewiseLinearTendency | ||
|
|
||
|
|
||
| class StepsTendency(PiecewiseLinearTendency): |
There was a problem hiding this comment.
Also, the pointdraw tool doesn't work properly for step tendencies. Could you have a look at that or disable the pointdraw functionality?
| if eval_derivatives: | ||
| values[mask] = slope | ||
| values[mask] = ( | ||
| tendency.start_value - prev_tendency.end_value | ||
| ) / (tendency.start - prev_tendency.end) |
There was a problem hiding this comment.
won't this break for categorical values?
| @property | ||
| def is_categorical(self): | ||
| """Whether this constant holds a non-numeric (categorical) value, e.g. a | ||
| string or boolean, that is held as a step rather than interpolated.""" | ||
| value = self.value | ||
| return isinstance(value, bool) or not isinstance(value, (int, float)) |
There was a problem hiding this comment.
- {type: constant, value: ohmic, duration: 2}
- {type: smooth, duration: 2}
- {type: constant, value: nbi, duration: 2}
When I try to create the waveform above, it will raise a ValueError in the Scipy interpolation. Can we instead catch at an earlier point that categorical tendencies may not be mixed with non-categorical tendencies?
File "/home/sebbe/projects/iter_python/Waveform-Editor/venv/lib/python3.13/site-packages/scipy/interpolate/_cubic.py", line 792, in init
x, dx, y, axis, _ = prepare_input(x, y, axis, xp=np_compat)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/sebbe/projects/iter_python/Waveform-Editor/venv/lib/python3.13/site-packages/scipy/interpolate/_cubic.py", line 45, in prepare_input
y = xp.astype(y, dtype, copy=False)
File "/home/sebbe/projects/iter_python/Waveform-Editor/venv/lib/python3.13/site-packages/scipy/_lib/array_api_compat/numpy/aliases.py", line 106, in astype
return x.astype(dtype=dtype, copy=copy)
~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: could not convert string to float: np.str('ohmic')
| if end is None and kwargs.get("user_duration") is None: | ||
| kwargs["user_end"] = time[-1] | ||
| elif isinstance(end, (int, float)) and end < time[-1]: | ||
| self.pre_check_annotations.add( | ||
| line_number, | ||
| "The `end` of a steps tendency must not precede the last time.\n", | ||
| ) |
There was a problem hiding this comment.
Shouldn't you check a minimum duration as well? e.g. this seems to be allowed but this should raise an error:
- {type: steps, value: [1, 3, 5], time: [1, 2, 3], duration: 1}

Includes a commit from #175