diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 57912cce2..0d9f9d89c 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -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 🛎️ diff --git a/packages/polaris-viz-core/src/types.ts b/packages/polaris-viz-core/src/types.ts index c24bfaa40..adf997bb9 100644 --- a/packages/polaris-viz-core/src/types.ts +++ b/packages/polaris-viz-core/src/types.ts @@ -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 { diff --git a/packages/polaris-viz/CHANGELOG.md b/packages/polaris-viz/CHANGELOG.md index 2573f4026..e84d2ec14 100644 --- a/packages/polaris-viz/CHANGELOG.md +++ b/packages/polaris-viz/CHANGELOG.md @@ -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 + +### 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 diff --git a/packages/polaris-viz/src/utilities/fillMissingDataPoints.ts b/packages/polaris-viz/src/utilities/fillMissingDataPoints.ts index 6114c9f5f..6c061ecdc 100644 --- a/packages/polaris-viz/src/utilities/fillMissingDataPoints.ts +++ b/packages/polaris-viz/src/utilities/fillMissingDataPoints.ts @@ -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(); const dataValueMap: {[key: number]: {[key: string]: number | null}} = {}; - for (const [index, {data}] of dataSeries.entries()) { for (const {key, value} of data) { allKeys.add(`${key}`); @@ -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}; diff --git a/packages/polaris-viz/src/utilities/tests/fillMissingDataPoints.test.ts b/packages/polaris-viz/src/utilities/tests/fillMissingDataPoints.test.ts index b7ac745e7..3eee6071e 100644 --- a/packages/polaris-viz/src/utilities/tests/fillMissingDataPoints.test.ts +++ b/packages/polaris-viz/src/utilities/tests/fillMissingDataPoints.test.ts @@ -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 = [ {