Skip to content

Commit

Permalink
[FEATURE][SC-42061] Add scatter chart (#182)
Browse files Browse the repository at this point in the history
* feat(Chart): Add scatter type

---------

Co-authored-by: Kevin Fabre <[email protected]>
  • Loading branch information
AnthoPepin and KevinFabre-ods authored Sep 19, 2023
1 parent f046cdd commit ec7f616
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { COLORS } from '../../utils';
import ChartTemplate from '../ChartTemplate';

const meta: Meta = {
component: ChartTemplate,
title: 'Chart/AxisAssemblages',
};

export default meta;

export const AreaChartStacked = ChartTemplate.bind({});
const AreaChartStackedArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -63,9 +63,8 @@ const AreaChartStackedArgs: Props<DataFrame, ChartOptions> = {
},
},
};
AreaChartStacked.args = AreaChartStackedArgs;
export const AreaChartStacked = {args: AreaChartStackedArgs};

export const AreaChartPercentage = ChartTemplate.bind({});
const AreaChartPercentageArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -117,9 +116,8 @@ const AreaChartPercentageArgs: Props<DataFrame, ChartOptions> = {
},
},
};
AreaChartPercentage.args = AreaChartPercentageArgs;
export const AreaChartPercentage = {args: AreaChartPercentageArgs};

export const LineChartStacked = ChartTemplate.bind({});
const LineChartStackedArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -173,9 +171,8 @@ const LineChartStackedArgs: Props<DataFrame, ChartOptions> = {
},
},
};
LineChartStacked.args = LineChartStackedArgs;
export const LineChartStacked = {args: LineChartStackedArgs};

export const LineChartPercentage = ChartTemplate.bind({});
const LineChartPercentageArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -229,9 +226,8 @@ const LineChartPercentageArgs: Props<DataFrame, ChartOptions> = {
},
},
};
LineChartPercentage.args = LineChartPercentageArgs;
export const LineChartPercentage = {args: LineChartPercentageArgs};

export const BarChartStacked = ChartTemplate.bind({});
const BarChartStackedArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -301,9 +297,8 @@ const BarChartStackedArgs: Props<DataFrame, ChartOptions> = {
},
},
};
BarChartStacked.args = BarChartStackedArgs;
export const BarChartStacked = {args: BarChartStackedArgs};

export const BarChartPercentage = ChartTemplate.bind({});
const BarChartPercentageArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -373,9 +368,8 @@ const BarChartPercentageArgs: Props<DataFrame, ChartOptions> = {
},
},
};
BarChartPercentage.args = BarChartPercentageArgs;
export const BarChartPercentage = {args: BarChartPercentageArgs};

export const BarChartStackedGroups = ChartTemplate.bind({});
const BarChartStackedGroupsArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -471,9 +465,8 @@ const BarChartStackedGroupsArgs: Props<DataFrame, ChartOptions> = {
},
},
};
BarChartStackedGroups.args = BarChartStackedGroupsArgs;
export const BarChartStackedGroups = {args: BarChartStackedGroupsArgs};

export const ColumnChartStacked = ChartTemplate.bind({});
const ColumnChartStackedArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -542,9 +535,8 @@ const ColumnChartStackedArgs: Props<DataFrame, ChartOptions> = {
},
},
};
ColumnChartStacked.args = ColumnChartStackedArgs;
export const ColumnChartStacked = {args: ColumnChartStackedArgs};

export const ColumnChartPercentage = ChartTemplate.bind({});
const ColumnChartPercentageArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -613,10 +605,8 @@ const ColumnChartPercentageArgs: Props<DataFrame, ChartOptions> = {
},
},
};
ColumnChartPercentage.args = ColumnChartPercentageArgs;
export const ColumnChartPercentage = {args: ColumnChartPercentageArgs};


export const ColumnChartStackedGroups = ChartTemplate.bind({});
const ColumnChartStackedGroupsArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
Expand Down Expand Up @@ -709,4 +699,115 @@ const ColumnChartStackedGroupsArgs: Props<DataFrame, ChartOptions> = {
},
},
};
ColumnChartStackedGroups.args = ColumnChartStackedGroupsArgs;
export const ColumnChartStackedGroups = {args: ColumnChartStackedGroupsArgs};

const ScatterPlotChartArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
value: [
{label: 'id-0', x: -10, y: 20},
{label: 'id-1', x: 20, y: -10},
{label: 'id-2', x: 5, y: 2},
{label: 'id-3', x: 7, y: 3}
],
},
options: {
labelColumn: 'label',
series: [
{
type: ChartSeriesType.Scatter,
label: "Serie 1",
valueColumn:"x",
indexAxis:"y",
backgroundColor: COLORS.blue,
},
],
axis: {
x: {
display: true,
type: 'linear',
title: {
display: true,
text: "Horizontal axis"
},
},
y: {
display: true,
title: {
display: true,
text: "Vertical axis"
},
type: 'linear',
},
},
title: {
text: 'Scatterplot Chart',
},
},
};
export const ScatterplotChart = {args: ScatterPlotChartArgs};

function randomNormal(mean = 0, stdDev = 1) {
let u1 = 0;
let u2 = 0;
while (u1 === 0) u1 = Math.random();
while (u2 === 0) u2 = Math.random();
const z0 = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2);
return z0 * stdDev + mean;
}

function generateNormalDistribution(n: number, xMean = 0, xStdDev = 1, yMean = 0, yStdDev = 1) {
const points = [];
for (let i = 0; i < n; i++) {
points.push({
label: `id-${i}`,
x: randomNormal(xMean, xStdDev),
y: randomNormal(yMean, yStdDev),
});
}
return points;
}

const ScatterplotNormalDistribChartArgs: Props<DataFrame, ChartOptions> = {
data: {
loading: false,
value: generateNormalDistribution(1000, 5, 2, 5, 2),
},
options: {
labelColumn: 'label',
series: [
{
label: "Serie 1",
type: ChartSeriesType.Scatter,
valueColumn:"x",
indexAxis:"y",
backgroundColor: COLORS.blue,
},
],
axis: {
x: {
display: true,
title: {
display: true,
text: "Horizontal axis"
},
beginAtZero: true
},
y: {
display: true,
title: {
display: true,
text: "Vertical axis"
},
beginAtZero: true
},
},
title: {
text: 'Scatterplot Chart - Normal distribution',
},
},
};
export const ScatterplotNormalDistribChart = {
args: ScatterplotNormalDistribChartArgs,
parameters: {chromatic: { disableSnapshot: true }}
};
7 changes: 7 additions & 0 deletions packages/visualizations/src/components/Chart/Chart.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@
// charts, the label is not the series legend, it's the category.
return `${dataFrame[dataIndex].x}: ${format(parsed)}`;
}
if (seriesType === ChartSeriesType.Scatter) {
const formattedValues = `${format(parsed.x)}, ${format(parsed.y)}`;
// e.g. dataset 1: (4.5, 54)
if (prefix) return `${prefix}(${formattedValues})`;
// 4.5, 54
return formattedValues;
}
}
return prefix + formattedValue + suffix;
Expand Down
13 changes: 13 additions & 0 deletions packages/visualizations/src/components/Chart/datasets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,18 @@ export default function toDataset(df: DataFrame, s: ChartSeries): ChartDataset {
};
}

if (s.type === 'scatter') {
return {
type: 'scatter',
label: defaultValue(s.label, ''),
data: df.map((entry) => ({ x: entry[s.indexAxis], y: entry[s.valueColumn] })),
datalabels: chartJsDataLabels(s.dataLabels),
backgroundColor: singleChartJsColor(s.backgroundColor),
pointRadius: defaultValue(s.pointRadius, 5),
pointHitRadius: defaultValue(s.pointHitRadius, 5),
pointHoverRadius: defaultValue(s.pointHoverRadius, 5),
pointBorderColor: defaultValue(s.pointBorderColor, 'rgba(255,255,255, 0)'),
};
}
throw new Error('Unknown chart type');
}
6 changes: 6 additions & 0 deletions packages/visualizations/src/components/Chart/scales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ export default function buildScales(options: ChartOptions): ChartJsChartOptions[
// X Axis
if (options.axis?.x) {
scales.x = {
...(options.axis.x.type === 'linear' && {
beginAtZero: defaultValue(options?.axis?.x?.beginAtZero, true),
}),
stacked: options.axis?.assemblage?.stacked,
max:
options?.axis?.x?.type === 'linear' && options.axis?.assemblage?.percentaged
Expand Down Expand Up @@ -130,6 +133,9 @@ export default function buildScales(options: ChartOptions): ChartJsChartOptions[
// Y Axis
if (options.axis?.y) {
scales.y = {
...(options.axis.y.type === 'linear' && {
beginAtZero: defaultValue(options?.axis?.y?.beginAtZero, true),
}),
stacked: options.axis?.assemblage?.stacked,
max:
options?.axis?.y?.type === 'linear' && options.axis?.assemblage?.percentaged
Expand Down
30 changes: 27 additions & 3 deletions packages/visualizations/src/components/Chart/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,19 @@ export interface CategoryCartesianAxisConfiguration extends BaseCartesianAxisCon
type?: 'category';
}

export interface NumericCartesianAxisConfiguration extends BaseCartesianAxisConfiguration {
type: 'linear' | 'logarithmic';
export interface LinearCartesianAxisConfiguration extends BaseCartesianAxisConfiguration {
type: 'linear';
beginAtZero?: boolean;
}

export interface LogarithmicCartesianAxisConfiguration extends BaseCartesianAxisConfiguration {
type: 'logarithmic';
}

export type NumericCartesianAxisConfiguration =
| LinearCartesianAxisConfiguration
| LogarithmicCartesianAxisConfiguration;

export interface AxisTitleConfiguration {
display?: boolean;
align?: 'start' | 'center' | 'end';
Expand Down Expand Up @@ -138,14 +147,15 @@ export interface DataLabelsConfiguration {
padding?: number;
}

export type ChartSeries = Line | Bar | Pie | Radar | Doughnut;
export type ChartSeries = Line | Bar | Pie | Radar | Doughnut | Scatter;

export enum ChartSeriesType {
Line = 'line',
Bar = 'bar',
Pie = 'pie',
Radar = 'radar',
Doughnut = 'doughnut',
Scatter = 'scatter',
}

export interface Line {
Expand Down Expand Up @@ -209,6 +219,20 @@ export interface Doughnut {
indexAxis?: 'x' | 'y';
}

export interface Scatter {
type: ChartSeriesType.Scatter;
valueColumn: string;
label?: string;
indexAxis: string;
/** Point color */
backgroundColor?: Color | Color[];
pointRadius?: number;
pointHitRadius?: number;
pointHoverRadius?: number;
pointBorderColor?: string;
dataLabels?: DataLabelsConfiguration;
}

export type FillMode = false | number | string | { value: number };

export interface FillConfiguration {
Expand Down

0 comments on commit ec7f616

Please sign in to comment.