Skip to content

Commit

Permalink
Introduce optional fillValue property on DataSeries (#1611)
Browse files Browse the repository at this point in the history
* Introduce optional `fillValue` property on `DataSeries`

* Added better changelog

* Fix GH action so we run chromatic on all non-dependabot PRs.

* Add comment to `types.ts` indicate meaning of `fillValue`

Co-authored-by: Koen Vendrik <[email protected]>

---------

Co-authored-by: Koen Vendrik <[email protected]>
  • Loading branch information
philschoefer and kvendrik authored Dec 1, 2023
1 parent 55a5127 commit 22922a7
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/chromatic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on: push
jobs:
chromatic:
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}
continue-on-error: true
steps:
- name: Checkout 🛎️
Expand Down
4 changes: 4 additions & 0 deletions packages/polaris-viz-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export interface DataSeries {
name?: string;
metadata?: {[key: string]: any};
styleOverride?: StyleOverride;
/**
* Value that gets used to fill in missing data points. Defaults to `null`.
*/
fillValue?: DataPoint['value'];
}

interface StyleOverride {
Expand Down
6 changes: 5 additions & 1 deletion packages/polaris-viz/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

<!-- ## Unreleased -->
## Unreleased

### Added

- Experimental feature to define a `fillValue` for a `DataSeries` which Polaris Viz will use to backfill missing data points

## [10.0.1] - 2023-11-16

Expand Down
10 changes: 5 additions & 5 deletions packages/polaris-viz/src/utilities/fillMissingDataPoints.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import type {DataSeries} from '@shopify/polaris-viz-core';

export function fillMissingDataPoints(dataSeries: DataSeries[]) {
const areAnyComparrison = dataSeries.some(
const areAnyComparison = dataSeries.some(
({isComparison}) => isComparison === true,
);

if (areAnyComparrison) {
if (areAnyComparison) {
return dataSeries;
}

const allKeys = new Set<string>();
const dataValueMap: {[key: number]: {[key: string]: number | null}} = {};

for (const [index, {data}] of dataSeries.entries()) {
for (const {key, value} of data) {
allKeys.add(`${key}`);
Expand All @@ -27,10 +26,11 @@ export function fillMissingDataPoints(dataSeries: DataSeries[]) {
return dataSeries.map((series, index) => {
const newData = [...allKeys].map((key) => {
const dataValue = dataValueMap[index];

const fillValue =
series.fillValue !== undefined ? series.fillValue : null;
return {
key,
value: dataValue == null ? null : dataValue[key] ?? null,
value: dataValue == null ? null : dataValue[key] ?? fillValue,
};
});
return {...series, data: newData};
Expand Down
120 changes: 120 additions & 0 deletions packages/polaris-viz/src/utilities/tests/fillMissingDataPoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,126 @@ describe('fillMissingDataPoints', () => {
]);
});

it('fills data with null by default', () => {
const mockData = [
{
name: 'Canada',
data: [
{key: 'Mice', value: 13.28},
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
{key: 'Birds', value: 54.47},
],
},
{
name: 'China',
data: [
{key: 'Snakes', value: 0},
{key: 'Dogs', value: 0},
],
},
];

const result = fillMissingDataPoints(mockData);

expect(result).toMatchObject(
expect.arrayContaining([
expect.objectContaining({
data: expect.arrayContaining([
expect.objectContaining({
value: null,
}),
]),
}),
]),
);
});

it('fills data with provided fill value when defined on series', () => {
const mockData = [
{
name: 'Canada',
data: [
{key: 'Mice', value: 13.28},
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
{key: 'Birds', value: 54.47},
],
},
{
name: 'China',
data: [
{key: 'Snakes', value: 10},
{key: 'Dogs', value: 10},
],
fillValue: 0,
},
];

const result = fillMissingDataPoints(mockData);

expect(result).toMatchObject(
expect.arrayContaining([
expect.objectContaining({
data: expect.arrayContaining([
expect.objectContaining({
value: 0,
}),
]),
}),
]),
);
});

it('fills data with fill value for provided series only', () => {
const mockData = [
{
name: 'Canada',
data: [
{key: 'Mice', value: 13.28},
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
{key: 'Birds', value: 54.47},
],
fillValue: null,
},
{
name: 'China',
data: [
{key: 'Snakes', value: 10},
{key: 'Dogs', value: 10},
],
fillValue: 0,
},
];

const result = fillMissingDataPoints(mockData);

expect(result).toMatchObject(
expect.arrayContaining([
expect.objectContaining({
data: expect.arrayContaining([
expect.objectContaining({
value: 0,
}),
]),
}),
]),
);

expect(result).toMatchObject(
expect.arrayContaining([
expect.objectContaining({
data: expect.arrayContaining([
expect.objectContaining({
value: null,
}),
]),
}),
]),
);
});

it('returns the original data series if any are comparison', () => {
const mockData = [
{
Expand Down

0 comments on commit 22922a7

Please sign in to comment.