mirror of
https://github.com/valitydev/redash.git
synced 2024-11-06 00:55:16 +00:00
Align Y axes at zero (#5053)
* Align Y axes as zero * Fix typo (with @deecay) * Add alignYAxesAtZero function * Avoid 0 division Co-authored-by: Gabriel Dutra <nesk.frz@gmail.com>
This commit is contained in:
parent
a473611cb0
commit
4fb77867b0
@ -32,6 +32,16 @@ export default function YAxisSettings({ options, onOptionsChange }) {
|
||||
onChange={axis => onOptionsChange({ yAxis: [leftYAxis, axis] })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
id="chart-editor-y-axis-align-at-zero"
|
||||
data-test="Chart.YAxis.AlignAtZero"
|
||||
defaultChecked={options.alignYAxesAtZero}
|
||||
onChange={alignYAxesAtZero => onOptionsChange({ alignYAxesAtZero })}>
|
||||
Align Y Axes at Zero
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
|
@ -5,8 +5,9 @@ const DEFAULT_OPTIONS = {
|
||||
globalSeriesType: "column",
|
||||
sortX: true,
|
||||
legend: { enabled: true, placement: "auto", traceorder: "normal" },
|
||||
yAxis: [{ type: "linear" }, { type: "linear", opposite: true }],
|
||||
xAxis: { type: "-", labels: { enabled: true } },
|
||||
yAxis: [{ type: "linear" }, { type: "linear", opposite: true }],
|
||||
alignYAxesAtZero: false,
|
||||
error_y: { type: "data", visible: true },
|
||||
series: { stacking: null, error_y: { type: "data", visible: true } },
|
||||
seriesOptions: {},
|
||||
|
@ -4,6 +4,42 @@ function calculateAxisRange(range, min, max) {
|
||||
return [isNumber(min) ? min : range[0], isNumber(max) ? max : range[1]];
|
||||
}
|
||||
|
||||
function calculateAbsoluteDiff(value, totalRange, percentageDiff) {
|
||||
return (percentageDiff * totalRange) / (1 - Math.abs(value) / totalRange - percentageDiff);
|
||||
}
|
||||
|
||||
function alignYAxesAtZero(axisA, axisB) {
|
||||
// Make sure the origin is included in both axes
|
||||
axisA.range[1] = Math.max(0, axisA.range[1]);
|
||||
axisB.range[1] = Math.max(0, axisB.range[1]);
|
||||
axisA.range[0] = Math.min(0, axisA.range[0]);
|
||||
axisB.range[0] = Math.min(0, axisB.range[0]);
|
||||
|
||||
const totalRangeA = axisA.range[1] - axisA.range[0];
|
||||
const proportionA = axisA.range[1] / totalRangeA;
|
||||
const totalRangeB = axisB.range[1] - axisB.range[0];
|
||||
const proportionB = axisB.range[1] / totalRangeB;
|
||||
|
||||
// Calculate the difference between the proportions and distribute them within the two axes
|
||||
const diff = Math.abs(proportionB - proportionA) / 2;
|
||||
|
||||
// Don't do anything if the difference is too low
|
||||
if (diff < 0.01) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Select the two that will correct the proportion by always augmenting, so the chart is not cut
|
||||
if (proportionA < proportionB) {
|
||||
// increase axisA max and axisB min
|
||||
axisA.range[1] += calculateAbsoluteDiff(axisA.range[1], totalRangeA, diff);
|
||||
axisB.range[0] -= calculateAbsoluteDiff(axisA.range[0], totalRangeB, diff);
|
||||
} else {
|
||||
// increase axisB max and axisA min
|
||||
axisB.range[1] += calculateAbsoluteDiff(axisB.range[1], totalRangeB, diff);
|
||||
axisA.range[0] -= calculateAbsoluteDiff(axisA.range[0], totalRangeA, diff);
|
||||
}
|
||||
}
|
||||
|
||||
export default function updateYRanges(plotlyElement, layout, options) {
|
||||
const updates = {};
|
||||
if (isObject(layout.yaxis)) {
|
||||
@ -38,6 +74,10 @@ export default function updateYRanges(plotlyElement, layout, options) {
|
||||
updates.yaxis2.range = calculateAxisRange(defaultRange, axisOptions.rangeMin, axisOptions.rangeMax);
|
||||
}
|
||||
|
||||
if (options.alignYAxesAtZero && isObject(layout.yaxis) && isObject(layout.yaxis2)) {
|
||||
alignYAxesAtZero(updates.yaxis, updates.yaxis2);
|
||||
}
|
||||
|
||||
return [updates, null]; // no further updates
|
||||
},
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user