-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(xy): stacked polarity #1502
Merged
+586
−301
Merged
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
6637aaf
fix: stacked polarity
nickofthyme de17519
refactor: stacking logic to group by x values
nickofthyme 5b08ee4
feat: add diverging support for all offset types
nickofthyme 0dcb91a
Merge branch 'master' into fix-stacked-polarity
nickofthyme 56249bc
fix: block using y0 accessors with split accessors
nickofthyme ef38163
fix: add bypass for non-mixed polarity data
nickofthyme 6f1cdb9
fix: remove filtered series from stack logic
nickofthyme c8eefea
fix: percentage stack offset to work for mixed polarity
nickofthyme 96797fe
fix: wiggle for negative values
nickofthyme cf7ae39
fix: cleanup types for offset functions
nickofthyme a9e7486
test: add vrt for all offset options and polarity cases
nickofthyme 0f40afc
fix: diverging logic for 0 case
nickofthyme fde8d5a
refactor: offset values to include y0 for fitting purposes
nickofthyme c1cf8ad
refactor: ignore y0Accessors when used with stackAccessors at the dat…
nickofthyme 25d11af
fix: apply percentage domain logic only when stacked
nickofthyme 8a1aef2
fix: remove y0 points in disallowed banded stack area charts
nickofthyme e1034d8
fix: series toggle logic with stacked offsets
nickofthyme 0a58d76
fix: percent offset stopping after sum of zero
nickofthyme 1b0a6a1
test: update vrt screenshots for mixes stories
nickofthyme ef547ea
fix: stacking order and stack value logic
nickofthyme 7e9149a
test: add tests for found and fixed edge cases
nickofthyme 075527b
test: prune stale vrt screenshots
nickofthyme d4c0196
fix: linting error
nickofthyme e916c6d
test: fix failing tests
nickofthyme 9eb5bf4
feat: add 0 baseline datum
nickofthyme 73a9e3c
refactor: rename banded spec check to be consistent throughout
nickofthyme ff2f537
test: update vrt screenshots with added baseline datum
nickofthyme f06db8a
chore: add warning when using area charts on mixed polarity datasets
nickofthyme edcb883
test: fix failing tests
nickofthyme File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+36.2 KB
...ntage-polarity-mixed-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+18.5 KB
...entage-polarity-mixed-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+36.2 KB
...ge-polarity-negative-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+18.5 KB
...age-polarity-negative-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+36.2 KB
...ge-polarity-positive-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+18.5 KB
...age-polarity-positive-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+48.4 KB
...uette-polarity-mixed-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+20.2 KB
...ouette-polarity-mixed-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+34.7 KB
...te-polarity-negative-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+20 KB
...tte-polarity-negative-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+35.5 KB
...te-polarity-positive-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+19.9 KB
...tte-polarity-positive-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+45.7 KB
...iggle-polarity-mixed-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+19.9 KB
...wiggle-polarity-mixed-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+32 KB
...le-polarity-negative-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+20.5 KB
...gle-polarity-negative-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+31.5 KB
...le-polarity-positive-should-display-correct-stacking-for-area-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+19.8 KB
...gle-polarity-positive-should-display-correct-stacking-for-bar-series-1-snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ export function renderArea( | |
areaGeometry: AreaGeometry; | ||
indexedGeometryMap: IndexedGeometryMap; | ||
} { | ||
const isBandChart = hasY0Accessors && !isStacked; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we reuse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
const y1Fn = getY1ScaledValueFn(yScale); | ||
const y0Fn = getY0ScaledValueFn(yScale); | ||
const definedFn = isYValueDefinedFn(yScale, xScale); | ||
|
@@ -57,15 +58,15 @@ export function renderArea( | |
.y1(y1Fn) | ||
.y0(y0Fn) | ||
.defined((datum) => { | ||
return definedFn(datum, y1DatumAccessor) && (hasY0Accessors ? definedFn(datum, y0DatumAccessor) : true); | ||
return definedFn(datum, y1DatumAccessor) && (isBandChart ? definedFn(datum, y0DatumAccessor) : true); | ||
}) | ||
.curve(getCurveFactory(curve)); | ||
|
||
// TODO we can probably avoid this function call if no fit function is applied. | ||
const clippedRanges = getClippedRanges(dataSeries.data, xScale, xScaleOffset); | ||
|
||
const lines: string[] = []; | ||
const y0Line = hasY0Accessors && pathGenerator.lineY0()(dataSeries.data); | ||
const y0Line = isBandChart && pathGenerator.lineY0()(dataSeries.data); | ||
const y1Line = pathGenerator.lineY1()(dataSeries.data); | ||
if (y1Line) lines.push(y1Line); | ||
if (y0Line) lines.push(y0Line); | ||
|
@@ -78,7 +79,7 @@ export function renderArea( | |
panel, | ||
color, | ||
style.point, | ||
hasY0Accessors, | ||
isBandChart, | ||
markSizeOptions, | ||
false, | ||
pointStyleAccessor, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
202 changes: 202 additions & 0 deletions
202
packages/charts/src/chart_types/xy_chart/utils/diverging_offsets.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
/* eslint-disable header/header, no-param-reassign */ | ||
|
||
/** | ||
* @notice | ||
* This product includes code that is adapted from d3-shape@3.0.1, | ||
* which is available under a "ISC" license. | ||
* | ||
* ISC License | ||
* | ||
* Copyright 2010-2021 Mike Bostock | ||
* Permission to use, copy, modify, and/or distribute this software for any purpose | ||
* with or without fee is hereby granted, provided that the above copyright notice | ||
* and this permission notice appear in all copies. | ||
|
||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | ||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | ||
* THIS SOFTWARE. | ||
*/ | ||
|
||
import { Series, SeriesPoint } from 'd3-shape'; | ||
|
||
import { SeriesKey } from '../../../common/series_id'; | ||
import { DataSeriesDatum } from './series'; | ||
|
||
type XValue = string | number; | ||
type SeriesValueMap = Map<SeriesKey, DataSeriesDatum>; | ||
|
||
/** @internal */ | ||
export type XValueMap = Map<XValue, SeriesValueMap>; | ||
/** @internal */ | ||
export type XValueSeriesDatum = [XValue, SeriesValueMap]; | ||
|
||
/** | ||
* Computes required wiggle offset for each x value __WITHOUT__ mutations | ||
*/ | ||
function getWiggleOffsets<K = string>(series: Series<XValueSeriesDatum, K>, order: number[]): number[] { | ||
const offsets = []; | ||
let y, j; | ||
for (y = 0, j = 1; j < series[order[0]].length; ++j) { | ||
let i, s1, s2; | ||
for (i = 0, s1 = 0, s2 = 0; i < series.length; ++i) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const si = series[order[i]] as SeriesPoint<XValueSeriesDatum>[]; | ||
const sij0 = si[j][1] || 0; | ||
const sij1 = si[j - 1][1] || 0; | ||
let s3 = (sij0 - sij1) / 2; | ||
|
||
for (let k = 0; k < i; ++k) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const sk = series[order[k]] as SeriesPoint<XValueSeriesDatum>[]; | ||
const skj0 = sk[j][1] || 0; | ||
const skj1 = sk[j - 1][1] || 0; | ||
s3 += skj0 - skj1; | ||
} | ||
s1 += sij0; | ||
s2 += s3 * sij0; | ||
} | ||
|
||
offsets.push(y); | ||
if (s1) y -= s2 / s1; | ||
} | ||
offsets.push(y); | ||
return offsets; | ||
} | ||
|
||
/** @internal */ | ||
const divergingOffset = (isSilhouette = false) => { | ||
return function <K = 'string'>(series: Series<XValueSeriesDatum, K>, order: number[]): void { | ||
const n = series.length; | ||
if (!(n > 0)) return; | ||
for (let i, j = 0, sumYn, sumYp, yp, yn = 0, s0 = series[order[0]], m = s0.length; j < m; ++j) { | ||
// sum negative values per x before to maintain original sort for negative values | ||
for (yn = 0, sumYn = 0, sumYp = 0, i = 0; i < n; ++i) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const d = series[order[i]][j] as SeriesPoint<XValueSeriesDatum>; | ||
const dy = d[1] - d[0]; | ||
if (dy < 0) { | ||
sumYn += Math.abs(d[1]) || 0; | ||
yn += dy; | ||
} else { | ||
sumYp += d[1] || 0; | ||
} | ||
} | ||
|
||
const silhouetteOffset = sumYp / 2 - sumYn / 2; | ||
const offset = isSilhouette ? -silhouetteOffset : 0; | ||
yn += offset; | ||
|
||
for (yp = offset, i = 0; i < n; ++i) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const d = series[order[i]][j] as SeriesPoint<XValueSeriesDatum>; | ||
const dy = d[1] - d[0]; | ||
if (dy >= 0) { | ||
d[0] = yp; | ||
d[1] = yp += dy; | ||
} else { | ||
d[1] = yn; | ||
d[0] = yn -= dy; | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
|
||
/** | ||
* Stacked offset function with diverging polarity offset | ||
* @internal | ||
*/ | ||
export const diverging = divergingOffset(); | ||
/** | ||
* Stacked Silhouette offset function with diverging polarity offset | ||
* @internal | ||
*/ | ||
export const divergingSilhouette = divergingOffset(true); | ||
|
||
/** | ||
* Stacked Wiggle offset function to account for diverging offset | ||
* @internal | ||
*/ | ||
export function divergingWiggle<K = 'string'>(series: Series<XValueSeriesDatum, K>, order: number[]): void { | ||
const n = series.length; | ||
const s0 = series[order[0]]; | ||
const m = s0.length; | ||
if (!(n > 0) || !(m > 0)) return diverging(series, order); | ||
|
||
const offsets = getWiggleOffsets(series, order); | ||
|
||
for (let i, j = 0, sumYn, yp, yn = 0; j < m; ++j) { | ||
// sum negative values per x before to maintain original sort for negative values | ||
for (i = 0, yn = 0, sumYn = 0; i < n; ++i) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const d = series[order[i]][j] as SeriesPoint<XValueSeriesDatum>; | ||
if (d[1] - d[0] < 0) { | ||
sumYn += Math.abs(d[1]) || 0; | ||
} | ||
} | ||
|
||
const offset = offsets[j]; | ||
yn += offset; | ||
|
||
for (yp = offset + sumYn, yn = offset, i = 0; i < n; ++i) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const d = series[order[i]][j] as SeriesPoint<XValueSeriesDatum>; | ||
const dy = d[1] - d[0]; | ||
if (dy >= 0) { | ||
d[0] = yp; | ||
d[1] = yp += dy; | ||
} else { | ||
d[1] = yn; | ||
d[0] = yn -= dy; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Stacked Percentage offset function with diverging polarity offset | ||
* Treats percentage as participation for mixed polarity data | ||
* @internal | ||
*/ | ||
export function divergingPercentage<K = 'string'>(series: Series<XValueSeriesDatum, K>, order: number[]): void { | ||
const n = series.length; | ||
if (!(n > 0)) return; | ||
for (let i, j = 0, sumYn, sumYp; j < series[0].length; ++j) { | ||
for (sumYn = sumYp = i = 0; i < n; ++i) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const d = series[order[i]][j] as SeriesPoint<XValueSeriesDatum>; | ||
if (d[1] - d[0] < 0) { | ||
sumYn += Math.abs(d[1]) || 0; | ||
} else { | ||
sumYp += d[1] || 0; | ||
} | ||
} | ||
|
||
const sumY = sumYn + sumYp; | ||
if (sumY === 0) continue; // must not return, else loop will stop | ||
|
||
let yp = sumYn / sumY; | ||
let yn = 0; | ||
|
||
for (i = 0; i < n; ++i) { | ||
// @ts-ignore - d3-shape type here is inaccurate | ||
const d = series[order[i]][j] as SeriesPoint<XValueSeriesDatum>; | ||
const dy = d[1] - d[0]; | ||
const participation = Math.abs(dy / sumY); | ||
|
||
if (dy >= 0) { | ||
d[0] = yp; | ||
d[1] = yp += participation; | ||
} else { | ||
d[0] = yn; | ||
d[1] = yn += participation; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/* eslint-enable header/header, no-param-reassign */ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what was the issue on upgrading to the latest version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The jest tests were throwing an error similar to https://stackoverflow.com/questions/49263429/jest-gives-an-error-syntaxerror-unexpected-token-export. I tried to fix it but couldn't see any difference between the 2 so I gave up for now.