Skip to content

Commit

Permalink
Merge pull request #1607 from Shopify/envex/fill-linear-charts
Browse files Browse the repository at this point in the history
Fill linear charts when necessary
  • Loading branch information
envex authored Nov 16, 2023
2 parents cb7325a + ae6af05 commit e4609eb
Show file tree
Hide file tree
Showing 14 changed files with 640 additions and 137 deletions.
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

### Changed

- We now assume that linear charts `<LineChart />`, `<LineChartRelational />` & `<StackedAreaChart />` have matching keys in each data set. Any keys that do not have matching data sets will be filled so all charts contain the same keys.

## [9.18.2] - 2023-11-15

Expand Down
148 changes: 147 additions & 1 deletion packages/polaris-viz/src/components/Docs/stories/Data.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Meta, Story, Canvas} from '@storybook/addon-docs';
import {Meta, Story, Canvas, Source} from '@storybook/addon-docs';
import LinkTo from '@storybook/addon-links/react';
import {SHARK_SPECIES_GROWTH} from '../utilities';
import {PolarisVizProvider} from '@shopify/polaris-viz';
Expand Down Expand Up @@ -357,5 +357,151 @@ If we use the same data set used above but set `isComparison: true` to the first
/>

</ExamplesGrid>

<Title type="h2">Filling Data</Title>

When providing multiple `DataSeries` objects, we will fill all the `Series` so that all arrays contain the same keys. The filled `Series` will contain `null` as a value.

<Title type="h4">Example</Title>

Suppose we have the following data arrays, we will fill the data arrays to ensure all keys are present in each `DataSeries` object

<ExamplesGrid>

<div>

**Input**

<Source
dark
language="jsx"
code={`
[
{
name: 'Canada',
data: [
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
],
},
{
name: 'United States',
data: [
{key: 'Lizards', value: 350.13},
{key: 'Turtles', value: 223.43},
],
},
{
name: 'China',
data: [
{key: 'Snakes', value: 0},
{key: 'Eagles', value: 0},
],
},
]
`}
/>

</div>

<div>

**Output**

<Source
dark
language="jsx"
code={`
[
{
name: 'Canada',
data: [
{key: 'Dogs', value: 23.43},
{key: 'Cats', value: 6.64},
{key: 'Lizards', value: null},
{key: 'Turtles', value: null},
{key: 'Snakes', value: null},
{key: 'Eagles', value: null},
],
},
{
name: 'United States',
data: [
{key: 'Dogs', value: null},
{key: 'Cats', value: null},
{key: 'Lizards', value: 350.13},
{key: 'Turtles', value: 223.43},
{key: 'Snakes', value: null},
{key: 'Eagles', value: null},
],
},
{
name: 'China',
data: [
{key: 'Dogs', value: null},
{key: 'Cats', value: null},
{key: 'Lizards', value: null},
{key: 'Turtles', value: null},
{key: 'Snakes', value: 0},
{key: 'Eagles', value: 0},
],
},
]
`}
/>

</div>

</ExamplesGrid>

<Title type="h3">Linear Data</Title>

This approach assumes that linear charts (`<LineChart />`, `<LineChartRelational />` & `<StackedAreaChart />`) will have matching keys for each `DataSeries`.

When creating the chart labels, we use the keys from the longest `DataSeries`. The keys from other `DataSeries` objects are ignored.

If a user provides different keys, the `DataSeries` will be combined, resulting in a longer set of data.

The exception to this rule is when a `DataSeries` is provided with `isComparison: true`. In that case, we will not fill the data because comparison data can have different dates for each key and can also include data of different sizes.

<Source
dark
language="jsx"
code={`
[
{
name: 'This Year',
data: [
{key: 'January', value: 10},
{key: 'February', value: 20},
{key: 'March', value: 30},
{key: 'April', value: 10},
{key: 'May', value: 20},
{key: 'June', value: 30},
],
},
{
name: 'Last Year',
data: [
{key: 'January', value: 0},
{key: 'February', value: 5},
{key: 'March', value: 10},
{key: 'April', value: 0},
{key: 'May', value: 5},
{key: 'June', value: 10},
{key: 'July', value: 10},
{key: 'August', value: 10},
{key: 'September', value: 10},
{key: 'October', value: 10},
{key: 'November', value: 10},
{key: 'December', value: 10},
],
isComparison: true
}
]
`}
/>

</div>

</PolarisVizProvider>
32 changes: 17 additions & 15 deletions packages/polaris-viz/src/components/Docs/utilities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,34 @@ const PRODUCT_NAMES = [
'Glasses',
];

const DATES = [
'2020-04-10T12:00:00',
'2020-04-09T12:00:00',
'2020-04-08T12:00:00',
'2020-04-07T12:00:00',
'2020-04-06T12:00:00',
'2020-04-05T12:00:00',
'2020-04-04T12:00:00',
'2020-04-03T12:00:00',
'2020-04-02T12:00:00',
'2020-04-01T12:00:00',
];

export function randomNumber(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

function generateDayRange(numDays: number) {
const currentDate = new Date('April 1, 2020');
const dayRange: string[] = [];

for (let i = 0; i < numDays; i++) {
const date = new Date(currentDate);
date.setDate(date.getDate() + i);
dayRange.push(date.toString());
}

return dayRange;
}

export const generateDataSet = (dataLength: number, typeOfData: string) => {
const dates = typeOfData === 'dates' ? generateDayRange(dataLength) : [];

return Array(dataLength)
.fill(null)
.map(() => {
.map((_, index) => {
return {
value: randomNumber(20, 50),
key:
typeOfData === 'dates'
? DATES[Math.floor(Math.random() * DATES.length)]
? dates[index]
: PRODUCT_NAMES[Math.floor(Math.random() * PRODUCT_NAMES.length)],
};
});
Expand Down
5 changes: 4 additions & 1 deletion packages/polaris-viz/src/components/LineChart/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
usePolarisVizContext,
} from '@shopify/polaris-viz-core';

import {fillMissingDataPoints} from '../../utilities/fillMissingDataPoints';
import {getLineChartDataWithDefaults} from '../../utilities/getLineChartDataWithDefaults';
import {ChartContainer} from '../../components/ChartContainer';
import {ChartSkeleton} from '../../components/ChartSkeleton';
Expand Down Expand Up @@ -52,7 +53,7 @@ export function LineChart(props: LineChartProps) {

const {
annotations = [],
data,
data: dataSeries,
emptyStateText,
errorText,
id,
Expand All @@ -71,6 +72,8 @@ export function LineChart(props: LineChartProps) {
...props,
};

const data = fillMissingDataPoints(dataSeries);

const selectedTheme = useTheme(theme);
const seriesColors = useThemeSeriesColors(data, selectedTheme);

Expand Down
Loading

0 comments on commit e4609eb

Please sign in to comment.