Skip to content

Commit

Permalink
Fill DataSeries with mismatched data sets so all DataSeries have matc…
Browse files Browse the repository at this point in the history
…hing data structures
  • Loading branch information
envex committed Nov 7, 2023
1 parent 12c5eb5 commit 8ecfc59
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 1 deletion.
5 changes: 4 additions & 1 deletion packages/polaris-viz/src/components/BarChart/BarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {useRenderTooltipContent} from '../../hooks';
import {HorizontalBarChart} from '../HorizontalBarChart';
import {VerticalBarChart} from '../VerticalBarChart';
import {ChartSkeleton} from '../../components/ChartSkeleton';
import {fillMissingDataPoints} from '../../utilities/fillMissingDataPoints';

export type BarChartProps = {
errorText?: string;
Expand All @@ -51,7 +52,7 @@ export function BarChart(props: BarChartProps) {

const {
annotations = [],
data,
data: dataSeries,
state,
errorText,
direction = 'vertical',
Expand All @@ -71,6 +72,8 @@ export function BarChart(props: BarChartProps) {
...props,
};

const data = fillMissingDataPoints(dataSeries);

const skipLinkAnchorId = useRef(uniqueId('BarChart'));

const emptyState = data.length === 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type {Story} from '@storybook/react';

import {BarChart, BarChartProps} from '../../../../components';
import {META} from '../meta';

export default {
...META,
title: `${META.title}/Playground`,
};

const DATA = [
{
name: 'Canada',
data: [
{key: 'Mice', value: 13.28},
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
{key: 'Birds', value: 54.47},
],
},
{
name: 'United States',
data: [
{key: 'Lizards', value: 350.13},
{key: 'Turtles', value: 223.43},
{key: 'Mice', value: 15.38},
{key: 'Snakes', value: 122.68},
{key: 'Dogs', value: 31.54},
{key: 'Birds', value: 94.84},
],
},
{
name: 'China',
data: [
{key: 'Snakes', value: 0},
{key: 'Dogs', value: 0},
],
},
];

const Template: Story<BarChartProps> = () => {
return <BarChart data={DATA} />;
};

export const MisMatchedData = Template.bind({});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type {Story} from '@storybook/react';

import {SimpleBarChart, SimpleBarChartProps} from '../../../../components';
import {META} from '../meta';

export default {
...META,
title: `${META.title}/Playground`,
};

const DATA = [
{
name: 'Canada',
data: [
{key: 'Mice', value: 13.28},
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
{key: 'Birds', value: 54.47},
],
},
{
name: 'United States',
data: [
{key: 'Lizards', value: 350.13},
{key: 'Turtles', value: 223.43},
{key: 'Mice', value: 15.38},
{key: 'Snakes', value: 122.68},
{key: 'Dogs', value: 31.54},
{key: 'Birds', value: 94.84},
],
},
{
name: 'China',
data: [
{key: 'Snakes', value: 0},
{key: 'Dogs', value: 0},
],
},
];

const Template: Story<SimpleBarChartProps> = () => {
return (
<div style={{height: 600, width: 800}}>
<SimpleBarChart data={DATA} />
</div>
);
};

export const MisMatchedData = Template.bind({});
36 changes: 36 additions & 0 deletions packages/polaris-viz/src/utilities/fillMissingDataPoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type {DataSeries} from '@shopify/polaris-viz-core';

export function fillMissingDataPoints(dataSeries: DataSeries[]) {
const areAnyDataLengthsDifferent = dataSeries.some(
({data}) => data.length !== dataSeries[0].data.length,
);

if (!areAnyDataLengthsDifferent) {
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}`);

if (dataValueMap[index] == null) {
dataValueMap[index] = {};
}

dataValueMap[index][key] = value;
}
}

return dataSeries.map(({name}, index) => {
const newData = [...allKeys].map((key) => {
return {
key,
value: dataValueMap[index][key] ?? null,
};
});
return {name, data: newData};
});
}
146 changes: 146 additions & 0 deletions packages/polaris-viz/src/utilities/tests/fillMissingDataPoints.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import type {DataPoint, DataSeries} from '@shopify/polaris-viz-core';

import {fillMissingDataPoints} from '../fillMissingDataPoints';

describe('fillMissingDataPoints', () => {
it('returns original data when each array length matches', () => {
const mockData = [
{
name: 'Canada',
data: [
{key: 'Snakes', value: 122.68},
{key: 'Dogs', value: 31.54},
],
},
{
name: 'United States',
data: [
{key: 'Snakes', value: 122.68},
{key: 'Dogs', value: 31.54},
],
},
{
name: 'China',
data: [
{key: 'Snakes', value: 0},
{key: 'Dogs', value: 0},
],
},
];
const result = fillMissingDataPoints(mockData);
expect(result).toMatchObject(mockData);
});

it('fills data so all arrays contain all items', () => {
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: 'United States',
data: [
{key: 'Lizards', value: 350.13},
{key: 'Turtles', value: 223.43},
{key: 'Mice', value: 15.38},
{key: 'Snakes', value: 122.68},
{key: 'Dogs', value: 31.54},
{key: 'Birds', value: 94.84},
],
},
{
name: 'China',
data: [
{key: 'Snakes', value: 0},
{key: 'Dogs', value: 0},
],
},
];

const result = fillMissingDataPoints(mockData);

expect(result).toMatchObject([
{
name: 'Canada',
data: [
{key: 'Mice', value: 13.28},
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
{key: 'Birds', value: 54.47},
{key: 'Lizards', value: null},
{key: 'Turtles', value: null},
{key: 'Snakes', value: null},
],
},
{
name: 'United States',
data: [
{key: 'Mice', value: 15.38},
{key: 'Dogs', value: 31.54},
{key: 'Cats', value: null},
{key: 'Birds', value: 94.84},
{key: 'Lizards', value: 350.13},
{key: 'Turtles', value: 223.43},
{key: 'Snakes', value: 122.68},
],
},
{
name: 'China',
data: [
{key: 'Mice', value: null},
{key: 'Dogs', value: 0},
{key: 'Cats', value: null},
{key: 'Birds', value: null},
{key: 'Lizards', value: null},
{key: 'Turtles', value: null},
{key: 'Snakes', value: 0},
],
},
]);
});

it('loops through a large data set in less than 10ms', () => {
const data = getData();

const start = Date.now();
fillMissingDataPoints(data);
const elapsed = Date.now() - start;

expect(elapsed).toBeLessThan(10);
});
});

const DATA_SERIES_COUNT = 10;
const DATA_POINTS_COUNT = 500;

function getData() {
const largestArray: DataSeries[] = [];

for (let i = 1; i <= DATA_SERIES_COUNT; i++) {
const dataItems: DataPoint[] = [];
const randomOffset = getRandomNumber(0, DATA_POINTS_COUNT / 6);

for (let j = 1; j <= DATA_POINTS_COUNT - randomOffset; j++) {
const key = getRandomKey();
const value = getRandomNumber(0, 100);
dataItems.push({key, value});
}

largestArray.push({name: `Array ${i}`, data: dataItems});
}

return largestArray;

function getRandomNumber(min, max) {
return Math.random() * (max - min) + min;
}

function getRandomKey() {
return Math.random().toString(36).substring(7);
}
}

0 comments on commit 8ecfc59

Please sign in to comment.