Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@sgratzl/chartjs-chart-boxplot

Package Overview
Dependencies
Maintainers
1
Versions
52
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sgratzl/chartjs-chart-boxplot - npm Package Compare versions

Comparing version 3.0.0-rc.0 to 3.0.0-rc.1

src/controllers/StatsBase.ts

69

build/index.cjs.js

@@ -38,3 +38,3 @@ /**

const m = mean(x);
return x.reduce((acc, x) => acc + (x - m) * (x - m), 0) / (x.length - 1);
return x.reduce((acc, xi) => acc + (xi - m) * (xi - m), 0) / (x.length - 1);
}

@@ -60,3 +60,3 @@ function nrd(sample, quantiles) {

if (Array.isArray(arr)) {
for (let i = 0; i < arr.length; i++) {
for (let i = 0; i < arr.length; i += 1) {
const v = arr[i];

@@ -68,3 +68,3 @@ if (v >= whiskerMin) {

}
for (let i = arr.length - 1; i >= 0; i--) {
for (let i = arr.length - 1; i >= 0; i -= 1) {
const v = arr[i];

@@ -227,3 +227,3 @@ if (v <= whiskerMax) {

const props = this.getProps(['x', 'y', 'items', 'width', 'height', 'outliers']);
const options = this.options;
const { options } = this;
if (options.itemRadius <= 0 || !props.items || props.items.length <= 0) {

@@ -262,3 +262,3 @@ return;

const props = this.getProps(['x', 'y', 'outliers']);
const options = this.options;
const { options } = this;
if (options.outlierRadius <= 0 || !props.outliers || props.outliers.length === 0) {

@@ -291,3 +291,3 @@ return;

const props = this.getProps(['x', 'y', 'mean']);
const options = this.options;
const { options } = this;
if (options.meanRadius <= 0 || props.mean == null || Number.isNaN(props.mean)) {

@@ -355,3 +355,3 @@ return;

const toCompare = vertical ? mouseY : mouseX;
for (let i = 0; i < outliers.length; i++) {
for (let i = 0; i < outliers.length; i += 1) {
if (Math.abs(outliers[i] - toCompare) <= hitRadius) {

@@ -429,6 +429,6 @@ return i;

_drawBoxPlotVertical(ctx) {
const options = this.options;
const { options } = this;
const props = this.getProps(['x', 'width', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const x0 = x - width / 2;

@@ -483,6 +483,6 @@ if (props.q3 > props.q1) {

_drawBoxPlotHorizontal(ctx) {
const options = this.options;
const { options } = this;
const props = this.getProps(['y', 'height', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const y0 = y - height / 2;

@@ -565,7 +565,9 @@ if (props.q3 > props.q1) {

BoxAndWiskers.id = 'boxandwhiskers';
BoxAndWiskers.defaults = Object.assign({}, chart_js.BarElement.defaults, baseDefaults$1, {
BoxAndWiskers.defaults = {
...chart_js.BarElement.defaults,
...baseDefaults$1,
medianColor: 'transparent',
lowerBackgroundColor: 'transparent',
});
BoxAndWiskers.defaultRoutes = Object.assign({}, chart_js.BarElement.defaultRoutes, baseRoutes);
};
BoxAndWiskers.defaultRoutes = { ...chart_js.BarElement.defaultRoutes, ...baseRoutes };

@@ -595,4 +597,4 @@ class Violin extends StatsBase$1 {

if (this.isVertical()) {
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const factor = width / 2 / props.maxEstimate;

@@ -611,4 +613,4 @@ ctx.moveTo(x, props.min);

else {
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const factor = height / 2 / props.maxEstimate;

@@ -652,4 +654,4 @@ ctx.moveTo(props.min, y);

Violin.id = 'violin';
Violin.defaults = Object.assign({}, chart_js.BarElement.defaults, baseDefaults$1);
Violin.defaultRoutes = Object.assign({}, chart_js.BarElement.defaultRoutes, baseRoutes);
Violin.defaults = { ...chart_js.BarElement.defaults, ...baseDefaults$1 };
Violin.defaultRoutes = { ...chart_js.BarElement.defaultRoutes, ...baseRoutes };

@@ -703,3 +705,3 @@ const interpolators = {

let count = 0;
for (let i = 0; i < items.length; ++i) {
for (let i = 0; i < items.length; i += 1) {
const el = items[i].element;

@@ -710,3 +712,3 @@ if (el && el.hasValue()) {

y += pos.y;
++count;
count += 1;
}

@@ -727,3 +729,3 @@ }

const colorKeys = ['borderColor', 'backgroundColor'].concat(keys.filter((c) => c.endsWith('Color')));
return Object.assign({
return {
animations: {

@@ -761,3 +763,4 @@ numberArray: {

maxStats: 'max',
}, defaultStatsOptions);
...defaultStatsOptions,
};
}

@@ -794,5 +797,5 @@ function defaultOverrides() {

scale.axis = config.minStats;
const min = super.getMinMax(scale, canStack).min;
const { min } = super.getMinMax(scale, canStack);
scale.axis = config.maxStats;
const max = super.getMinMax(scale, canStack).max;
const { max } = super.getMinMax(scale, canStack);
scale.axis = bak;

@@ -806,3 +809,3 @@ return { min, max };

const r = [];
for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i += 1) {
const index = i + start;

@@ -828,3 +831,3 @@ const parsed = {};

const r = super.getLabelAndValue(index);
const vScale = this._cachedMeta.vScale;
const { vScale } = this._cachedMeta;
const parsed = this.getParsed(index);

@@ -840,3 +843,3 @@ if (!vScale || !parsed || r.value === 'NaN') {

const s = this._toStringStats(r.value);
r.value.toString = function () {
r.value.toString = function toString() {
if (this.hoveredOutlierIndex >= 0) {

@@ -850,3 +853,3 @@ return `(outlier: ${this.outliers[this.hoveredOutlierIndex]})`;

_toStringStats(b) {
const f = (v) => (v == null ? 'NaN' : v.toLocaleString());
const f = (v) => (v == null ? 'NaN' : helpers.formatNumber(v, this.chart.options.locale, {}));
return `(min: ${f(b.min)}, 25% quantile: ${f(b.q1)}, median: ${f(b.median)}, mean: ${f(b.mean)}, 75% quantile: ${f(b.q3)}, max: ${f(b.max)})`;

@@ -926,3 +929,3 @@ }

if (Array.isArray(source.coords)) {
target.coords = source.coords.map((c) => Object.assign({}, c, { v: mapper(c.v) }));
target.coords = source.coords.map((c) => ({ ...c, v: mapper(c.v) }));
}

@@ -929,0 +932,0 @@ }

@@ -1,3 +0,294 @@

export * from './elements';
export * from './controllers';
//# sourceMappingURL=index.d.ts.map
/**
* @sgratzl/chartjs-chart-boxplot
* https://github.com/sgratzl/chartjs-chart-boxplot
*
* Copyright (c) 2021 Samuel Gratzl <sam@sgratzl.com>
*/
import { TooltipModel, Element, BarController, Scale, ChartMeta, UpdateMode, ControllerDatasetOptions, ScriptableAndArrayOptions, CommonHoverOptions, CartesianScaleTypeRegistry, Chart, ChartItem, ChartConfiguration } from 'chart.js';
interface ExtendedTooltip extends TooltipModel<'boxplot' | 'violin'> {
_tooltipOutlier?: {
index: number;
datasetIndex: number;
};
}
interface IStatsBaseOptions {
backgroundColor: string;
borderColor: string;
borderWidth: number;
outlierStyle: 'circle' | 'triangle' | 'rect' | 'rectRounded' | 'rectRot' | 'cross' | 'crossRot' | 'star' | 'line' | 'dash';
outlierRadius: number;
outlierBackgroundColor: string;
outlierBorderColor: string;
outlierBorderWidth: number;
itemStyle: 'circle' | 'triangle' | 'rect' | 'rectRounded' | 'rectRot' | 'cross' | 'crossRot' | 'star' | 'line' | 'dash';
itemRadius: number;
itemBackgroundColor: string;
itemBorderColor: string;
itemBorderWidth: number;
hitPadding: number;
outlierHitRadius: number;
meanStyle: 'circle' | 'triangle' | 'rect' | 'rectRounded' | 'rectRot' | 'cross' | 'crossRot' | 'star' | 'line' | 'dash';
meanRadius: number;
meanBackgroundColor: string;
meanBorderColor: string;
meanBorderWidth: number;
}
interface IStatsBaseProps {
x: number;
y: number;
width: number;
height: number;
items: number[];
outliers: number[];
mean: number;
}
declare class StatsBase$1<T extends IStatsBaseProps, O extends IStatsBaseOptions> extends Element<T, O> {
_datasetIndex: number;
_index: number;
isVertical(): boolean;
protected _drawItems(ctx: CanvasRenderingContext2D): void;
protected _drawOutliers(ctx: CanvasRenderingContext2D): void;
protected _drawMeanDot(ctx: CanvasRenderingContext2D): void;
_getBounds(_useFinalPosition?: boolean): {
left: number;
top: number;
right: number;
bottom: number;
};
_getHitBounds(useFinalPosition?: boolean): {
left: number;
top: number;
right: number;
bottom: number;
};
inRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): boolean;
inXRange(mouseX: number, useFinalPosition?: boolean): boolean;
inYRange(mouseY: number, useFinalPosition?: boolean): boolean;
protected _outlierIndexInRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): number;
protected _boxInRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): boolean;
getCenterPoint(useFinalPosition?: boolean): {
x: number;
y: number;
};
protected _getOutliers(useFinalPosition?: boolean): number[];
tooltipPosition(eventPosition?: {
x: number;
y: number;
} | boolean, tooltip?: ExtendedTooltip): {
x: number;
y: number;
};
}
interface IBoxAndWhiskersOptions extends IStatsBaseOptions {
medianColor: string;
lowerBackgroundColor: string;
}
interface IBoxAndWhiskerProps extends IStatsBaseProps {
q1: number;
q3: number;
median: number;
whiskerMin: number;
whiskerMax: number;
mean: number;
}
declare class BoxAndWiskers extends StatsBase$1<IBoxAndWhiskerProps, IBoxAndWhiskersOptions> {
draw(ctx: CanvasRenderingContext2D): void;
protected _drawBoxPlot(ctx: CanvasRenderingContext2D): void;
protected _drawBoxPlotVertical(ctx: CanvasRenderingContext2D): void;
protected _drawBoxPlotHorizontal(ctx: CanvasRenderingContext2D): void;
_getBounds(useFinalPosition?: boolean): {
left: number;
top: number;
right: number;
bottom: number;
};
static id: string;
static defaults: {
medianColor: string;
lowerBackgroundColor: string;
borderWidth: number;
outlierStyle: string;
outlierRadius: number;
outlierBorderWidth: number;
itemStyle: string;
itemRadius: number;
itemBorderWidth: number;
meanStyle: string;
meanRadius: number;
meanBorderWidth: number;
hitPadding: number;
outlierHitRadius: number;
};
static defaultRoutes: {
outlierBackgroundColor: string;
outlierBorderColor: string;
itemBackgroundColor: string;
itemBorderColor: string;
meanBackgroundColor: string;
meanBorderColor: string;
};
}
interface IBaseStats {
min: number;
max: number;
q1: number;
q3: number;
median: number;
mean: number;
items: readonly number[];
outliers: readonly number[];
}
interface IBoxPlot extends IBaseStats {
whiskerMax: number;
whiskerMin: number;
}
interface IKDEPoint {
v: number;
estimate: number;
}
interface IViolin extends IBaseStats {
maxEstimate: number;
coords: IKDEPoint[];
}
declare type QuantileMethod = 7 | 'quantiles' | 'hinges' | 'fivenum' | 'linear' | 'lower' | 'higher' | 'nearest' | 'midpoint' | ((arr: ArrayLike<number>, length?: number | undefined) => {
q1: number;
median: number;
q3: number;
});
interface IBaseOptions {
minStats?: 'min' | 'q1' | 'whiskerMin';
maxStats?: 'max' | 'q3' | 'whiskerMax';
coef?: number;
quantiles?: QuantileMethod;
}
declare type IBoxplotOptions = IBaseOptions;
interface IViolinOptions extends IBaseOptions {
points: number;
}
declare type IViolinElementOptions = IStatsBaseOptions;
interface IViolinElementProps extends IStatsBaseProps {
min: number;
max: number;
coords: IKDEPoint[];
maxEstimate: number;
}
declare class Violin extends StatsBase$1<IViolinElementProps, IViolinElementOptions> {
draw(ctx: CanvasRenderingContext2D): void;
protected _drawCoords(ctx: CanvasRenderingContext2D, props: IViolinElementProps): void;
_getBounds(useFinalPosition?: boolean): {
left: number;
top: number;
right: number;
bottom: number;
};
static id: string;
static defaults: {
borderWidth: number;
outlierStyle: string;
outlierRadius: number;
outlierBorderWidth: number;
itemStyle: string;
itemRadius: number;
itemBorderWidth: number;
meanStyle: string;
meanRadius: number;
meanBorderWidth: number;
hitPadding: number;
outlierHitRadius: number;
};
static defaultRoutes: {
outlierBackgroundColor: string;
outlierBorderColor: string;
itemBackgroundColor: string;
itemBorderColor: string;
meanBackgroundColor: string;
meanBorderColor: string;
};
}
declare abstract class StatsBase<S extends IBaseStats, C extends Required<IBaseOptions>> extends BarController {
options: C;
protected _transformStats<T>(target: any, source: S, mapper: (v: number) => T): void;
getMinMax(scale: Scale, canStack?: boolean | undefined): {
min: number;
max: number;
};
parsePrimitiveData(meta: ChartMeta, data: any[], start: number, count: number): Record<string, unknown>[];
parseArrayData(meta: ChartMeta, data: any[], start: number, count: number): Record<string, unknown>[];
parseObjectData(meta: ChartMeta, data: any[], start: number, count: number): Record<string, unknown>[];
protected abstract _parseStats(value: any, options: C): S | undefined;
getLabelAndValue(index: number): {
label: string;
value: string & {
raw: S;
hoveredOutlierIndex: number;
} & S;
};
protected _toStringStats(b: S): string;
updateElement(rectangle: Element, index: number, properties: any, mode: UpdateMode): void;
}
declare class BoxPlotController extends StatsBase<IBoxPlot, Required<IBoxplotOptions>> {
protected _parseStats(value: unknown, config: IBoxplotOptions): IBoxPlot | undefined;
protected _transformStats<T>(target: any, source: IBoxPlot, mapper: (v: number) => T): void;
static readonly id = "boxplot";
static readonly defaults: any;
static readonly overrides: any;
}
interface BoxPlotControllerDatasetOptions extends ControllerDatasetOptions, IBoxplotOptions, ScriptableAndArrayOptions<IBoxAndWhiskersOptions, 'boxplot'>, ScriptableAndArrayOptions<CommonHoverOptions, 'boxplot'> {
}
declare type BoxPlotDataPoint = number[] | (Partial<IBoxPlot> & IBaseStats);
interface IBoxPlotChartOptions {
}
declare module 'chart.js' {
interface ChartTypeRegistry {
boxplot: {
chartOptions: IBoxPlotChartOptions;
datasetOptions: BoxPlotControllerDatasetOptions;
defaultDataPoint: BoxPlotDataPoint;
scales: keyof CartesianScaleTypeRegistry;
parsedDataType: IBoxPlot & ChartTypeRegistry['bar']['parsedDataType'];
};
}
}
declare class BoxPlotChart<DATA extends unknown[] = BoxPlotDataPoint[], LABEL = string> extends Chart<'boxplot', DATA, LABEL> {
static id: string;
constructor(item: ChartItem, config: Omit<ChartConfiguration<'boxplot', DATA, LABEL>, 'type'>);
}
declare class ViolinController extends StatsBase<IViolin, Required<IViolinOptions>> {
protected _parseStats(value: any, config: IViolinOptions): IViolin | undefined;
protected _transformStats<T>(target: any, source: IViolin, mapper: (v: number) => T): void;
static readonly id = "violin";
static readonly defaults: any;
static readonly overrides: any;
}
declare type ViolinDataPoint = number[] | (Partial<IViolin> & IBaseStats);
interface ViolinControllerDatasetOptions extends ControllerDatasetOptions, IViolinOptions, ScriptableAndArrayOptions<IViolinElementOptions, 'violin'>, ScriptableAndArrayOptions<CommonHoverOptions, 'violin'> {
}
interface IViolinChartOptions {
}
declare module 'chart.js' {
interface ChartTypeRegistry {
violin: {
chartOptions: IViolinChartOptions;
datasetOptions: ViolinControllerDatasetOptions;
defaultDataPoint: ViolinDataPoint;
scales: keyof CartesianScaleTypeRegistry;
parsedDataType: IViolin & ChartTypeRegistry['bar']['parsedDataType'];
};
}
}
declare class ViolinChart<DATA extends unknown[] = ViolinDataPoint[], LABEL = string> extends Chart<'violin', DATA, LABEL> {
static id: string;
constructor(item: ChartItem, config: Omit<ChartConfiguration<'violin', DATA, LABEL>, 'type'>);
}
export { BoxAndWiskers, BoxPlotChart, BoxPlotController, BoxPlotControllerDatasetOptions, BoxPlotDataPoint, IBoxAndWhiskerProps, IBoxAndWhiskersOptions, IBoxPlotChartOptions, IStatsBaseOptions, IStatsBaseProps, IViolinChartOptions, IViolinElementOptions, IViolinElementProps, StatsBase$1 as StatsBase, Violin, ViolinChart, ViolinController, ViolinControllerDatasetOptions, ViolinDataPoint };
//# sourceMappingURL=index.d.ts.map

