Skip to content
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

feat(D3 plugin): Stacked percentage charts (bar-x, bar-y, area) #391

Merged
merged 2 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/i18n/keysets/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"label_invalid-axis-datetime-data-point": "It seems you are trying to use inappropriate data type for \"{{key}}\" value in series \"{{seriesName}}\" for axis with type \"datetime\". Only numbers are allowed.",
"label_invalid-axis-linear-data-point": "It seems you are trying to use inappropriate data type for \"{{key}}\" value in series \"{{seriesName}}\" for axis with type \"linear\". Numbers and nulls are allowed.",
"label_invalid-pie-data-value": "It seems you are trying to use inappropriate data type for \"value\" value. Only numbers are allowed.",
"label_invalid-series-type": "It seems you haven't defined \"series.type\" property, or defined it incorrectly. Available values: [{{types}}]."
"label_invalid-series-type": "It seems you haven't defined \"series.type\" property, or defined it incorrectly. Available values: [{{types}}].",
"label_invalid-series-property": "It seems you are trying to use inappropriate value for \"{{key}}\", or defined it incorrectly. Available values: [{{values}}]."
},
"highcharts": {
"reset-zoom-title": "Reset zoom",
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/keysets/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"label_invalid-axis-datetime-data-point": "Похоже, что вы пытаетесь использовать недопустимый тип данных для значения \"{{key}}\" в серии \"{{seriesName}}\" для оси с типом \"datetime\". Допускается только использование чисел.",
"label_invalid-axis-linear-data-point": "Похоже, что вы пытаетесь использовать недопустимый тип данных для значения \"{{key}}\" в серии \"{{seriesName}}\" для оси с типом \"linear\". Допускается использование чисел и значений null.",
"label_invalid-pie-data-value": "Похоже, что вы пытаетесь использовать недопустимый тип данных для значения \"value\". Допускается только использование чисел.",
"label_invalid-series-type": "Похоже, что вы не указали значение \"series.type\" или указали его неверно. Доступные значения: [{{types}}]."
"label_invalid-series-type": "Похоже, что вы не указали значение \"series.type\" или указали его неверно. Доступные значения: [{{types}}].",
"label_invalid-series-property": "Похоже, что вы пытаетесь использовать недопустимое значение для \"{{key}}\", или указали его неверно. Доступные значения: [{{values}}]."
},
"highcharts": {
"reset-zoom-title": "Сбросить увеличение",
Expand Down
19 changes: 17 additions & 2 deletions src/plugins/d3/__stories__/Showcase.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {D3Plugin} from '../index';
import {BasicBarXChart} from '../examples/bar-x/Basic';
import {GroupedColumns} from '../examples/bar-x/GroupedColumns';
import {StackedColumns} from '../examples/bar-x/StackedColumns';
import {PercentStackColumns} from '../examples/bar-x/PercentStack';
import {DataLabels as BarXDataLabels} from '../examples/bar-x/DataLabels';
import {Basic as BasicBarY} from '../examples/bar-y/Basic';
import {GroupedColumns as GroupedColumnsBarY} from '../examples/bar-y/GroupedColumns';
Expand All @@ -23,6 +24,8 @@ import {Donut} from '../examples/pie/Donut';
import {LineAndBarXCombinedChart} from '../examples/combined/LineAndBarX';
import {LineWithMarkers} from '../examples/line/LineWithMarkers';
import {StackedArea} from '../examples/area/StackedArea';
import {PercentStackingBars} from '../examples/bar-y/PercentStacking';
import {PercentStackingArea} from '../examples/area/PercentStacking';

const ShowcaseStory = () => {
const [loading, setLoading] = React.useState(true);
Expand Down Expand Up @@ -71,6 +74,10 @@ const ShowcaseStory = () => {
<Text variant="subheader-1">Stacked area</Text>
<StackedArea />
</Col>
<Col s={12} m={6}>
<Text variant="subheader-1">Stacked percentage areas</Text>
<PercentStackingArea />
</Col>
</Row>
<Row space={1}>
<Text variant="header-2">Bar-x charts</Text>
Expand All @@ -85,9 +92,13 @@ const ShowcaseStory = () => {
<GroupedColumns />
</Col>
<Col s={12} m={6}>
<Text variant="subheader-1">Stacked columns</Text>
<Text variant="subheader-1">Stacked columns(normal)</Text>
<StackedColumns />
</Col>
<Col s={12} m={6}>
<Text variant="subheader-1">Stacked percentage column</Text>
<PercentStackColumns />
</Col>
<Col s={12} m={6}>
<Text variant="subheader-1">Bar-x chart with data labels</Text>
<BarXDataLabels />
Expand All @@ -105,10 +116,14 @@ const ShowcaseStory = () => {
<Text variant="subheader-1">Grouped bars</Text>
<GroupedColumnsBarY />
</Col>
<Col s={12} m={12}>
<Col s={12} m={6}>
<Text variant="subheader-1">Stacked bars</Text>
<StackedColumnsBarY />
</Col>
<Col s={12} m={6}>
<Text variant="subheader-1">Stacked percentage bars</Text>
<PercentStackingBars />
</Col>
</Row>
<Row space={1}>
<Text variant="header-2">Pie charts</Text>
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/d3/__stories__/area/Basic.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {settings} from '../../../../libs';
import {D3Plugin} from '../..';
import {Basic} from '../../examples/area/Basic';
import {StackedArea} from '../../examples/area/StackedArea';
import {PercentStackingArea} from '../../examples/area/PercentStacking';

const ChartStory = ({Chart}: {Chart: React.FC}) => {
const [shown, setShown] = React.useState(false);
Expand Down Expand Up @@ -41,6 +42,13 @@ export const StackedAreaChartStory: StoryObj<typeof ChartStory> = {
},
};

export const PercentStackingAreaChartStory: StoryObj<typeof ChartStory> = {
name: 'Stacked percentage areas',
args: {
Chart: PercentStackingArea,
},
};

export default {
title: 'Plugins/D3/Area',
decorators: [withKnobs],
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/d3/__stories__/bar-x/BarX.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '../../examples/bar-x/Basic';
import {GroupedColumns} from '../../examples/bar-x/GroupedColumns';
import {StackedColumns} from '../../examples/bar-x/StackedColumns';
import {PercentStackColumns} from '../../examples/bar-x/PercentStack';

const ChartStory = ({Chart}: {Chart: React.FC}) => {
const [shown, setShown] = React.useState(false);
Expand Down Expand Up @@ -67,6 +68,13 @@ export const StackedBarXChartStory: StoryObj<typeof ChartStory> = {
},
};

export const PercentStackBarXChartStory: StoryObj<typeof ChartStory> = {
name: 'Stacked percentage columns',
args: {
Chart: PercentStackColumns,
},
};

export default {
title: 'Plugins/D3/Bar-X',
decorators: [withKnobs],
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/d3/__stories__/bar-y/BarY.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {D3Plugin} from '../..';
import {Basic} from '../../examples/bar-y/Basic';
import {GroupedColumns} from '../../examples/bar-y/GroupedColumns';
import {StackedColumns} from '../../examples/bar-y/StackedColumns';
import {PercentStackingBars} from '../../examples/bar-y/PercentStacking';

const ChartStory = ({Chart}: {Chart: React.FC}) => {
const [shown, setShown] = React.useState(false);
Expand Down Expand Up @@ -48,6 +49,13 @@ export const StackedBarYChartStory: StoryObj<typeof ChartStory> = {
},
};

export const PercentStackingBarYChartStory: StoryObj<typeof ChartStory> = {
name: 'Stacked percentage bars',
args: {
Chart: PercentStackingBars,
},
};

export default {
title: 'Plugins/D3/Bar-Y',
component: ChartStory,
Expand Down
69 changes: 69 additions & 0 deletions src/plugins/d3/examples/area/PercentStacking.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {groups} from 'd3';
import React from 'react';
import {ChartKit} from '../../../../components/ChartKit';
import type {ChartKitWidgetData, AreaSeries, AreaSeriesData} from '../../../../types';
import {ExampleWrapper} from '../ExampleWrapper';
import nintendoGames from '../nintendoGames';

const years = Array.from(
new Set(
nintendoGames.map((d) =>
d.date ? String(new Date(d.date as number).getFullYear()) : 'unknown',
),
),
).sort();

function prepareData() {
const grouped = groups(
nintendoGames,
(d) => d.platform,
(d) => (d.date ? String(new Date(d.date as number).getFullYear()) : 'unknown'),
);
const series = grouped.map(([platform, gamesByYear]) => {
const platformGames = Object.fromEntries(gamesByYear) || {};
return {
name: platform,
data: years.reduce<AreaSeriesData[]>((acc, year) => {
if (year in platformGames) {
acc.push({
x: year,
y: platformGames[year].length,
});
}

return acc;
}, []),
};
});

return {series};
}

export const PercentStackingArea = () => {
const {series} = prepareData();

const data = series.map((s) => {
return {
type: 'area',
stacking: 'percent',
name: s.name,
data: s.data,
} as AreaSeries;
});

const widgetData: ChartKitWidgetData = {
series: {
data: data,
},
xAxis: {
type: 'category',
categories: years,
},
};

return (
<ExampleWrapper>
<ChartKit type="d3" data={widgetData} />
</ExampleWrapper>
);
};
61 changes: 61 additions & 0 deletions src/plugins/d3/examples/bar-x/PercentStack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import {groups} from 'd3';
import {ChartKit} from '../../../../components/ChartKit';
import type {BarXSeries, ChartKitWidgetData} from '../../../../types';
import {ExampleWrapper} from '../ExampleWrapper';
import nintendoGames from '../nintendoGames';

function prepareData() {
const grouped = groups(
nintendoGames,
(d) => d.platform,
(d) => (d.date ? new Date(d.date as number).getFullYear() : 'unknown'),
);
const categories: string[] = [];
const series = grouped.map(([platform, years]) => {
return {
name: platform,
data: years.map(([year, list]) => {
categories.push(String(year));

return {
x: String(year),
y: list.length,
};
}),
};
});

return {categories, series};
}

export const PercentStackColumns = () => {
const {series, categories} = prepareData();
const data = series.map((s) => {
return {
type: 'bar-x',
stacking: 'percent',
name: s.name,
data: s.data,
} as BarXSeries;
});

const widgetData: ChartKitWidgetData = {
series: {
data: data,
},
xAxis: {
type: 'category',
categories: categories.sort(),
title: {
text: 'Release year',
},
},
};

return (
<ExampleWrapper>
<ChartKit type="d3" data={widgetData} />
</ExampleWrapper>
);
};
63 changes: 63 additions & 0 deletions src/plugins/d3/examples/bar-y/PercentStacking.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import {groups} from 'd3';
import {ChartKit} from '../../../../components/ChartKit';
import type {BarYSeries, ChartKitWidgetData} from '../../../../types';
import {ExampleWrapper} from '../ExampleWrapper';
import nintendoGames from '../nintendoGames';

function prepareData() {
const grouped = groups(
nintendoGames,
(d) => d.platform,
(d) => (d.date ? new Date(d.date as number).getFullYear() : 'unknown'),
);
const categories: string[] = [];
const series = grouped.map(([platform, years]) => {
return {
name: platform,
data: years.map(([year, list]) => {
categories.push(String(year));

return {
y: String(year),
x: list.length,
};
}),
};
});

return {categories, series};
}

export const PercentStackingBars = () => {
const {series, categories} = prepareData();
const data = series.map((s) => {
return {
type: 'bar-y',
stacking: 'percent',
name: s.name,
data: s.data,
} as BarYSeries;
});

const widgetData: ChartKitWidgetData = {
series: {
data: data,
},
yAxis: [
{
type: 'category',
categories: categories.sort(),
title: {
text: 'Release year',
},
},
],
};

return (
<ExampleWrapper>
<ChartKit type="d3" data={widgetData} />
</ExampleWrapper>
);
};
2 changes: 2 additions & 0 deletions src/plugins/d3/renderer/hooks/useSeries/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export type PreparedBarXSeries = {
type: BarXSeries['type'];
data: BarXSeriesData[];
stackId: string;
stacking: BarXSeries['stacking'];
dataLabels: {
enabled: boolean;
inside: boolean;
Expand All @@ -105,6 +106,7 @@ export type PreparedBarYSeries = {
type: BarYSeries['type'];
data: BarYSeriesData[];
stackId: string;
stacking: BarYSeries['stacking'];
dataLabels: {
enabled: boolean;
inside: boolean;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/d3/renderer/hooks/useSeries/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function getSeriesStackId(series: StackedSeries) {
let stackId = series.stackId;

if (!stackId) {
stackId = series.stacking === 'normal' ? getCommonStackId() : getRandomCKId();
stackId = series.stacking ? getCommonStackId() : getRandomCKId();
}

return stackId;
Expand Down
Loading
Loading