awtaylor opened a new issue, #21793: URL: https://github.com/apache/echarts/issues/21793
### What problem does this feature solve? Smoothed line and area series are easy to misread. With `smooth: true`, the constrained Bézier can bow past the samples and invent a peak or a valley that is not in the data. `smoothMonotone: 'x'` or `'y'` avoids that overshoot, but it does so by making the tangent horizontal or vertical at every sample, so each knot looks like a saddle or a plateau. That behavior was an intentional tradeoff ([#7158](https://github.com/apache/echarts/issues/7158)). It is still surprising on ordinary time series ([#21532](https://github.com/apache/echarts/issues/21532)): a sensor that rises and then levels off is drawn as if it turned over at every measurement. There is no option today for a curve that passes through the samples, keeps a continuous slope, and does not add extrema between samples. That is the usual monotone cubic interpolant in scientific tools (MATLAB `pchip`, SciPy `PchipInterpolator`, R `splinefun(..., method = "monoH.FC")`). Dashboards and monitoring charts are the common case: category or time on one axis, a value on the other, including stacked areas. This could be opt-in. The default smoother, and the existing `'x'`, `'y'`, and `'none'` modes, could happily stay as they are. ### What does the proposed API look like? Extend `series.line.smoothMonotone` with two values. No new option name, so the axis and the algorithm stay in the option that already means "how should smoothing respect monotonicity". ```js option = { xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: {}, series: [{ type: 'line', data: [12, 18, 18, 30, 22, 16, 28], smooth: true, smoothMonotone: 'monotoneX', areaStyle: {} }] }; ``` - `monotoneX`: y is a function of x. This is the time-series case in #21532. - `monotoneY`: x is a function of y. - `'x'`, `'y'`, `'none'`, and the default `null` remain unchanged. In particular, `'x'` and `'y'` keep the flat tangents. - `smooth: false` still a polyline. In this mode only, `smooth: true` means full-strength Hermite tangents. A number is clamped to `(0, 1]` and multiplies those tangents, which stays monotone. Numbers above `1` are clamped to `1`. In the existing Bézier modes, `smooth: true` would still means tension `0.5`. - Stacked areas use the same mode for the baseline. Each series' own `smooth` value is the tangent scale for its boundary. - Cartesian line series only. On a polar series the value is ignored and the current Bézier smooth is used, because the guarantee is about screen x or y and would be false after a polar projection. - Where the chosen axis is not strictly monotone (a repeated x, or a value axis that turns backward), that piece uses the existing non-monotone Bézier. A strictly decreasing run is handled, so an inverse axis still works. - `connectNulls` keeps its current meaning: nulls break the line, or are skipped and the remaining samples are interpolated. `monotoneX` names the axis. It is not a claim that the curve matches d3 `curveMonotoneX` (that implementation is Steffen's method). Other names could work too e.g., `smoothInterpolation: 'monotone'` if that fits the option style better. ### Method One cubic Bézier per segment, so the current path, hit testing, and area fill stay in place. The knots are the samples. Interior slopes are the Fritsch–Butland weighted harmonic mean (1984, doi:[10.1137/0905021](https://doi.org/10.1137/0905021), which lies in the Fritsch–Carlson monotone region (1980, doi:[10.1137/0717021](https://doi.org/10.1137/0717021)). End slopes are the one-sided three-point estimate, then clamped into that region ([Moler, *Numerical Computing with MATLAB*, 2004](https://www.mathworks.com/moler/chapters.html)). The code would be original, with those citations, and not be a port of SciPy, d3, or Chart.js. Other monotone or shape-preserving methods were considered and are not proposed as extra options. The three local cubic rules below are the same feature with different slope formulas; they differ visibly only when neighboring secants are very different. Shipping a menu of them would freeze that choice in the API. The slope step would be one function, so the formula can be swapped in review without an option change. - [**Steffen (1990)**](https://doi.org/10.4236/apm.2018.81003) is also local and monotone. It is d3 `curveMonotoneX` / `curveMonotoneY` and Vega-Lite `interpolate: "monotone"`. On equal spacing the slope is held down to the smaller neighboring secant, so a sharp turn looks a little tighter than Fritsch–Butland. This is the alternative I would switch to if maintainers prefer the d3/Vega look. - **Arithmetic mean of the secants, then project onto the 1980 disk** is what Chart.js uses for `cubicInterpolationMode: 'monotone'`. It is the roundest of the three and still monotone. Fritsch–Butland is the direct construction, so that projection is only needed at the endpoints. - **[Akima (1970)](https://doi.org/10.1145/321607.321609) and modified Akima** are local cubics that are not monotone. They can still overshoot. - **[Hyman (1983)](https://doi.org/10.1137/0904045) and [Huynh (1993)](https://doi.org/10.1137/0730004)** limit the slopes of a global cubic. One edited point can move the whole line, which fits shock-capturing better than an interactive chart with null breaks and large series. The quintic extension is not a cubic Bézier. - **[Delbourgo and Gregory's rational curves](ttps://bura.brunel.ac.uk/handle/2438/2285), and [Schumaker's shape-preserving quadratics](https://www.jstor.org/stable/2157245),** have a real tension parameter, and a segment is not one cubic Bézier. ECharts strokes with `bezierCurveTo`. Scaling the Fritsch–Butland slopes by `smooth` in `(0, 1]` is the tension control that stays inside that path model. The option spelling or the slope formula could be adjusted as the reviewers see fit. I would like to implement this and open a pull request that leaves the default and the existing `smoothMonotone` values behaviorally unchanged (with option docs in `apache/echarts-doc`). I would follow up there once the name is settled. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