@@ -9,3 +9,3 @@ /**

import { Element, BarElement, Tooltip, BarController, registry, Chart, LinearScale, CategoryScale } from 'chart.js';
import { drawPoint, merge } from 'chart.js/helpers';
import { drawPoint, formatNumber, merge } from 'chart.js/helpers';
import boxplots, { quantilesType7, quantilesHinges, quantilesFivenum, quantilesLinear, quantilesLower, quantilesHigher, quantilesNearest, quantilesMidpoint } from '@sgratzl/boxplots';

@@ -31,3 +31,3 @@

const m = mean(x);
return x.reduce((acc, x) => acc + (x - m) * (x - m), 0) / (x.length - 1);
return x.reduce((acc, xi) => acc + (xi - m) * (xi - m), 0) / (x.length - 1);
}

@@ -53,3 +53,3 @@ function nrd(sample, quantiles) {

if (Array.isArray(arr)) {
for (let i = 0; i < arr.length; i++) {
for (let i = 0; i < arr.length; i += 1) {
const v = arr[i];

@@ -61,3 +61,3 @@ if (v >= whiskerMin) {

}
for (let i = arr.length - 1; i >= 0; i--) {
for (let i = arr.length - 1; i >= 0; i -= 1) {
const v = arr[i];

@@ -220,3 +220,3 @@ if (v <= whiskerMax) {

const props = this.getProps(['x', 'y', 'items', 'width', 'height', 'outliers']);
const options = this.options;
const { options } = this;
if (options.itemRadius <= 0 || !props.items || props.items.length <= 0) {

@@ -255,3 +255,3 @@ return;

const props = this.getProps(['x', 'y', 'outliers']);
const options = this.options;
const { options } = this;
if (options.outlierRadius <= 0 || !props.outliers || props.outliers.length === 0) {

@@ -284,3 +284,3 @@ return;

const props = this.getProps(['x', 'y', 'mean']);
const options = this.options;
const { options } = this;
if (options.meanRadius <= 0 || props.mean == null || Number.isNaN(props.mean)) {

@@ -348,3 +348,3 @@ return;

const toCompare = vertical ? mouseY : mouseX;
for (let i = 0; i < outliers.length; i++) {
for (let i = 0; i < outliers.length; i += 1) {
if (Math.abs(outliers[i] - toCompare) <= hitRadius) {

@@ -422,6 +422,6 @@ return i;

_drawBoxPlotVertical(ctx) {
const options = this.options;
const { options } = this;
const props = this.getProps(['x', 'width', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const x0 = x - width / 2;

@@ -476,6 +476,6 @@ if (props.q3 > props.q1) {

_drawBoxPlotHorizontal(ctx) {
const options = this.options;
const { options } = this;
const props = this.getProps(['y', 'height', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const y0 = y - height / 2;

@@ -558,7 +558,9 @@ if (props.q3 > props.q1) {

BoxAndWiskers.id = 'boxandwhiskers';
BoxAndWiskers.defaults = Object.assign({}, BarElement.defaults, baseDefaults$1, {
BoxAndWiskers.defaults = {
...BarElement.defaults,
...baseDefaults$1,
medianColor: 'transparent',
lowerBackgroundColor: 'transparent',
});
BoxAndWiskers.defaultRoutes = Object.assign({}, BarElement.defaultRoutes, baseRoutes);
};
BoxAndWiskers.defaultRoutes = { ...BarElement.defaultRoutes, ...baseRoutes };

@@ -588,4 +590,4 @@ class Violin extends StatsBase$1 {

if (this.isVertical()) {
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const factor = width / 2 / props.maxEstimate;

@@ -604,4 +606,4 @@ ctx.moveTo(x, props.min);

else {
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const factor = height / 2 / props.maxEstimate;

@@ -645,4 +647,4 @@ ctx.moveTo(props.min, y);

Violin.id = 'violin';
Violin.defaults = Object.assign({}, BarElement.defaults, baseDefaults$1);
Violin.defaultRoutes = Object.assign({}, BarElement.defaultRoutes, baseRoutes);
Violin.defaults = { ...BarElement.defaults, ...baseDefaults$1 };
Violin.defaultRoutes = { ...BarElement.defaultRoutes, ...baseRoutes };

@@ -696,3 +698,3 @@ const interpolators = {

let count = 0;
for (let i = 0; i < items.length; ++i) {
for (let i = 0; i < items.length; i += 1) {
const el = items[i].element;

@@ -703,3 +705,3 @@ if (el && el.hasValue()) {

y += pos.y;
++count;
count += 1;
}

@@ -720,3 +722,3 @@ }

const colorKeys = ['borderColor', 'backgroundColor'].concat(keys.filter((c) => c.endsWith('Color')));
return Object.assign({
return {
animations: {

@@ -754,3 +756,4 @@ numberArray: {

maxStats: 'max',
}, defaultStatsOptions);
...defaultStatsOptions,
};
}

@@ -787,5 +790,5 @@ function defaultOverrides() {

scale.axis = config.minStats;
const min = super.getMinMax(scale, canStack).min;
const { min } = super.getMinMax(scale, canStack);
scale.axis = config.maxStats;
const max = super.getMinMax(scale, canStack).max;
const { max } = super.getMinMax(scale, canStack);
scale.axis = bak;

@@ -799,3 +802,3 @@ return { min, max };

const r = [];
for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i += 1) {
const index = i + start;

@@ -821,3 +824,3 @@ const parsed = {};

const r = super.getLabelAndValue(index);
const vScale = this._cachedMeta.vScale;
const { vScale } = this._cachedMeta;
const parsed = this.getParsed(index);

@@ -833,3 +836,3 @@ if (!vScale || !parsed || r.value === 'NaN') {

const s = this._toStringStats(r.value);
r.value.toString = function () {
r.value.toString = function toString() {
if (this.hoveredOutlierIndex >= 0) {

@@ -843,3 +846,3 @@ return `(outlier: ${this.outliers[this.hoveredOutlierIndex]})`;

_toStringStats(b) {
const f = (v) => (v == null ? 'NaN' : v.toLocaleString());
const f = (v) => (v == null ? 'NaN' : formatNumber(v, this.chart.options.locale, {}));
return `(min: ${f(b.min)}, 25% quantile: ${f(b.q1)}, median: ${f(b.median)}, mean: ${f(b.mean)}, 75% quantile: ${f(b.q3)}, max: ${f(b.max)})`;

@@ -919,3 +922,3 @@ }

if (Array.isArray(source.coords)) {
target.coords = source.coords.map((c) => Object.assign({}, c, { v: mapper(c.v) }));
target.coords = source.coords.map((c) => ({ ...c, v: mapper(c.v) }));
}

@@ -922,0 +925,0 @@ }

@@ -232,3 +232,3 @@ /**

const m = mean(x);
return x.reduce((acc, x) => acc + (x - m) * (x - m), 0) / (x.length - 1);
return x.reduce((acc, xi) => acc + (xi - m) * (xi - m), 0) / (x.length - 1);
}

@@ -254,3 +254,3 @@ function nrd(sample, quantiles) {

if (Array.isArray(arr)) {
for (let i = 0; i < arr.length; i++) {
for (let i = 0; i < arr.length; i += 1) {
const v = arr[i];

@@ -262,3 +262,3 @@ if (v >= whiskerMin) {

}
for (let i = arr.length - 1; i >= 0; i--) {
for (let i = arr.length - 1; i >= 0; i -= 1) {
const v = arr[i];

@@ -438,3 +438,3 @@ if (v <= whiskerMax) {

let count = 0;
for (let i = 0; i < items.length; ++i) {
for (let i = 0; i < items.length; i += 1) {
const el = items[i].element;

@@ -445,3 +445,3 @@ if (el && el.hasValue()) {

y += pos.y;
++count;
count += 1;
}

@@ -462,3 +462,3 @@ }

const colorKeys = ['borderColor', 'backgroundColor'].concat(keys.filter((c) => c.endsWith('Color')));
return Object.assign({
return {
animations: {

@@ -496,3 +496,4 @@ numberArray: {

maxStats: 'max',
}, defaultStatsOptions);
...defaultStatsOptions,
};
}

@@ -529,5 +530,5 @@ function defaultOverrides() {

scale.axis = config.minStats;
const min = super.getMinMax(scale, canStack).min;
const { min } = super.getMinMax(scale, canStack);
scale.axis = config.maxStats;
const max = super.getMinMax(scale, canStack).max;
const { max } = super.getMinMax(scale, canStack);
scale.axis = bak;

@@ -541,3 +542,3 @@ return { min, max };

const r = [];
for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i += 1) {
const index = i + start;

@@ -563,3 +564,3 @@ const parsed = {};

const r = super.getLabelAndValue(index);
const vScale = this._cachedMeta.vScale;
const { vScale } = this._cachedMeta;
const parsed = this.getParsed(index);

@@ -575,3 +576,3 @@ if (!vScale || !parsed || r.value === 'NaN') {

const s = this._toStringStats(r.value);
r.value.toString = function () {
r.value.toString = function toString() {
if (this.hoveredOutlierIndex >= 0) {

@@ -585,3 +586,3 @@ return `(outlier: ${this.outliers[this.hoveredOutlierIndex]})`;

_toStringStats(b) {
const f = (v) => (v == null ? 'NaN' : v.toLocaleString());
const f = (v) => (v == null ? 'NaN' : helpers.formatNumber(v, this.chart.options.locale, {}));
return `(min: ${f(b.min)}, 25% quantile: ${f(b.q1)}, median: ${f(b.median)}, mean: ${f(b.mean)}, 75% quantile: ${f(b.q3)}, max: ${f(b.max)})`;

@@ -631,3 +632,3 @@ }

const props = this.getProps(['x', 'y', 'items', 'width', 'height', 'outliers']);
const options = this.options;
const { options } = this;
if (options.itemRadius <= 0 || !props.items || props.items.length <= 0) {

@@ -666,3 +667,3 @@ return;

const props = this.getProps(['x', 'y', 'outliers']);
const options = this.options;
const { options } = this;
if (options.outlierRadius <= 0 || !props.outliers || props.outliers.length === 0) {

@@ -695,3 +696,3 @@ return;

const props = this.getProps(['x', 'y', 'mean']);
const options = this.options;
const { options } = this;
if (options.meanRadius <= 0 || props.mean == null || Number.isNaN(props.mean)) {

@@ -759,3 +760,3 @@ return;

const toCompare = vertical ? mouseY : mouseX;
for (let i = 0; i < outliers.length; i++) {
for (let i = 0; i < outliers.length; i += 1) {
if (Math.abs(outliers[i] - toCompare) <= hitRadius) {

@@ -833,6 +834,6 @@ return i;

_drawBoxPlotVertical(ctx) {
const options = this.options;
const { options } = this;
const props = this.getProps(['x', 'width', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const x0 = x - width / 2;

@@ -887,6 +888,6 @@ if (props.q3 > props.q1) {

_drawBoxPlotHorizontal(ctx) {
const options = this.options;
const { options } = this;
const props = this.getProps(['y', 'height', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const y0 = y - height / 2;

@@ -969,7 +970,9 @@ if (props.q3 > props.q1) {

BoxAndWiskers.id = 'boxandwhiskers';
BoxAndWiskers.defaults = Object.assign({}, chart_js.BarElement.defaults, baseDefaults, {
BoxAndWiskers.defaults = {
...chart_js.BarElement.defaults,
...baseDefaults,
medianColor: 'transparent',
lowerBackgroundColor: 'transparent',
});
BoxAndWiskers.defaultRoutes = Object.assign({}, chart_js.BarElement.defaultRoutes, baseRoutes);
};
BoxAndWiskers.defaultRoutes = { ...chart_js.BarElement.defaultRoutes, ...baseRoutes };

@@ -999,4 +1002,4 @@ class Violin extends StatsBase {

if (this.isVertical()) {
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const factor = width / 2 / props.maxEstimate;

@@ -1015,4 +1018,4 @@ ctx.moveTo(x, props.min);

else {
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const factor = height / 2 / props.maxEstimate;

@@ -1056,4 +1059,4 @@ ctx.moveTo(props.min, y);

Violin.id = 'violin';
Violin.defaults = Object.assign({}, chart_js.BarElement.defaults, baseDefaults);
Violin.defaultRoutes = Object.assign({}, chart_js.BarElement.defaultRoutes, baseRoutes);
Violin.defaults = { ...chart_js.BarElement.defaults, ...baseDefaults };
Violin.defaultRoutes = { ...chart_js.BarElement.defaultRoutes, ...baseRoutes };

@@ -1120,3 +1123,3 @@ function patchController(type, config, controller, elements = [], scales = []) {

if (Array.isArray(source.coords)) {
target.coords = source.coords.map((c) => Object.assign({}, c, { v: mapper(c.v) }));
target.coords = source.coords.map((c) => ({ ...c, v: mapper(c.v) }));
}

@@ -1123,0 +1126,0 @@ }

@@ -1,2 +0,2 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["exports","chart.js","chart.js/helpers"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ChartBoxPlot={},e.Chart,e.Chart.helpers)}(this,(function(e,t,r){"use strict";function i(e,t,r){const i=t-1,o=t=>{const o=t*i,n=Math.floor(o),s=o-n,a=e[n];return 0===s?a:r(a,e[Math.min(n+1,i)],s)};return{q1:o(.25),median:o(.5),q3:o(.75)}}function o(e,t=e.length){return i(e,t,((e,t,r)=>e+r*(t-e)))}function n(e,t=e.length){return i(e,t,((e,t,r)=>e+(t-e)*r))}function s(e,t=e.length){return i(e,t,(e=>e))}function a(e,t=e.length){return i(e,t,((e,t)=>t))}function l(e,t=e.length){return i(e,t,((e,t,r)=>r<.5?e:t))}function u(e,t=e.length){return i(e,t,((e,t)=>.5*(e+t)))}function h(e,t=e.length){const r=t,i=Math.floor((r+3)/2)/2,o=t=>.5*(e[Math.floor(t)-1]+e[Math.ceil(t)-1]);return{q1:o(i),median:o((r+1)/2),q3:o(r+1-i)}}function d(e,t=e.length){return h(e,t)}function m(e,t={}){const{quantiles:r,validAndSorted:i,coef:n,whiskersMode:s,eps:a}=Object.assign({coef:1.5,eps:.01,quantiles:o,validAndSorted:!1,whiskersMode:"nearest"},t),{missing:l,s:u,min:h,max:d,sum:m}=i?function(e){if(0===e.length)return{sum:Number.NaN,min:Number.NaN,max:Number.NaN,missing:0,s:[]};const t=e[0],r=e[e.length-1],i=(e,t)=>e+t;return{sum:(e instanceof Float32Array||Float64Array,e.reduce(i,0)),min:t,max:r,missing:0,s:e}}(e):function(e){let t=Number.POSITIVE_INFINITY,r=Number.NEGATIVE_INFINITY,i=0,o=0;const n=e.length,s=e instanceof Float64Array?new Float64Array(n):new Float32Array(n);for(let a=0;a<n;++a){const n=e[a];null==n||Number.isNaN(n)||(s[o]=n,o++,n<t&&(t=n),n>r&&(r=n),i+=n)}const a=n-o;if(0===o)return{sum:i,min:t,max:r,missing:a,s:[]};const l=o===n?s:s.subarray(0,o);return l.sort(((e,t)=>e===t?0:e<t?-1:1)),{sum:i,min:l[0],max:l[l.length-1],missing:a,s:l}}(e),c={min:Number.NaN,max:Number.NaN,mean:Number.NaN,missing:l,iqr:Number.NaN,count:e.length,whiskerHigh:Number.NaN,whiskerLow:Number.NaN,outlier:[],median:Number.NaN,q1:Number.NaN,q3:Number.NaN,items:[]},f=(e,t)=>Math.abs(e-t)<a,g=e.length-l;if(0===g)return c;const{median:p,q1:x,q3:y}=r(u,g),b=y-x,w="number"==typeof n&&n>0;let q=w?Math.max(h,x-n*b):h,k=w?Math.min(d,y+n*b):d;const N=[];for(let e=0;e<g;++e){const t=u[e];if(t>=q||f(t,q)){"nearest"===s&&(q=t);break}0!==N.length&&f(N[N.length-1],t)||N.push(t)}const C=[];for(let e=g-1;e>=0;--e){const t=u[e];if(t<=k||f(t,k)){"nearest"===s&&(k=t);break}0!==C.length&&f(C[C.length-1],t)||0!==N.length&&f(N[N.length-1],t)||C.push(t)}return{min:h,max:d,count:e.length,missing:l,mean:m/g,whiskerHigh:k,whiskerLow:q,outlier:N.concat(C.reverse()),median:p,q1:x,q3:y,iqr:b,items:u}}function c(e){const t=e.length;if(t<1)return Number.NaN;if(1===t)return 0;const r=function(e){return 0===e.length?Number.NaN:e.reduce(((e,t,r)=>e+(t-e)/(r+1)),0)}(e);return e.reduce(((e,t)=>e+(t-r)*(t-r)),0)/(e.length-1)}function f(e,t,r){const i=function(e,t){const r=t(e),i=(r.q3-r.q1)/1.34;return 1.06*Math.min(Math.sqrt(c(e)),i)*Math.pow(e.length,-.2)}(t,r);return e.map((e=>{const r=t.reduce(((t,r)=>{return t+(o=(e-r)/i,1/Math.sqrt(2*Math.PI)*Math.exp(-.5*o*o));var o}),0);return{v:e,estimate:r/i/t.length}}))}const g={coef:1.5,quantiles:7};function p(e){return{coef:null==e||"number"!=typeof e.coef?g.coef:e.coef,quantiles:function(e){return"function"==typeof e?e:{hinges:d,fivenum:h,7:o,quantiles:o,linear:n,lower:s,higher:a,nearest:l,midpoint:u}[e]||o}(null==e||null==e.quantiles?o:e.quantiles)}}function x(e,t){if(e){if("number"==typeof e.median&&"number"==typeof e.q1&&"number"==typeof e.q3){if(void 0===e.whiskerMin){const{coef:r}=p(t),{whiskerMin:i,whiskerMax:o}=function(e,t,r=1.5){const i=e.q3-e.q1,o="number"==typeof r&&r>0;let n=o?Math.max(e.min,e.q1-r*i):e.min,s=o?Math.min(e.max,e.q3+r*i):e.max;if(Array.isArray(t)){for(let e=0;e<t.length;e++){const r=t[e];if(r>=n){n=r;break}}for(let e=t.length-1;e>=0;e--){const r=t[e];if(r<=s){s=r;break}}}return{whiskerMin:n,whiskerMax:s}}(e,Array.isArray(e.items)?e.items.slice().sort(((e,t)=>e-t)):null,r);e.whiskerMin=i,e.whiskerMax=o}return e}if(Array.isArray(e))return function(e,t){const r=m(e,p(t));return{items:Array.from(r.items),outliers:r.outlier,whiskerMax:r.whiskerHigh,whiskerMin:r.whiskerLow,max:r.max,median:r.median,mean:r.mean,min:r.min,q1:r.q1,q3:r.q3}}(e,t)}}function y(e,t){if(e){if("number"==typeof e.median&&Array.isArray(e.coords))return e;if(Array.isArray(e))return function(e,t){if(0===e.length)return;const r=e.filter((e=>"number"==typeof e&&!Number.isNaN(e))).sort(((e,t)=>e-t)),i=r.reduce(((e,t)=>e+t),0)/r.length,{quantiles:o}=p(t),n=o(r),s=r[0],a=r[r.length-1],l=[],u=(a-s)/t.points;for(let e=s;e<=a&&u>0;e+=u)l.push(e);l[l.length-1]!==a&&l.push(a);const h=f(r,l,o),d=h.reduce(((e,t)=>Math.max(e,t.estimate)),Number.NEGATIVE_INFINITY);return{...n,min:s,items:r,mean:i,max:a,coords:h,outliers:[],maxEstimate:d}}(e,t)}}const b={number:(e,t,r)=>e===t||null==e?t:null==t?e:e+(t-e)*r};function w(e,t,r){return"number"==typeof e&&"number"==typeof t?b.number(e,t,r):Array.isArray(e)&&Array.isArray(t)?t.map(((t,i)=>b.number(e[i],t,r))):t}function q(e){const t=e.formattedValue,r=this;t&&null!=r._tooltipOutlier&&e.datasetIndex===r._tooltipOutlier.datasetIndex&&(t.hoveredOutlierIndex=r._tooltipOutlier.index)}function k(e,t){if(!e.length)return!1;let r=0,i=0,o=0;for(let n=0;n<e.length;++n){const s=e[n].element;if(s&&s.hasValue()){const e=s.tooltipPosition(t,this);r+=e.x,i+=e.y,++o}}return{x:r/o,y:i/o}}function N(e){const t=["borderColor","backgroundColor"].concat(e.filter((e=>e.endsWith("Color"))));return Object.assign({animations:{numberArray:{fn:w,properties:["outliers","items"]},colors:{type:"color",properties:t}},transitions:{show:{animations:{colors:{type:"color",properties:t,from:"transparent"}}},hide:{animations:{colors:{type:"color",properties:t,to:"transparent"}}}},minStats:"min",maxStats:"max"},g)}function C(){return{plugins:{tooltips:{position:k.register().id,callbacks:{beforeLabel:q}}}}}k.id="averageInstance",k.register=()=>(t.Tooltip.positioners.averageInstance=k,k);class M extends t.BarController{_transformStats(e,t,r){for(const i of["min","max","median","q3","q1","mean"]){const o=t[i];"number"==typeof o&&(e[i]=r(o))}for(const i of["outliers","items"])Array.isArray(t[i])&&(e[i]=t[i].map(r))}getMinMax(e,t){const r=e.axis,i=this.options;e.axis=i.minStats;const o=super.getMinMax(e,t).min;e.axis=i.maxStats;const n=super.getMinMax(e,t).max;return e.axis=r,{min:o,max:n}}parsePrimitiveData(e,t,r,i){const o=e.vScale,n=e.iScale,s=n.getLabels(),a=[];for(let e=0;e<i;e++){const i=e+r,l={};l[n.axis]=n.parse(s[i],i);const u=this._parseStats(null==t?null:t[i],this.options);u&&(Object.assign(l,u),l[o.axis]=u.median),a.push(l)}return a}parseArrayData(e,t,r,i){return this.parsePrimitiveData(e,t,r,i)}parseObjectData(e,t,r,i){return this.parsePrimitiveData(e,t,r,i)}getLabelAndValue(e){const t=super.getLabelAndValue(e),r=this._cachedMeta.vScale,i=this.getParsed(e);if(!r||!i||"NaN"===t.value)return t;t.value={raw:i,hoveredOutlierIndex:-1},this._transformStats(t.value,i,(e=>r.getLabelForValue(e)));const o=this._toStringStats(t.value);return t.value.toString=function(){return this.hoveredOutlierIndex>=0?`(outlier: ${this.outliers[this.hoveredOutlierIndex]})`:o},t}_toStringStats(e){const t=e=>null==e?"NaN":e.toLocaleString();return`(min: ${t(e.min)}, 25% quantile: ${t(e.q1)}, median: ${t(e.median)}, mean: ${t(e.mean)}, 75% quantile: ${t(e.q3)}, max: ${t(e.max)})`}updateElement(e,t,r,i){const o="reset"===i,n=this._cachedMeta.vScale,s=this.getParsed(t),a=n.getBasePixel();r._datasetIndex=this.index,r._index=t,this._transformStats(r,s,(e=>o?a:n.getPixelForValue(e,t))),super.updateElement(e,t,r,i)}}const v={borderWidth:1,outlierStyle:"circle",outlierRadius:2,outlierBorderWidth:1,itemStyle:"circle",itemRadius:0,itemBorderWidth:0,meanStyle:"circle",meanRadius:3,meanBorderWidth:1,hitPadding:2,outlierHitRadius:4},_={outlierBackgroundColor:"backgroundColor",outlierBorderColor:"borderColor",itemBackgroundColor:"backgroundColor",itemBorderColor:"borderColor",meanBackgroundColor:"backgroundColor",meanBorderColor:"borderColor"},B=Object.keys(v).concat(Object.keys(_));class S extends t.Element{isVertical(){return null==this.getProps(["height"]).height}_drawItems(e){const t=this.isVertical(),i=this.getProps(["x","y","items","width","height","outliers"]),o=this.options;if(o.itemRadius<=0||!i.items||i.items.length<=0)return;e.save(),e.strokeStyle=o.itemBorderColor,e.fillStyle=o.itemBackgroundColor,e.lineWidth=o.itemBorderWidth;const n=function(e=Date.now()){let t=e;return()=>(t=(9301*t+49297)%233280,t/233280)}(1e3*this._datasetIndex+this._index),s={pointStyle:o.itemStyle,radius:o.itemRadius,borderWidth:o.itemBorderWidth},a=new Set(i.outliers||[]);t?i.items.forEach((t=>{a.has(t)||r.drawPoint(e,s,i.x-i.width/2+n()*i.width,t)})):i.items.forEach((t=>{a.has(t)||r.drawPoint(e,s,t,i.y-i.height/2+n()*i.height)})),e.restore()}_drawOutliers(e){const t=this.isVertical(),i=this.getProps(["x","y","outliers"]),o=this.options;if(o.outlierRadius<=0||!i.outliers||0===i.outliers.length)return;e.save(),e.fillStyle=o.outlierBackgroundColor,e.strokeStyle=o.outlierBorderColor,e.lineWidth=o.outlierBorderWidth;const n={pointStyle:o.outlierStyle,radius:o.outlierRadius,borderWidth:o.outlierBorderWidth};t?i.outliers.forEach((t=>{r.drawPoint(e,n,i.x,t)})):i.outliers.forEach((t=>{r.drawPoint(e,n,t,i.y)})),e.restore()}_drawMeanDot(e){const t=this.isVertical(),i=this.getProps(["x","y","mean"]),o=this.options;if(o.meanRadius<=0||null==i.mean||Number.isNaN(i.mean))return;e.save(),e.fillStyle=o.meanBackgroundColor,e.strokeStyle=o.meanBorderColor,e.lineWidth=o.meanBorderWidth;const n={pointStyle:o.meanStyle,radius:o.meanRadius,borderWidth:o.meanBorderWidth};t?r.drawPoint(e,n,i.x,i.mean):r.drawPoint(e,n,i.mean,i.y),e.restore()}_getBounds(e){return{left:0,top:0,right:0,bottom:0}}_getHitBounds(e){const t=this.options.hitPadding,r=this._getBounds(e);return{left:r.left-t,top:r.top-t,right:r.right+t,bottom:r.bottom+t}}inRange(e,t,r){return(!Number.isNaN(this.x)||!Number.isNaN(this.y))&&(this._boxInRange(e,t,r)||this._outlierIndexInRange(e,t,r)>=0)}inXRange(e,t){const r=this._getHitBounds(t);return e>=r.left&&e<=r.right}inYRange(e,t){const r=this._getHitBounds(t);return e>=r.top&&e<=r.bottom}_outlierIndexInRange(e,t,r){const i=this.getProps(["x","y"],r),o=this.options.outlierHitRadius,n=this._getOutliers(r),s=this.isVertical();if(s&&Math.abs(e-i.x)>o||!s&&Math.abs(t-i.y)>o)return-1;const a=s?t:e;for(let e=0;e<n.length;e++)if(Math.abs(n[e]-a)<=o)return e;return-1}_boxInRange(e,t,r){const i=this._getHitBounds(r);return e>=i.left&&e<=i.right&&t>=i.top&&t<=i.bottom}getCenterPoint(e){const t=this.getProps(["x","y"],e);return{x:t.x,y:t.y}}_getOutliers(e){return this.getProps(["outliers"],e).outliers||[]}tooltipPosition(e,t){if(!e||"boolean"==typeof e)return this.getCenterPoint();t&&delete t._tooltipOutlier;const r=this.getProps(["x","y"]),i=this._outlierIndexInRange(e.x,e.y);return i<0||!t?this.getCenterPoint():(t._tooltipOutlier={index:i,datasetIndex:this._datasetIndex},this.isVertical()?{x:r.x,y:this._getOutliers()[i]}:{x:this._getOutliers()[i],y:r.y})}}const P=B.concat(["medianColor","lowerBackgroundColor"]);class T extends S{draw(e){e.save(),e.fillStyle=this.options.backgroundColor,e.strokeStyle=this.options.borderColor,e.lineWidth=this.options.borderWidth,this._drawBoxPlot(e),this._drawOutliers(e),this._drawMeanDot(e),e.restore(),this._drawItems(e)}_drawBoxPlot(e){this.isVertical()?this._drawBoxPlotVertical(e):this._drawBoxPlotHorizontal(e)}_drawBoxPlotVertical(e){const t=this.options,r=this.getProps(["x","width","q1","q3","median","whiskerMin","whiskerMax"]),i=r.x,o=r.width,n=i-o/2;r.q3>r.q1?e.fillRect(n,r.q1,o,r.q3-r.q1):e.fillRect(n,r.q3,o,r.q1-r.q3),e.save(),t.medianColor&&"transparent"!==t.medianColor&&"#0000"!==t.medianColor&&(e.strokeStyle=t.medianColor),e.beginPath(),e.moveTo(n,r.median),e.lineTo(n+o,r.median),e.closePath(),e.stroke(),e.restore(),e.save(),t.lowerBackgroundColor&&"transparent"!==t.lowerBackgroundColor&&"#0000"!==t.lowerBackgroundColor&&(e.fillStyle=t.lowerBackgroundColor,r.q3>r.q1?e.fillRect(n,r.median,o,r.q3-r.median):e.fillRect(n,r.median,o,r.q1-r.median)),e.restore(),r.q3>r.q1?e.strokeRect(n,r.q1,o,r.q3-r.q1):e.strokeRect(n,r.q3,o,r.q1-r.q3),e.beginPath(),e.moveTo(n,r.whiskerMin),e.lineTo(n+o,r.whiskerMin),e.moveTo(i,r.whiskerMin),e.lineTo(i,r.q1),e.moveTo(n,r.whiskerMax),e.lineTo(n+o,r.whiskerMax),e.moveTo(i,r.whiskerMax),e.lineTo(i,r.q3),e.closePath(),e.stroke()}_drawBoxPlotHorizontal(e){const t=this.options,r=this.getProps(["y","height","q1","q3","median","whiskerMin","whiskerMax"]),i=r.y,o=r.height,n=i-o/2;r.q3>r.q1?e.fillRect(r.q1,n,r.q3-r.q1,o):e.fillRect(r.q3,n,r.q1-r.q3,o),e.save(),t.medianColor&&"transparent"!==t.medianColor&&(e.strokeStyle=t.medianColor),e.beginPath(),e.moveTo(r.median,n),e.lineTo(r.median,n+o),e.closePath(),e.stroke(),e.restore(),e.save(),t.lowerBackgroundColor&&"transparent"!==t.lowerBackgroundColor&&(e.fillStyle=t.lowerBackgroundColor,r.q3>r.q1?e.fillRect(r.median,n,r.q3-r.median,o):e.fillRect(r.median,n,r.q1-r.median,o)),e.restore(),r.q3>r.q1?e.strokeRect(r.q1,n,r.q3-r.q1,o):e.strokeRect(r.q3,n,r.q1-r.q3,o),e.beginPath(),e.moveTo(r.whiskerMin,n),e.lineTo(r.whiskerMin,n+o),e.moveTo(r.whiskerMin,i),e.lineTo(r.q1,i),e.moveTo(r.whiskerMax,n),e.lineTo(r.whiskerMax,n+o),e.moveTo(r.whiskerMax,i),e.lineTo(r.q3,i),e.closePath(),e.stroke()}_getBounds(e){const t=this.isVertical();if(null==this.x)return{left:0,top:0,right:0,bottom:0};if(t){const{x:t,width:r,whiskerMax:i,whiskerMin:o}=this.getProps(["x","width","whiskerMin","whiskerMax"],e),n=t-r/2;return{left:n,top:i,right:n+r,bottom:o}}const{y:r,height:i,whiskerMax:o,whiskerMin:n}=this.getProps(["y","height","whiskerMin","whiskerMax"],e),s=r-i/2;return{left:n,top:s,right:o,bottom:s+i}}}T.id="boxandwhiskers",T.defaults=Object.assign({},t.BarElement.defaults,v,{medianColor:"transparent",lowerBackgroundColor:"transparent"}),T.defaultRoutes=Object.assign({},t.BarElement.defaultRoutes,_);class A extends S{draw(e){e.save(),e.fillStyle=this.options.backgroundColor,e.strokeStyle=this.options.borderColor,e.lineWidth=this.options.borderWidth;const t=this.getProps(["x","y","width","height","min","max","coords","maxEstimate"]);r.drawPoint(e,{pointStyle:"rectRot",radius:5,borderWidth:this.options.borderWidth},t.x,t.y),t.coords&&t.coords.length>0&&this._drawCoords(e,t),this._drawOutliers(e),this._drawMeanDot(e),e.restore(),this._drawItems(e)}_drawCoords(e,t){if(e.beginPath(),this.isVertical()){const r=t.x,i=t.width/2/t.maxEstimate;e.moveTo(r,t.min),t.coords.forEach((t=>{e.lineTo(r-t.estimate*i,t.v)})),e.lineTo(r,t.max),e.moveTo(r,t.min),t.coords.forEach((t=>{e.lineTo(r+t.estimate*i,t.v)})),e.lineTo(r,t.max)}else{const r=t.y,i=t.height/2/t.maxEstimate;e.moveTo(t.min,r),t.coords.forEach((t=>{e.lineTo(t.v,r-t.estimate*i)})),e.lineTo(t.max,r),e.moveTo(t.min,r),t.coords.forEach((t=>{e.lineTo(t.v,r+t.estimate*i)})),e.lineTo(t.max,r)}e.closePath(),e.stroke(),e.fill()}_getBounds(e){if(this.isVertical()){const{x:t,width:r,min:i,max:o}=this.getProps(["x","width","min","max"],e),n=t-r/2;return{left:n,top:o,right:n+r,bottom:i}}const{y:t,height:r,min:i,max:o}=this.getProps(["y","height","min","max"],e),n=t-r/2;return{left:i,top:n,right:o,bottom:n+r}}}function I(e,r,i,o=[],n=[]){t.registry.addControllers(i),Array.isArray(o)?t.registry.addElements(...o):t.registry.addElements(o),Array.isArray(n)?t.registry.addScales(...n):t.registry.addScales(n);const s=r;return s.type=e,s}A.id="violin",A.defaults=Object.assign({},t.BarElement.defaults,v),A.defaultRoutes=Object.assign({},t.BarElement.defaultRoutes,_);class R extends M{_parseStats(e,t){return x(e,t)}_transformStats(e,t,r){super._transformStats(e,t,r);for(const i of["whiskerMin","whiskerMax"])e[i]=r(t[i])}}R.id="boxplot",R.defaults=r.merge({},[t.BarController.defaults,N(P),{animations:{numbers:{type:"number",properties:t.BarController.defaults.animations.numbers.properties.concat(["q1","q3","min","max","median","whiskerMin","whiskerMax","mean"],P.filter((e=>!e.endsWith("Color"))))}},dataElementType:T.id}]),R.overrides=r.merge({},[t.BarController.overrides,C()]);class E extends t.Chart{constructor(e,r){super(e,I("boxplot",r,R,T,[t.LinearScale,t.CategoryScale]))}}E.id=R.id;class O extends M{_parseStats(e,t){return y(e,t)}_transformStats(e,t,r){super._transformStats(e,t,r),e.maxEstimate=t.maxEstimate,Array.isArray(t.coords)&&(e.coords=t.coords.map((e=>Object.assign({},e,{v:r(e.v)}))))}}O.id="violin",O.defaults=r.merge({},[t.BarController.defaults,N(B),{points:100,animations:{numbers:{type:"number",properties:t.BarController.defaults.animations.numbers.properties.concat(["q1","q3","min","max","median","maxEstimate"],B.filter((e=>!e.endsWith("Color"))))},kdeCoords:{fn:function(e,t,r){return Array.isArray(e)&&Array.isArray(t)?t.map(((t,i)=>({v:b.number(e[i]?e[i].v:null,t.v,r),estimate:b.number(e[i]?e[i].estimate:null,t.estimate,r)}))):t},properties:["coords"]}},dataElementType:A.id}]),O.overrides=r.merge({},[t.BarController.overrides,C()]);class W extends t.Chart{constructor(e,r){super(e,I("violin",r,O,A,[t.LinearScale,t.CategoryScale]))}}W.id=O.id,t.registry.addControllers(R,O),t.registry.addElements(T,A),e.BoxAndWiskers=T,e.BoxPlotChart=E,e.BoxPlotController=R,e.StatsBase=S,e.Violin=A,e.ViolinChart=W,e.ViolinController=O,Object.defineProperty(e,"__esModule",{value:!0})}));
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("chart.js"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["exports","chart.js","chart.js/helpers"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).ChartBoxPlot={},t.Chart,t.Chart.helpers)}(this,(function(t,e,r){"use strict";function i(t,e,r){const i=e-1,o=e=>{const o=e*i,n=Math.floor(o),s=o-n,a=t[n];return 0===s?a:r(a,t[Math.min(n+1,i)],s)};return{q1:o(.25),median:o(.5),q3:o(.75)}}function o(t,e=t.length){return i(t,e,((t,e,r)=>t+r*(e-t)))}function n(t,e=t.length){return i(t,e,((t,e,r)=>t+(e-t)*r))}function s(t,e=t.length){return i(t,e,(t=>t))}function a(t,e=t.length){return i(t,e,((t,e)=>e))}function l(t,e=t.length){return i(t,e,((t,e,r)=>r<.5?t:e))}function u(t,e=t.length){return i(t,e,((t,e)=>.5*(t+e)))}function h(t,e=t.length){const r=e,i=Math.floor((r+3)/2)/2,o=e=>.5*(t[Math.floor(e)-1]+t[Math.ceil(e)-1]);return{q1:o(i),median:o((r+1)/2),q3:o(r+1-i)}}function d(t,e=t.length){return h(t,e)}function m(t,e={}){const{quantiles:r,validAndSorted:i,coef:n,whiskersMode:s,eps:a}=Object.assign({coef:1.5,eps:.01,quantiles:o,validAndSorted:!1,whiskersMode:"nearest"},e),{missing:l,s:u,min:h,max:d,sum:m}=i?function(t){if(0===t.length)return{sum:Number.NaN,min:Number.NaN,max:Number.NaN,missing:0,s:[]};const e=t[0],r=t[t.length-1],i=(t,e)=>t+e;return{sum:(t instanceof Float32Array||Float64Array,t.reduce(i,0)),min:e,max:r,missing:0,s:t}}(t):function(t){let e=Number.POSITIVE_INFINITY,r=Number.NEGATIVE_INFINITY,i=0,o=0;const n=t.length,s=t instanceof Float64Array?new Float64Array(n):new Float32Array(n);for(let a=0;a<n;++a){const n=t[a];null==n||Number.isNaN(n)||(s[o]=n,o++,n<e&&(e=n),n>r&&(r=n),i+=n)}const a=n-o;if(0===o)return{sum:i,min:e,max:r,missing:a,s:[]};const l=o===n?s:s.subarray(0,o);return l.sort(((t,e)=>t===e?0:t<e?-1:1)),{sum:i,min:l[0],max:l[l.length-1],missing:a,s:l}}(t),c={min:Number.NaN,max:Number.NaN,mean:Number.NaN,missing:l,iqr:Number.NaN,count:t.length,whiskerHigh:Number.NaN,whiskerLow:Number.NaN,outlier:[],median:Number.NaN,q1:Number.NaN,q3:Number.NaN,items:[]},f=(t,e)=>Math.abs(t-e)<a,g=t.length-l;if(0===g)return c;const{median:p,q1:x,q3:y}=r(u,g),b=y-x,w="number"==typeof n&&n>0;let q=w?Math.max(h,x-n*b):h,k=w?Math.min(d,y+n*b):d;const N=[];for(let t=0;t<g;++t){const e=u[t];if(e>=q||f(e,q)){"nearest"===s&&(q=e);break}0!==N.length&&f(N[N.length-1],e)||N.push(e)}const C=[];for(let t=g-1;t>=0;--t){const e=u[t];if(e<=k||f(e,k)){"nearest"===s&&(k=e);break}0!==C.length&&f(C[C.length-1],e)||0!==N.length&&f(N[N.length-1],e)||C.push(e)}return{min:h,max:d,count:t.length,missing:l,mean:m/g,whiskerHigh:k,whiskerLow:q,outlier:N.concat(C.reverse()),median:p,q1:x,q3:y,iqr:b,items:u}}function c(t){const e=t.length;if(e<1)return Number.NaN;if(1===e)return 0;const r=function(t){return 0===t.length?Number.NaN:t.reduce(((t,e,r)=>t+(e-t)/(r+1)),0)}(t);return t.reduce(((t,e)=>t+(e-r)*(e-r)),0)/(t.length-1)}function f(t,e,r){const i=function(t,e){const r=e(t),i=(r.q3-r.q1)/1.34;return 1.06*Math.min(Math.sqrt(c(t)),i)*Math.pow(t.length,-.2)}(e,r);return t.map((t=>{const r=e.reduce(((e,r)=>{return e+(o=(t-r)/i,1/Math.sqrt(2*Math.PI)*Math.exp(-.5*o*o));var o}),0);return{v:t,estimate:r/i/e.length}}))}const g={coef:1.5,quantiles:7};function p(t){return{coef:null==t||"number"!=typeof t.coef?g.coef:t.coef,quantiles:function(t){return"function"==typeof t?t:{hinges:d,fivenum:h,7:o,quantiles:o,linear:n,lower:s,higher:a,nearest:l,midpoint:u}[t]||o}(null==t||null==t.quantiles?o:t.quantiles)}}function x(t,e){if(t){if("number"==typeof t.median&&"number"==typeof t.q1&&"number"==typeof t.q3){if(void 0===t.whiskerMin){const{coef:r}=p(e),{whiskerMin:i,whiskerMax:o}=function(t,e,r=1.5){const i=t.q3-t.q1,o="number"==typeof r&&r>0;let n=o?Math.max(t.min,t.q1-r*i):t.min,s=o?Math.min(t.max,t.q3+r*i):t.max;if(Array.isArray(e)){for(let t=0;t<e.length;t+=1){const r=e[t];if(r>=n){n=r;break}}for(let t=e.length-1;t>=0;t-=1){const r=e[t];if(r<=s){s=r;break}}}return{whiskerMin:n,whiskerMax:s}}(t,Array.isArray(t.items)?t.items.slice().sort(((t,e)=>t-e)):null,r);t.whiskerMin=i,t.whiskerMax=o}return t}if(Array.isArray(t))return function(t,e){const r=m(t,p(e));return{items:Array.from(r.items),outliers:r.outlier,whiskerMax:r.whiskerHigh,whiskerMin:r.whiskerLow,max:r.max,median:r.median,mean:r.mean,min:r.min,q1:r.q1,q3:r.q3}}(t,e)}}function y(t,e){if(t){if("number"==typeof t.median&&Array.isArray(t.coords))return t;if(Array.isArray(t))return function(t,e){if(0===t.length)return;const r=t.filter((t=>"number"==typeof t&&!Number.isNaN(t))).sort(((t,e)=>t-e)),i=r.reduce(((t,e)=>t+e),0)/r.length,{quantiles:o}=p(e),n=o(r),s=r[0],a=r[r.length-1],l=[],u=(a-s)/e.points;for(let t=s;t<=a&&u>0;t+=u)l.push(t);l[l.length-1]!==a&&l.push(a);const h=f(r,l,o),d=h.reduce(((t,e)=>Math.max(t,e.estimate)),Number.NEGATIVE_INFINITY);return{...n,min:s,items:r,mean:i,max:a,coords:h,outliers:[],maxEstimate:d}}(t,e)}}const b={number:(t,e,r)=>t===e||null==t?e:null==e?t:t+(e-t)*r};function w(t,e,r){return"number"==typeof t&&"number"==typeof e?b.number(t,e,r):Array.isArray(t)&&Array.isArray(e)?e.map(((e,i)=>b.number(t[i],e,r))):e}function q(t){const e=t.formattedValue,r=this;e&&null!=r._tooltipOutlier&&t.datasetIndex===r._tooltipOutlier.datasetIndex&&(e.hoveredOutlierIndex=r._tooltipOutlier.index)}function k(t,e){if(!t.length)return!1;let r=0,i=0,o=0;for(let n=0;n<t.length;n+=1){const s=t[n].element;if(s&&s.hasValue()){const t=s.tooltipPosition(e,this);r+=t.x,i+=t.y,o+=1}}return{x:r/o,y:i/o}}function N(t){const e=["borderColor","backgroundColor"].concat(t.filter((t=>t.endsWith("Color"))));return{animations:{numberArray:{fn:w,properties:["outliers","items"]},colors:{type:"color",properties:e}},transitions:{show:{animations:{colors:{type:"color",properties:e,from:"transparent"}}},hide:{animations:{colors:{type:"color",properties:e,to:"transparent"}}}},minStats:"min",maxStats:"max",...g}}function C(){return{plugins:{tooltips:{position:k.register().id,callbacks:{beforeLabel:q}}}}}k.id="averageInstance",k.register=()=>(e.Tooltip.positioners.averageInstance=k,k);class M extends e.BarController{_transformStats(t,e,r){for(const i of["min","max","median","q3","q1","mean"]){const o=e[i];"number"==typeof o&&(t[i]=r(o))}for(const i of["outliers","items"])Array.isArray(e[i])&&(t[i]=e[i].map(r))}getMinMax(t,e){const r=t.axis,i=this.options;t.axis=i.minStats;const{min:o}=super.getMinMax(t,e);t.axis=i.maxStats;const{max:n}=super.getMinMax(t,e);return t.axis=r,{min:o,max:n}}parsePrimitiveData(t,e,r,i){const o=t.vScale,n=t.iScale,s=n.getLabels(),a=[];for(let t=0;t<i;t+=1){const i=t+r,l={};l[n.axis]=n.parse(s[i],i);const u=this._parseStats(null==e?null:e[i],this.options);u&&(Object.assign(l,u),l[o.axis]=u.median),a.push(l)}return a}parseArrayData(t,e,r,i){return this.parsePrimitiveData(t,e,r,i)}parseObjectData(t,e,r,i){return this.parsePrimitiveData(t,e,r,i)}getLabelAndValue(t){const e=super.getLabelAndValue(t),{vScale:r}=this._cachedMeta,i=this.getParsed(t);if(!r||!i||"NaN"===e.value)return e;e.value={raw:i,hoveredOutlierIndex:-1},this._transformStats(e.value,i,(t=>r.getLabelForValue(t)));const o=this._toStringStats(e.value);return e.value.toString=function(){return this.hoveredOutlierIndex>=0?`(outlier: ${this.outliers[this.hoveredOutlierIndex]})`:o},e}_toStringStats(t){const e=t=>null==t?"NaN":r.formatNumber(t,this.chart.options.locale,{});return`(min: ${e(t.min)}, 25% quantile: ${e(t.q1)}, median: ${e(t.median)}, mean: ${e(t.mean)}, 75% quantile: ${e(t.q3)}, max: ${e(t.max)})`}updateElement(t,e,r,i){const o="reset"===i,n=this._cachedMeta.vScale,s=this.getParsed(e),a=n.getBasePixel();r._datasetIndex=this.index,r._index=e,this._transformStats(r,s,(t=>o?a:n.getPixelForValue(t,e))),super.updateElement(t,e,r,i)}}const v={borderWidth:1,outlierStyle:"circle",outlierRadius:2,outlierBorderWidth:1,itemStyle:"circle",itemRadius:0,itemBorderWidth:0,meanStyle:"circle",meanRadius:3,meanBorderWidth:1,hitPadding:2,outlierHitRadius:4},_={outlierBackgroundColor:"backgroundColor",outlierBorderColor:"borderColor",itemBackgroundColor:"backgroundColor",itemBorderColor:"borderColor",meanBackgroundColor:"backgroundColor",meanBorderColor:"borderColor"},B=Object.keys(v).concat(Object.keys(_));class P extends e.Element{isVertical(){return null==this.getProps(["height"]).height}_drawItems(t){const e=this.isVertical(),i=this.getProps(["x","y","items","width","height","outliers"]),{options:o}=this;if(o.itemRadius<=0||!i.items||i.items.length<=0)return;t.save(),t.strokeStyle=o.itemBorderColor,t.fillStyle=o.itemBackgroundColor,t.lineWidth=o.itemBorderWidth;const n=function(t=Date.now()){let e=t;return()=>(e=(9301*e+49297)%233280,e/233280)}(1e3*this._datasetIndex+this._index),s={pointStyle:o.itemStyle,radius:o.itemRadius,borderWidth:o.itemBorderWidth},a=new Set(i.outliers||[]);e?i.items.forEach((e=>{a.has(e)||r.drawPoint(t,s,i.x-i.width/2+n()*i.width,e)})):i.items.forEach((e=>{a.has(e)||r.drawPoint(t,s,e,i.y-i.height/2+n()*i.height)})),t.restore()}_drawOutliers(t){const e=this.isVertical(),i=this.getProps(["x","y","outliers"]),{options:o}=this;if(o.outlierRadius<=0||!i.outliers||0===i.outliers.length)return;t.save(),t.fillStyle=o.outlierBackgroundColor,t.strokeStyle=o.outlierBorderColor,t.lineWidth=o.outlierBorderWidth;const n={pointStyle:o.outlierStyle,radius:o.outlierRadius,borderWidth:o.outlierBorderWidth};e?i.outliers.forEach((e=>{r.drawPoint(t,n,i.x,e)})):i.outliers.forEach((e=>{r.drawPoint(t,n,e,i.y)})),t.restore()}_drawMeanDot(t){const e=this.isVertical(),i=this.getProps(["x","y","mean"]),{options:o}=this;if(o.meanRadius<=0||null==i.mean||Number.isNaN(i.mean))return;t.save(),t.fillStyle=o.meanBackgroundColor,t.strokeStyle=o.meanBorderColor,t.lineWidth=o.meanBorderWidth;const n={pointStyle:o.meanStyle,radius:o.meanRadius,borderWidth:o.meanBorderWidth};e?r.drawPoint(t,n,i.x,i.mean):r.drawPoint(t,n,i.mean,i.y),t.restore()}_getBounds(t){return{left:0,top:0,right:0,bottom:0}}_getHitBounds(t){const e=this.options.hitPadding,r=this._getBounds(t);return{left:r.left-e,top:r.top-e,right:r.right+e,bottom:r.bottom+e}}inRange(t,e,r){return(!Number.isNaN(this.x)||!Number.isNaN(this.y))&&(this._boxInRange(t,e,r)||this._outlierIndexInRange(t,e,r)>=0)}inXRange(t,e){const r=this._getHitBounds(e);return t>=r.left&&t<=r.right}inYRange(t,e){const r=this._getHitBounds(e);return t>=r.top&&t<=r.bottom}_outlierIndexInRange(t,e,r){const i=this.getProps(["x","y"],r),o=this.options.outlierHitRadius,n=this._getOutliers(r),s=this.isVertical();if(s&&Math.abs(t-i.x)>o||!s&&Math.abs(e-i.y)>o)return-1;const a=s?e:t;for(let t=0;t<n.length;t+=1)if(Math.abs(n[t]-a)<=o)return t;return-1}_boxInRange(t,e,r){const i=this._getHitBounds(r);return t>=i.left&&t<=i.right&&e>=i.top&&e<=i.bottom}getCenterPoint(t){const e=this.getProps(["x","y"],t);return{x:e.x,y:e.y}}_getOutliers(t){return this.getProps(["outliers"],t).outliers||[]}tooltipPosition(t,e){if(!t||"boolean"==typeof t)return this.getCenterPoint();e&&delete e._tooltipOutlier;const r=this.getProps(["x","y"]),i=this._outlierIndexInRange(t.x,t.y);return i<0||!e?this.getCenterPoint():(e._tooltipOutlier={index:i,datasetIndex:this._datasetIndex},this.isVertical()?{x:r.x,y:this._getOutliers()[i]}:{x:this._getOutliers()[i],y:r.y})}}const S=B.concat(["medianColor","lowerBackgroundColor"]);class T extends P{draw(t){t.save(),t.fillStyle=this.options.backgroundColor,t.strokeStyle=this.options.borderColor,t.lineWidth=this.options.borderWidth,this._drawBoxPlot(t),this._drawOutliers(t),this._drawMeanDot(t),t.restore(),this._drawItems(t)}_drawBoxPlot(t){this.isVertical()?this._drawBoxPlotVertical(t):this._drawBoxPlotHorizontal(t)}_drawBoxPlotVertical(t){const{options:e}=this,r=this.getProps(["x","width","q1","q3","median","whiskerMin","whiskerMax"]),{x:i}=r,{width:o}=r,n=i-o/2;r.q3>r.q1?t.fillRect(n,r.q1,o,r.q3-r.q1):t.fillRect(n,r.q3,o,r.q1-r.q3),t.save(),e.medianColor&&"transparent"!==e.medianColor&&"#0000"!==e.medianColor&&(t.strokeStyle=e.medianColor),t.beginPath(),t.moveTo(n,r.median),t.lineTo(n+o,r.median),t.closePath(),t.stroke(),t.restore(),t.save(),e.lowerBackgroundColor&&"transparent"!==e.lowerBackgroundColor&&"#0000"!==e.lowerBackgroundColor&&(t.fillStyle=e.lowerBackgroundColor,r.q3>r.q1?t.fillRect(n,r.median,o,r.q3-r.median):t.fillRect(n,r.median,o,r.q1-r.median)),t.restore(),r.q3>r.q1?t.strokeRect(n,r.q1,o,r.q3-r.q1):t.strokeRect(n,r.q3,o,r.q1-r.q3),t.beginPath(),t.moveTo(n,r.whiskerMin),t.lineTo(n+o,r.whiskerMin),t.moveTo(i,r.whiskerMin),t.lineTo(i,r.q1),t.moveTo(n,r.whiskerMax),t.lineTo(n+o,r.whiskerMax),t.moveTo(i,r.whiskerMax),t.lineTo(i,r.q3),t.closePath(),t.stroke()}_drawBoxPlotHorizontal(t){const{options:e}=this,r=this.getProps(["y","height","q1","q3","median","whiskerMin","whiskerMax"]),{y:i}=r,{height:o}=r,n=i-o/2;r.q3>r.q1?t.fillRect(r.q1,n,r.q3-r.q1,o):t.fillRect(r.q3,n,r.q1-r.q3,o),t.save(),e.medianColor&&"transparent"!==e.medianColor&&(t.strokeStyle=e.medianColor),t.beginPath(),t.moveTo(r.median,n),t.lineTo(r.median,n+o),t.closePath(),t.stroke(),t.restore(),t.save(),e.lowerBackgroundColor&&"transparent"!==e.lowerBackgroundColor&&(t.fillStyle=e.lowerBackgroundColor,r.q3>r.q1?t.fillRect(r.median,n,r.q3-r.median,o):t.fillRect(r.median,n,r.q1-r.median,o)),t.restore(),r.q3>r.q1?t.strokeRect(r.q1,n,r.q3-r.q1,o):t.strokeRect(r.q3,n,r.q1-r.q3,o),t.beginPath(),t.moveTo(r.whiskerMin,n),t.lineTo(r.whiskerMin,n+o),t.moveTo(r.whiskerMin,i),t.lineTo(r.q1,i),t.moveTo(r.whiskerMax,n),t.lineTo(r.whiskerMax,n+o),t.moveTo(r.whiskerMax,i),t.lineTo(r.q3,i),t.closePath(),t.stroke()}_getBounds(t){const e=this.isVertical();if(null==this.x)return{left:0,top:0,right:0,bottom:0};if(e){const{x:e,width:r,whiskerMax:i,whiskerMin:o}=this.getProps(["x","width","whiskerMin","whiskerMax"],t),n=e-r/2;return{left:n,top:i,right:n+r,bottom:o}}const{y:r,height:i,whiskerMax:o,whiskerMin:n}=this.getProps(["y","height","whiskerMin","whiskerMax"],t),s=r-i/2;return{left:n,top:s,right:o,bottom:s+i}}}T.id="boxandwhiskers",T.defaults={...e.BarElement.defaults,...v,medianColor:"transparent",lowerBackgroundColor:"transparent"},T.defaultRoutes={...e.BarElement.defaultRoutes,..._};class A extends P{draw(t){t.save(),t.fillStyle=this.options.backgroundColor,t.strokeStyle=this.options.borderColor,t.lineWidth=this.options.borderWidth;const e=this.getProps(["x","y","width","height","min","max","coords","maxEstimate"]);r.drawPoint(t,{pointStyle:"rectRot",radius:5,borderWidth:this.options.borderWidth},e.x,e.y),e.coords&&e.coords.length>0&&this._drawCoords(t,e),this._drawOutliers(t),this._drawMeanDot(t),t.restore(),this._drawItems(t)}_drawCoords(t,e){if(t.beginPath(),this.isVertical()){const{x:r}=e,{width:i}=e,o=i/2/e.maxEstimate;t.moveTo(r,e.min),e.coords.forEach((e=>{t.lineTo(r-e.estimate*o,e.v)})),t.lineTo(r,e.max),t.moveTo(r,e.min),e.coords.forEach((e=>{t.lineTo(r+e.estimate*o,e.v)})),t.lineTo(r,e.max)}else{const{y:r}=e,{height:i}=e,o=i/2/e.maxEstimate;t.moveTo(e.min,r),e.coords.forEach((e=>{t.lineTo(e.v,r-e.estimate*o)})),t.lineTo(e.max,r),t.moveTo(e.min,r),e.coords.forEach((e=>{t.lineTo(e.v,r+e.estimate*o)})),t.lineTo(e.max,r)}t.closePath(),t.stroke(),t.fill()}_getBounds(t){if(this.isVertical()){const{x:e,width:r,min:i,max:o}=this.getProps(["x","width","min","max"],t),n=e-r/2;return{left:n,top:o,right:n+r,bottom:i}}const{y:e,height:r,min:i,max:o}=this.getProps(["y","height","min","max"],t),n=e-r/2;return{left:i,top:n,right:o,bottom:n+r}}}function I(t,r,i,o=[],n=[]){e.registry.addControllers(i),Array.isArray(o)?e.registry.addElements(...o):e.registry.addElements(o),Array.isArray(n)?e.registry.addScales(...n):e.registry.addScales(n);const s=r;return s.type=t,s}A.id="violin",A.defaults={...e.BarElement.defaults,...v},A.defaultRoutes={...e.BarElement.defaultRoutes,..._};class R extends M{_parseStats(t,e){return x(t,e)}_transformStats(t,e,r){super._transformStats(t,e,r);for(const i of["whiskerMin","whiskerMax"])t[i]=r(e[i])}}R.id="boxplot",R.defaults=r.merge({},[e.BarController.defaults,N(S),{animations:{numbers:{type:"number",properties:e.BarController.defaults.animations.numbers.properties.concat(["q1","q3","min","max","median","whiskerMin","whiskerMax","mean"],S.filter((t=>!t.endsWith("Color"))))}},dataElementType:T.id}]),R.overrides=r.merge({},[e.BarController.overrides,C()]);class E extends e.Chart{constructor(t,r){super(t,I("boxplot",r,R,T,[e.LinearScale,e.CategoryScale]))}}E.id=R.id;class W extends M{_parseStats(t,e){return y(t,e)}_transformStats(t,e,r){super._transformStats(t,e,r),t.maxEstimate=e.maxEstimate,Array.isArray(e.coords)&&(t.coords=e.coords.map((t=>({...t,v:r(t.v)}))))}}W.id="violin",W.defaults=r.merge({},[e.BarController.defaults,N(B),{points:100,animations:{numbers:{type:"number",properties:e.BarController.defaults.animations.numbers.properties.concat(["q1","q3","min","max","median","maxEstimate"],B.filter((t=>!t.endsWith("Color"))))},kdeCoords:{fn:function(t,e,r){return Array.isArray(t)&&Array.isArray(e)?e.map(((e,i)=>({v:b.number(t[i]?t[i].v:null,e.v,r),estimate:b.number(t[i]?t[i].estimate:null,e.estimate,r)}))):e},properties:["coords"]}},dataElementType:A.id}]),W.overrides=r.merge({},[e.BarController.overrides,C()]);class V extends e.Chart{constructor(t,r){super(t,I("violin",r,W,A,[e.LinearScale,e.CategoryScale]))}}V.id=W.id,e.registry.addControllers(R,W),e.registry.addElements(T,A),t.BoxAndWiskers=T,t.BoxPlotChart=E,t.BoxPlotController=R,t.StatsBase=P,t.Violin=A,t.ViolinChart=V,t.ViolinController=W,Object.defineProperty(t,"__esModule",{value:!0})}));
//# sourceMappingURL=index.umd.min.js.map
{
"name": "@sgratzl/chartjs-chart-boxplot",
"description": "Chart.js module for charting boxplots and violin charts",
"version": "3.0.0-rc.0",
"version": "3.0.0-rc.1",
"publishConfig": {

@@ -53,3 +53,3 @@ "access": "public"

"peerDependencies": {
"chart.js": "^3.0.0-rc"
"chart.js": "^3.0.0-rc.2"
},

@@ -77,4 +77,5 @@ "browserslist": [

"canvas-5-polyfill": "^0.1.5",
"chart.js": "^3.0.0-rc",
"chart.js": "^3.0.0-rc.2",
"eslint": "^7.22.0",
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint-config-prettier": "^8.1.0",

@@ -91,3 +92,3 @@ "eslint-config-react-app": "^6.0.0",

"prettier": "^2.2.1",
"release-it": "^14.4.1",
"release-it": "^14.5.0",
"rimraf": "^3.0.2",

@@ -106,6 +107,5 @@ "rollup": "^2.42.1",

"compile": "tsc -b tsconfig.c.json",
"compile:types": "tsc -p tsconfig.c.json --emitDeclarationOnly",
"start": "yarn run watch",
"watch": "rollup -c -w",
"build": "rollup -c && yarn run compile:types",
"build": "rollup -c",
"test": "jest --passWithNoTests",

@@ -112,0 +112,0 @@ "test:watch": "jest --passWithNoTests --watch",

@@ -15,2 +15,3 @@ /// <reference types="jest" />

file.onload = () => resolve(Buffer.from(file.result as ArrayBuffer));
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
file.readAsArrayBuffer(b!);

@@ -21,3 +22,3 @@ });

export async function expectMatchSnapshot(canvas: HTMLCanvasElement) {
export async function expectMatchSnapshot(canvas: HTMLCanvasElement): Promise<void> {
const image = await toBuffer(canvas);

@@ -27,2 +28,9 @@ expect(image).toMatchImageSnapshot();

export interface ChartHelper<TYPE extends ChartType, DATA extends unknown[] = DefaultDataPoint<TYPE>, LABEL = string> {
chart: Chart<TYPE, DATA, LABEL>;
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D;
toMatchImageSnapshot(options?: MatchImageSnapshotOptions): Promise<void>;
}
export default function createChart<

@@ -32,3 +40,3 @@ TYPE extends ChartType,

LABEL = string
>(config: ChartConfiguration<TYPE, DATA, LABEL>, width = 800, height = 600) {
>(config: ChartConfiguration<TYPE, DATA, LABEL>, width = 800, height = 600): ChartHelper<TYPE, DATA, LABEL> {
const canvas = document.createElement('canvas');

@@ -38,18 +46,20 @@ canvas.width = width;

defaults.font.family = 'Courier New';
defaults.color = 'transparent';
config.options = Object.assign(
{
responsive: false,
animation: false,
plugins: {
legend: {
display: false,
},
title: {
display: false,
},
// defaults.color = 'transparent';
// eslint-disable-next-line no-param-reassign
config.options = {
responsive: false,
animation: {
duration: 1,
},
plugins: {
legend: {
display: false,
},
title: {
display: false,
},
},
config.options || {}
) as any;
...(config.options || {}),
} as any;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const ctx = canvas.getContext('2d')!;

@@ -56,0 +66,0 @@

@@ -18,3 +18,7 @@ import type { IKDEPoint } from './data';

export function interpolateNumberArray(from: number | number[], to: number | number[], factor: number) {
export function interpolateNumberArray(
from: number | number[],
to: number | number[],
factor: number
): number | null | undefined | (number | null | undefined)[] {
if (typeof from === 'number' && typeof to === 'number') {

@@ -29,3 +33,7 @@ return interpolators.number(from, to, factor);

export function interpolateKdeCoords(from: IKDEPoint[], to: IKDEPoint[], factor: number) {
export function interpolateKdeCoords(
from: IKDEPoint[],
to: IKDEPoint[],
factor: number
): { v: number | null | undefined; estimate: number | null | undefined }[] {
if (Array.isArray(from) && Array.isArray(to)) {

@@ -32,0 +40,0 @@ return to.map((t, i) => ({

@@ -0,1 +1,4 @@

/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { BoxPlotDataPoint } from '../BoxPlotController';
const Months = [

@@ -35,3 +38,3 @@ 'January',

randF(min = 0, max = 1) {
randF(min = 0, max = 1): () => number {
return () => {

@@ -43,10 +46,11 @@ this._seed = (this._seed * 9301 + 49297) % 233280;

rand(min?: number, max?: number) {
rand(min?: number, max?: number): number {
return this.randF(min, max)();
}
months({ count = 12, section }: { count?: number; section?: number }) {
const values = [];
// eslint-disable-next-line class-methods-use-this
months({ count = 12, section }: { count?: number; section?: number }): string[] {
const values: string[] = [];
for (let i = 0; i < count; ++i) {
for (let i = 0; i < count; i += 1) {
const value = Months[Math.ceil(i) % 12];

@@ -73,3 +77,3 @@ values.push(value.substring(0, section));

const rand01 = random01 ? random01() : this.randF();
for (let i = 0; i < count; ++i) {
for (let i = 0; i < count; i += 1) {
const value = (from[i] || 0) + rand();

@@ -86,5 +90,10 @@ if (rand01() <= continuity) {

randomBoxPlot(config: INumberOptions = {}) {
randomBoxPlot(config: INumberOptions = {}): BoxPlotDataPoint {
const base = this.numbers({ ...config, count: 10 }) as number[];
base.sort((a, b) => (a === b ? 0 : a! < b! ? -1 : 1));
base.sort((a, b) => {
if (a === b) {
return 0;
}
return a! < b! ? -1 : 1;
});
const shift = 3;

@@ -103,3 +112,3 @@ return {

boxplots(config: INumberOptions = {}) {
boxplots(config: INumberOptions = {}): BoxPlotDataPoint[] {
const count = config.count || 8;

@@ -111,3 +120,3 @@ return Array(count)

boxplotsArray(config: INumberOptions = {}) {
boxplotsArray(config: INumberOptions = {}): number[][] {
const count = config.count || 8;

@@ -119,2 +128,3 @@ return Array(count)

// eslint-disable-next-line class-methods-use-this
labels({

@@ -126,3 +136,3 @@ min = 0,

prefix = '',
}: { min?: number; max?: number; count?: number; decimals?: number; prefix?: string } = {}) {
}: { min?: number; max?: number; count?: number; decimals?: number; prefix?: string } = {}): string[] {
const step = (max - min) / count;

@@ -129,0 +139,0 @@ const dfactor = Math.pow(10, decimals) || 0;

@@ -0,5 +1,5 @@

import { registry, BarController, LineController, PointElement, BarElement, LineElement } from 'chart.js';
import createChart from '../__tests__/createChart';
import { BoxPlotController, BoxPlotDataPoint } from './BoxPlotController';
import { Samples } from './__tests__/utils';
import { registry, BarController, LineController, PointElement, BarElement, LineElement } from 'chart.js';
import { BoxAndWiskers } from '../elements';

@@ -275,3 +275,3 @@

test('datastructures', () => {
test('data structures', () => {
const chart = createChart({

@@ -278,0 +278,0 @@ type: BoxPlotController.id,

@@ -1,3 +0,2 @@

import { asBoxPlotStats, IBaseStats, IBoxPlot, IBoxplotOptions } from '../data';
import {
import {
Chart,

@@ -15,3 +14,4 @@ BarController,

import { merge } from 'chart.js/helpers';
import { baseDefaults, StatsBase, defaultOverrides } from './base';
import { asBoxPlotStats, IBaseStats, IBoxPlot, IBoxplotOptions } from '../data';
import { baseDefaults, StatsBase, defaultOverrides } from './StatsBase';
import { BoxAndWiskers, IBoxAndWhiskersOptions } from '../elements';

@@ -22,9 +22,12 @@ import patchController from './patchController';

export class BoxPlotController extends StatsBase<IBoxPlot, Required<IBoxplotOptions>> {
protected _parseStats(value: any, config: IBoxplotOptions) {
// eslint-disable-next-line class-methods-use-this
protected _parseStats(value: unknown, config: IBoxplotOptions): IBoxPlot | undefined {
return asBoxPlotStats(value, config);
}
protected _transformStats<T>(target: any, source: IBoxPlot, mapper: (v: number) => T) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
protected _transformStats<T>(target: any, source: IBoxPlot, mapper: (v: number) => T): void {
super._transformStats(target, source, mapper);
for (const key of ['whiskerMin', 'whiskerMax']) {
// eslint-disable-next-line no-param-reassign
target[key] = mapper(source[key as 'whiskerMin' | 'whiskerMax']);

@@ -35,3 +38,4 @@ }

static readonly id = 'boxplot';
static readonly defaults: any = /*#__PURE__*/ merge({}, [
static readonly defaults: any = /* #__PURE__ */ merge({}, [
BarController.defaults,

@@ -52,3 +56,4 @@ baseDefaults(boxOptionsKeys),

]);
static readonly overrides: any = /*#__PURE__*/ merge({}, [(BarController as any).overrides, defaultOverrides()]);
static readonly overrides: any = /* #__PURE__ */ merge({}, [(BarController as any).overrides, defaultOverrides()]);
}

@@ -55,0 +60,0 @@

@@ -0,5 +1,5 @@

import { registry } from 'chart.js';
import createChart from '../__tests__/createChart';
import { ViolinController } from './ViolinController';
import { Samples } from './__tests__/utils';
import { registry } from 'chart.js';
import { Violin } from '../elements';

@@ -6,0 +6,0 @@

@@ -1,3 +0,2 @@

import { asViolinStats, IBaseStats, IViolin, IViolinOptions } from '../data';
import {
import {
Chart,

@@ -15,3 +14,4 @@ BarController,

import { merge } from 'chart.js/helpers';
import { StatsBase, baseDefaults, defaultOverrides } from './base';
import { asViolinStats, IBaseStats, IViolin, IViolinOptions } from '../data';
import { StatsBase, baseDefaults, defaultOverrides } from './StatsBase';
import { baseOptionKeys } from '../elements/base';

@@ -23,11 +23,15 @@ import { IViolinElementOptions, Violin } from '../elements';

export class ViolinController extends StatsBase<IViolin, Required<IViolinOptions>> {
protected _parseStats(value: any, config: IViolinOptions) {
// eslint-disable-next-line class-methods-use-this,@typescript-eslint/explicit-module-boundary-types
protected _parseStats(value: any, config: IViolinOptions): IViolin | undefined {
return asViolinStats(value, config);
}
protected _transformStats<T>(target: any, source: IViolin, mapper: (v: number) => T) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
protected _transformStats<T>(target: any, source: IViolin, mapper: (v: number) => T): void {
super._transformStats(target, source, mapper);
// eslint-disable-next-line no-param-reassign
target.maxEstimate = source.maxEstimate;
if (Array.isArray(source.coords)) {
target.coords = source.coords.map((c) => Object.assign({}, c, { v: mapper(c.v) }));
// eslint-disable-next-line no-param-reassign
target.coords = source.coords.map((c) => ({ ...c, v: mapper(c.v) }));
}

@@ -37,3 +41,4 @@ }

static readonly id = 'violin';
static readonly defaults: any = /*#__PURE__*/ merge({}, [
static readonly defaults: any = /* #__PURE__ */ merge({}, [
BarController.defaults,

@@ -59,3 +64,4 @@ baseDefaults(baseOptionKeys),

]);
static readonly overrides: any = /*#__PURE__*/ merge({}, [(BarController as any).overrides, defaultOverrides()]);
static readonly overrides: any = /* #__PURE__ */ merge({}, [(BarController as any).overrides, defaultOverrides()]);
}

@@ -62,0 +68,0 @@ export type ViolinDataPoint = number[] | (Partial<IViolin> & IBaseStats);

@@ -11,3 +11,4 @@ import boxplots, {

} from '@sgratzl/boxplots';
import { kde } from './kde';
import kde from './kde';
export {

@@ -56,3 +57,7 @@ quantilesFivenum,

*/
export function whiskers(boxplot: IBoxPlot, arr: number[] | null, coef = 1.5) {
export function whiskers(
boxplot: IBoxPlot,
arr: number[] | null,
coef = 1.5
): { whiskerMin: number; whiskerMax: number } {
const iqr = boxplot.q3 - boxplot.q1;

@@ -66,3 +71,3 @@ // since top left is max

// compute the closest real element
for (let i = 0; i < arr.length; i++) {
for (let i = 0; i < arr.length; i += 1) {
const v = arr[i];

@@ -74,3 +79,3 @@ if (v >= whiskerMin) {

}
for (let i = arr.length - 1; i >= 0; i--) {
for (let i = arr.length - 1; i >= 0; i -= 1) {
const v = arr[i];

@@ -238,3 +243,4 @@ if (v <= whiskerMax) {

export function asBoxPlotStats(value: any, options: IBoxplotOptions) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function asBoxPlotStats(value: any, options: IBoxplotOptions): IBoxPlot | undefined {
if (!value) {

@@ -252,3 +258,5 @@ return undefined;

);
// eslint-disable-next-line no-param-reassign
value.whiskerMin = whiskerMin;
// eslint-disable-next-line no-param-reassign
value.whiskerMax = whiskerMax;

@@ -264,3 +272,4 @@ }

export function asViolinStats(value: any, options: IViolinOptions) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function asViolinStats(value: any, options: IViolinOptions): IViolin | undefined {
if (!value) {

@@ -278,3 +287,3 @@ return undefined;

export function rnd(seed = Date.now()) {
export function rnd(seed = Date.now()): () => number {
// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/

@@ -281,0 +290,0 @@ let s = seed;

@@ -213,3 +213,3 @@ import { Element } from 'chart.js';

export const baseOptionKeys = /*#__PURE__*/ (() => Object.keys(baseDefaults).concat(Object.keys(baseRoutes)))();
export const baseOptionKeys = /* #__PURE__ */ (() => Object.keys(baseDefaults).concat(Object.keys(baseRoutes)))();

@@ -228,12 +228,13 @@ export interface IStatsBaseProps {

declare _datasetIndex: number;
declare _index: number;
isVertical() {
isVertical(): boolean {
return this.getProps(['height']).height == null;
}
protected _drawItems(ctx: CanvasRenderingContext2D) {
protected _drawItems(ctx: CanvasRenderingContext2D): void {
const vert = this.isVertical();
const props = this.getProps(['x', 'y', 'items', 'width', 'height', 'outliers']);
const options = this.options;
const { options } = this;

@@ -274,6 +275,6 @@ if (options.itemRadius <= 0 || !props.items || props.items.length <= 0) {

protected _drawOutliers(ctx: CanvasRenderingContext2D) {
protected _drawOutliers(ctx: CanvasRenderingContext2D): void {
const vert = this.isVertical();
const props = this.getProps(['x', 'y', 'outliers']);
const options = this.options;
const { options } = this;
if (options.outlierRadius <= 0 || !props.outliers || props.outliers.length === 0) {

@@ -306,6 +307,6 @@ return;

protected _drawMeanDot(ctx: CanvasRenderingContext2D) {
protected _drawMeanDot(ctx: CanvasRenderingContext2D): void {
const vert = this.isVertical();
const props = this.getProps(['x', 'y', 'mean']);
const options = this.options;
const { options } = this;
if (options.meanRadius <= 0 || props.mean == null || Number.isNaN(props.mean)) {

@@ -334,4 +335,4 @@ return;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
_getBounds(_useFinalPosition?: boolean) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,class-methods-use-this
_getBounds(_useFinalPosition?: boolean): { left: number; top: number; right: number; bottom: number } {
// abstract

@@ -346,3 +347,3 @@ return {

_getHitBounds(useFinalPosition?: boolean) {
_getHitBounds(useFinalPosition?: boolean): { left: number; top: number; right: number; bottom: number } {
const padding = this.options.hitPadding;

@@ -358,3 +359,3 @@ const b = this._getBounds(useFinalPosition);

inRange(mouseX: number, mouseY: number, useFinalPosition?: boolean) {
inRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): boolean {
if (Number.isNaN(this.x) && Number.isNaN(this.y)) {

@@ -369,3 +370,3 @@ return false;

inXRange(mouseX: number, useFinalPosition?: boolean) {
inXRange(mouseX: number, useFinalPosition?: boolean): boolean {
const bounds = this._getHitBounds(useFinalPosition);

@@ -375,3 +376,3 @@ return mouseX >= bounds.left && mouseX <= bounds.right;

inYRange(mouseY: number, useFinalPosition?: boolean) {
inYRange(mouseY: number, useFinalPosition?: boolean): boolean {
const bounds = this._getHitBounds(useFinalPosition);

@@ -381,3 +382,3 @@ return mouseY >= bounds.top && mouseY <= bounds.bottom;

protected _outlierIndexInRange(mouseX: number, mouseY: number, useFinalPosition?: boolean) {
protected _outlierIndexInRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): number {
const props = this.getProps(['x', 'y'], useFinalPosition);

@@ -393,3 +394,3 @@ const hitRadius = this.options.outlierHitRadius;

const toCompare = vertical ? mouseY : mouseX;
for (let i = 0; i < outliers.length; i++) {
for (let i = 0; i < outliers.length; i += 1) {
if (Math.abs(outliers[i] - toCompare) <= hitRadius) {

@@ -402,3 +403,3 @@ return i;

protected _boxInRange(mouseX: number, mouseY: number, useFinalPosition?: boolean) {
protected _boxInRange(mouseX: number, mouseY: number, useFinalPosition?: boolean): boolean {
const bounds = this._getHitBounds(useFinalPosition);

@@ -408,3 +409,3 @@ return mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;

getCenterPoint(useFinalPosition?: boolean) {
getCenterPoint(useFinalPosition?: boolean): { x: number; y: number } {
const props = this.getProps(['x', 'y'], useFinalPosition);

@@ -417,3 +418,3 @@ return {

protected _getOutliers(useFinalPosition?: boolean) {
protected _getOutliers(useFinalPosition?: boolean): number[] {
const props = this.getProps(['outliers'], useFinalPosition);

@@ -423,3 +424,6 @@ return props.outliers || [];

tooltipPosition(eventPosition?: { x: number; y: number } | boolean, tooltip?: ExtendedTooltip) {
tooltipPosition(
eventPosition?: { x: number; y: number } | boolean,
tooltip?: ExtendedTooltip
): { x: number; y: number } {
if (!eventPosition || typeof eventPosition === 'boolean') {

@@ -430,2 +434,3 @@ // fallback

if (tooltip) {
// eslint-disable-next-line no-param-reassign
delete tooltip._tooltipOutlier;

@@ -440,2 +445,3 @@ }

// hack in the data of the hovered outlier
// eslint-disable-next-line no-param-reassign
tooltip._tooltipOutlier = {

@@ -442,0 +448,0 @@ index,

@@ -34,3 +34,3 @@ import { BarElement } from 'chart.js';

export class BoxAndWiskers extends StatsBase<IBoxAndWhiskerProps, IBoxAndWhiskersOptions> {
draw(ctx: CanvasRenderingContext2D) {
draw(ctx: CanvasRenderingContext2D): void {
ctx.save();

@@ -51,3 +51,3 @@

protected _drawBoxPlot(ctx: CanvasRenderingContext2D) {
protected _drawBoxPlot(ctx: CanvasRenderingContext2D): void {
if (this.isVertical()) {

@@ -60,8 +60,8 @@ this._drawBoxPlotVertical(ctx);

protected _drawBoxPlotVertical(ctx: CanvasRenderingContext2D) {
const options = this.options;
protected _drawBoxPlotVertical(ctx: CanvasRenderingContext2D): void {
const { options } = this;
const props = this.getProps(['x', 'width', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const x0 = x - width / 2;

@@ -124,8 +124,8 @@ // Draw the q1>q3 box

protected _drawBoxPlotHorizontal(ctx: CanvasRenderingContext2D) {
const options = this.options;
protected _drawBoxPlotHorizontal(ctx: CanvasRenderingContext2D): void {
const { options } = this;
const props = this.getProps(['y', 'height', 'q1', 'q3', 'median', 'whiskerMin', 'whiskerMax']);
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const y0 = y - height / 2;

@@ -185,3 +185,3 @@

_getBounds(useFinalPosition?: boolean) {
_getBounds(useFinalPosition?: boolean): { left: number; top: number; right: number; bottom: number } {
const vert = this.isVertical();

@@ -224,7 +224,11 @@ if (this.x == null) {

static id = 'boxandwhiskers';
static defaults = /*#__PURE__*/ Object.assign({}, BarElement.defaults, baseDefaults, {
static defaults = /* #__PURE__ */ {
...BarElement.defaults,
...baseDefaults,
medianColor: 'transparent',
lowerBackgroundColor: 'transparent',
});
static defaultRoutes = /*#__PURE__*/ Object.assign({}, BarElement.defaultRoutes, baseRoutes);
};
static defaultRoutes = /* #__PURE__ */ { ...BarElement.defaultRoutes, ...baseRoutes };
}

@@ -16,3 +16,3 @@ import { BarElement } from 'chart.js';

export class Violin extends StatsBase<IViolinElementProps, IViolinElementOptions> {
draw(ctx: CanvasRenderingContext2D) {
draw(ctx: CanvasRenderingContext2D): void {
ctx.save();

@@ -48,7 +48,7 @@

protected _drawCoords(ctx: CanvasRenderingContext2D, props: IViolinElementProps) {
protected _drawCoords(ctx: CanvasRenderingContext2D, props: IViolinElementProps): void {
ctx.beginPath();
if (this.isVertical()) {
const x = props.x;
const width = props.width;
const { x } = props;
const { width } = props;
const factor = width / 2 / props.maxEstimate;

@@ -66,4 +66,4 @@ ctx.moveTo(x, props.min);

} else {
const y = props.y;
const height = props.height;
const { y } = props;
const { height } = props;
const factor = height / 2 / props.maxEstimate;

@@ -86,3 +86,3 @@ ctx.moveTo(props.min, y);

_getBounds(useFinalPosition?: boolean) {
_getBounds(useFinalPosition?: boolean): { left: number; top: number; right: number; bottom: number } {
if (this.isVertical()) {

@@ -109,4 +109,6 @@ const { x, width, min, max } = this.getProps(['x', 'width', 'min', 'max'], useFinalPosition);

static id = 'violin';
static defaults = /*#__PURE__*/ Object.assign({}, BarElement.defaults, baseDefaults);
static defaultRoutes = /*#__PURE__*/ Object.assign({}, BarElement.defaultRoutes, baseRoutes);
static defaults = /* #__PURE__ */ { ...BarElement.defaults, ...baseDefaults };
static defaultRoutes = /* #__PURE__ */ { ...BarElement.defaultRoutes, ...baseRoutes };
}

@@ -25,3 +25,3 @@ // See <http://en.wikipedia.org/wiki/Kernel_(statistics)>.

const m = mean(x);
return x.reduce((acc, x) => acc + (x - m) * (x - m), 0) / (x.length - 1);
return x.reduce((acc, xi) => acc + (xi - m) * (xi - m), 0) / (x.length - 1);
}

@@ -35,3 +35,7 @@

export function kde(points: number[], sample: number[], quantiles: (x: number[]) => { q1: number; q3: number }) {
export default function kde(
points: number[],
sample: number[],
quantiles: (x: number[]) => { q1: number; q3: number }
): { v: number; estimate: number }[] {
const bw = nrd(sample, quantiles);

@@ -38,0 +42,0 @@

@@ -13,3 +13,3 @@ import { InteractionItem, TooltipItem, Tooltip, TooltipModel } from 'chart.js';

item: TooltipItem<'boxplot' | 'violin'>
) {
): void {
const value = item.formattedValue as any;

@@ -27,3 +27,3 @@ const that = this as ExtendedTooltip;

eventPosition: { x: number; y: number }
) {
): false | { x: number; y: number } {
if (!items.length) {

@@ -35,3 +35,3 @@ return false;

let count = 0;
for (let i = 0; i < items.length; ++i) {
for (let i = 0; i < items.length; i += 1) {
const el = items[i].element;

@@ -42,3 +42,3 @@ if (el && el.hasValue()) {

y += pos.y;
++count;
count += 1;
}

@@ -45,0 +45,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc