Skip to content

Commit 01ec4e2

Browse files
committed
violin plots
1 parent 59bfd3f commit 01ec4e2

File tree

10 files changed

+198
-376
lines changed

10 files changed

+198
-376
lines changed

samples/violin.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969

7070
document.getElementById('randomizeData').addEventListener('click', function () {
7171
boxplotData.datasets.forEach(function (dataset) {
72-
dataset.data = samples.boxplots({ count: 7 });
72+
dataset.data = samples.boxplotsArray({ count: 7, random: random });
7373
});
7474
window.myBar.update();
7575
});

samples/violinSingle.html

Lines changed: 0 additions & 121 deletions
This file was deleted.

src/animation.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ const interpolators = {
33
if (from === to) {
44
return to;
55
}
6+
if (from == null) {
7+
return to;
8+
}
9+
if (to == null) {
10+
return from;
11+
}
612
return from + (to - from) * factor;
713
},
814
};
@@ -12,7 +18,17 @@ export function interpolateNumberArray(from, to, factor) {
1218
return interpolators.number(from, to, factor);
1319
}
1420
if (Array.isArray(from) && Array.isArray(to)) {
15-
return from.map((f, i) => interpolators.number(f, to[i], factor));
21+
return to.map((t, i) => interpolators.number(from[i], t, factor));
22+
}
23+
return to;
24+
}
25+
26+
export function interpolateKdeCoords(from, to, factor) {
27+
if (Array.isArray(from) && Array.isArray(to)) {
28+
return to.map((t, i) => ({
29+
v: interpolators.number(from[i] ? from[i].v : null, t.v, factor),
30+
estimate: interpolators.number(from[i] ? from[i].estimate : null, t.estimate, factor),
31+
}));
1632
}
1733
return to;
1834
}

src/bundle.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
export * from '.';
22

3-
import { BoxPlot, HorizontalBoxPlot } from './controllers';
3+
import { BoxPlot, HorizontalBoxPlot, Violin, HorizontalViolin } from './controllers';
44

55
BoxPlot.register();
66
HorizontalBoxPlot.register();
7+
Violin.register();
8+
HorizontalViolin.register();

src/controllers/base.js

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,42 @@
11
import { interpolateNumberArray } from '../animation';
22
import { outlierPositioner, patchInHoveredOutlier } from '../tooltip';
33
import { controllers } from 'chart.js';
4+
import { defaultStatsOptions } from '../data';
45

56
export function baseDefaults(keys) {
67
const colorKeys = ['borderColor', 'backgroundColor'].concat(keys.filter((c) => c.endsWith('Color')));
78
return {
8-
datasets: {
9-
animation: {
10-
numberArray: {
11-
fn: interpolateNumberArray,
12-
properties: ['outliers', 'items'],
13-
},
14-
colors: {
15-
type: 'color',
16-
properties: colorKeys,
17-
},
18-
show: {
19-
colors: {
20-
type: 'color',
21-
properties: colorKeys,
22-
from: 'transparent',
9+
datasets: Object.assign(
10+
{
11+
animation: {
12+
numberArray: {
13+
fn: interpolateNumberArray,
14+
properties: ['outliers', 'items'],
2315
},
24-
},
25-
hide: {
2616
colors: {
2717
type: 'color',
2818
properties: colorKeys,
29-
to: 'transparent',
19+
},
20+
show: {
21+
colors: {
22+
type: 'color',
23+
properties: colorKeys,
24+
from: 'transparent',
25+
},
26+
},
27+
hide: {
28+
colors: {
29+
type: 'color',
30+
properties: colorKeys,
31+
to: 'transparent',
32+
},
3033
},
3134
},
35+
minStats: 'min',
36+
maxStats: 'max',
3237
},
33-
minStats: 'min',
34-
maxStats: 'max',
35-
},
38+
defaultStatsOptions
39+
),
3640
tooltips: {
3741
position: outlierPositioner.register().id,
3842
callbacks: {
@@ -96,7 +100,7 @@ export class StatsBase extends controllers.bar {
96100
raw: parsed,
97101
hoveredOutlierIndex: -1,
98102
};
99-
this._transformStats(r.value, parsed, (v) => vScale.getLabelForValue(v));
103+
this._transformStats(r.value, parsed, (v) => vScale.getLabelForValue(v), 'string');
100104
const s = this._toStringStats(r.value);
101105
r.value.toString = function () {
102106
// custom to string function for the 'value'
@@ -113,7 +117,7 @@ export class StatsBase extends controllers.bar {
113117
return '';
114118
}
115119

116-
_transformStats(_target, _source, _mapper) {
120+
_transformStats(_target, _source, _mapper, _mode) {
117121
// abstract
118122
}
119123

@@ -123,7 +127,7 @@ export class StatsBase extends controllers.bar {
123127
const parsed = this.getParsed(index);
124128
const base = scale.getBasePixel();
125129
properties._datasetIndex = this.index;
126-
this._transformStats(properties, parsed, (v) => (reset ? base : scale.getPixelForValue(v)));
130+
this._transformStats(properties, parsed, (v) => (reset ? base : scale.getPixelForValue(v)), mode);
127131
super.updateElement(rectangle, index, properties, mode);
128132
}
129133
}

src/controllers/boxplot.js

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { asBoxPlotStats, defaultStatsOptions } from '../data';
1+
import { asBoxPlotStats } from '../data';
22
import { controllers, helpers, defaults } from 'chart.js';
33
import { baseDefaults, StatsBase } from './base';
44
import { BoxAndWiskers, boxOptionsKeys } from '../elements';
@@ -35,20 +35,17 @@ BoxPlot.register = () => {
3535
defaults.bar,
3636
baseDefaults(boxOptionsKeys),
3737
{
38-
datasets: Object.assign(
39-
{
40-
animation: {
41-
numbers: {
42-
type: 'number',
43-
properties: defaults.bar.datasets.animation.numbers.properties.concat(
44-
['q1', 'q3', 'min', 'max', 'median', 'whiskerMin', 'whiskerMax'],
45-
boxOptionsKeys.filter((c) => !c.endsWith('Color'))
46-
),
47-
},
38+
datasets: {
39+
animation: {
40+
numbers: {
41+
type: 'number',
42+
properties: defaults.bar.datasets.animation.numbers.properties.concat(
43+
['q1', 'q3', 'min', 'max', 'median', 'whiskerMin', 'whiskerMax'],
44+
boxOptionsKeys.filter((c) => !c.endsWith('Color'))
45+
),
4846
},
4947
},
50-
defaultStatsOptions
51-
),
48+
},
5249
},
5350
])
5451
);
@@ -78,20 +75,17 @@ HorizontalBoxPlot.register = () => {
7875
defaults.horizontalBar,
7976
baseDefaults(boxOptionsKeys),
8077
{
81-
datasets: Object.assign(
82-
{
83-
animation: {
84-
numbers: {
85-
type: 'number',
86-
properties: defaults.bar.datasets.animation.numbers.properties.concat(
87-
['q1', 'q3', 'min', 'max', 'median', 'whiskerMin', 'whiskerMax'],
88-
boxOptionsKeys.filter((c) => !c.endsWith('Color'))
89-
),
90-
},
78+
datasets: {
79+
animation: {
80+
numbers: {
81+
type: 'number',
82+
properties: defaults.bar.datasets.animation.numbers.properties.concat(
83+
['q1', 'q3', 'min', 'max', 'median', 'whiskerMin', 'whiskerMax'],
84+
boxOptionsKeys.filter((c) => !c.endsWith('Color'))
85+
),
9186
},
9287
},
93-
defaultStatsOptions
94-
),
88+
},
9589
},
9690
])
9791
);

src/controllers/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './boxplot';
2-
// export * from './violin';
2+
export * from './violin';

0 commit comments

Comments
 (0)