Skip to content

Commit

Permalink
update README
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed May 18, 2020
1 parent c8ce80d commit 54176fc
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 93 deletions.
235 changes: 149 additions & 86 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,57 +27,71 @@ four new types: `boxplot`, `horizontalBoxplot`, `violin`, and `horizontalViolin`

## Config

// TODO
The config can be done on a per dataset `.data.datasets[0].minStats` or for all datasets under the controllers name. e.g., `.options.boxplot.datasets.minStats`.

```ts
interface IBaseOptions {
/**
* statistic measure that should be used for computing the minimal data limit
* @default 'min'
*/
minStats: 'min' | 'q1' | 'whiskerMin';

/**
* statistic measure that should be used for computing the maximal data limit
* @default 'max'
*/
maxStats: 'max' | 'q3' | 'whiskerMax';

/**
* from the R doc: this determines how far the plot ‘whiskers’ extend out from
* the box. If coef is positive, the whiskers extend to the most extreme data
* point which is no more than coef times the length of the box away from the
* box. A value of zero causes the whiskers to extend to the data extremes
* @default 1.5
*/
coef: number;

/**
* the method to compute the quantiles.
*
* 7, 'quantiles': the type-7 method as used by R 'quantiles' method.
* 'hinges' and 'fivenum': the method used by R 'boxplot.stats' method.
* 'linear': the interpolation method 'linear' as used by 'numpy.percentile' function
* 'lower': the interpolation method 'lower' as used by 'numpy.percentile' function
* 'higher': the interpolation method 'higher' as used by 'numpy.percentile' function
* 'nearest': the interpolation method 'nearest' as used by 'numpy.percentile' function
* 'midpoint': the interpolation method 'midpoint' as used by 'numpy.percentile' function
* @default 7
*/
quantiles:
| 7
| 'quantiles'
| 'hinges'
| 'fivenum'
| 'linear'
| 'lower'
| 'higher'
| 'nearest'
| 'midpoint'
| ((sortedArr: number[]) => { min: number; q1: number; median: number; q3: number; max: number });
}

interface IBoxplotOptions extends IBaseOptions {
// no extra options
}

interface IViolinOptions extends IBaseOptions {
/**
* number of points that should be samples of the KDE
* @default 100
*/
points: number;
}

```typescript
interface IChartJSOptions {
boxplot: {
datasets: {
/**
* statistic measure that should be used for computing the minimal data limit
* @default 'min'
*/
minStats: 'min' | 'q1' | 'whiskerMin';

/**
* statistic measure that should be used for computing the maximal data limit
* @default 'max'
*/
maxStats: 'max' | 'q3' | 'whiskerMax';

/**
* from the R doc: this determines how far the plot ‘whiskers’ extend out from
* the box. If coef is positive, the whiskers extend to the most extreme data
* point which is no more than coef times the length of the box away from the
* box. A value of zero causes the whiskers to extend to the data extremes
* @default 1.5
*/
coef: number;

/**
* the method to compute the quantiles.
*
* 7, 'quantiles': the type-7 method as used by R 'quantiles' method.
* 'hinges' and 'fivenum': the method used by R 'boxplot.stats' method.
* 'linear': the interpolation method 'linear' as used by 'numpy.percentile' function
* 'lower': the interpolation method 'lower' as used by 'numpy.percentile' function
* 'higher': the interpolation method 'higher' as used by 'numpy.percentile' function
* 'nearest': the interpolation method 'nearest' as used by 'numpy.percentile' function
* 'midpoint': the interpolation method 'midpoint' as used by 'numpy.percentile' function
* @default 7
*/
quantiles:
| 7
| 'quantiles'
| 'hinges'
| 'fivenum'
| 'linear'
| 'lower'
| 'higher'
| 'nearest'
| 'midpoint'
| ((sortedArr: number[]) => { min: number; q1: number; median: number; q3: number; max: number });
};
datasets: {};
};
}
```
Expand All @@ -86,7 +100,7 @@ interface IChartJSOptions {

The boxplot element is called `boxandwhiskers`. The basic options are from the `rectangle` element. The violin element is called `violin` also based on the `rectangle` element.

```typescript
```ts
interface IBaseStyling {
/**
* @default see rectangle
Expand All @@ -103,18 +117,27 @@ interface IBaseStyling {
borderColor: string;

/**
* @default null takes the current borderColor
* @default 1
* @scriptable
* @indexable
*/
medianColor: string;
borderWidth: number;

/**
* @default 1
* @scriptable
* @indexable
* item style used to render outliers
* @default circle
*/
borderWidth: number;
outlierStyle:
| 'circle'
| 'triangle'
| 'rect'
| 'rectRounded'
| 'rectRot'
| 'cross'
| 'crossRot'
| 'star'
| 'line'
| 'dash';

/**
* radius used to render outliers
Expand All @@ -132,20 +155,17 @@ interface IBaseStyling {
outlierBackgroundColor: string;

/**
* to fill color below the median line of the box
* @default transparent
* @default see rectangle.borderColor
* @scriptable
* @indexable
*/
lowerBackgroundColor: string;

outlierBorderColor: string;
/**
* radius used to render items
* @default 0 so disabled
* @default 1
* @scriptable
* @indexable
*/
itemRadius: number;
outlierBorderWidth: number;

/**
* item style used to render items
Expand All @@ -163,25 +183,41 @@ interface IBaseStyling {
| 'line'
| 'dash';

/**
* radius used to render items
* @default 0 so disabled
* @scriptable
* @indexable
*/
itemRadius: number;

/**
* background color for items
* @default see rectangle backgroundColor
* @default see rectangle.backgroundColor
* @scriptable
* @indexable
*/
itemBackgroundColor: string;

/**
* border color for items
* @default see rectangle backgroundColor
* @default see rectangle.borderColor
* @scriptable
* @indexable
*/
itemBorderColor: string;

/**
* border width for items
* @default 0
* @scriptable
* @indexable
*/
itemBorderColor: number;

/**
* padding that is added around the bounding box when computing a mouse hit
* @default 1
* @default 2
* @scriptable
* @indexable
*/
Expand All @@ -197,23 +233,33 @@ interface IBaseStyling {
}

interface IBoxPlotStyling extends IBaseStyling {
// no extra styling options
}
/**
* separate color for the median line
* @default 'transparent' takes the current borderColor
* @scriptable
* @indexable
*/
medianColor: string;

interface IViolinStyling extends IBaseStyling {
/**
* number of sample points of the underlying KDE for creating the violin plot
* @default 100
* color the lower half (median-q3) of the box in a different color
* @default 'transparent' takes the current borderColor
* @scriptable
* @indexable
*/
points: number;
lowerBackgroundColor: string;
}

interface IViolinElementStyling extends IBaseStyling {
// no extras
}
```

## Data structure

Both types support that the data is given as an array of numbers `number[]`. The statistics will be automatically computed. In addition, specific summary data structures are supported:

```typescript
```ts
interface IBaseItem {
min: number;
median: number;
Expand Down Expand Up @@ -256,24 +302,36 @@ interface IViolinItem extends IBaseItem {

## Tooltips

In order to simplify the customization of the tooltips,
// TODO

```js
arr = {
options: {
tooltips: {
callbacks: {
// TODO
},
},
},
};
In order to simplify the customization of the tooltips the tooltip item given to the tooltip callbacks was improved. The default `toString()` behavior should be fine in most cases. The tooltip item has the following structure:

```ts
interface ITooltipItem {
label: string; // original
value: {
raw: IBoxPlotItem | IViolinItem;
/**
* in case an outlier is hovered this will contains its index
* @default -1
*/
hoveredOutlierRadius: number;
/**
* toString function with a proper default implementation, which is used implicitly
*/
toString(): string;

min: string;
median: string;
max: string;
items?: string[];

//... the formatted version of different attributes IBoxPlotItem or ViolinItem
};
}
```

### ESM and Tree Shaking

The ESM build of the library supports three shaking but having no side effects. As a consequence the chart.js library won't be automatically manipulated nor new controllers automatically registered. One has to manually import and register them.
The ESM build of the library supports tree shaking thus having no side effects. As a consequence the chart.js library won't be automatically manipulated nor new controllers automatically registered. One has to manually import and register them.

```js
import Chart from 'chart.js';
Expand All @@ -282,6 +340,11 @@ import { BoxPlot } from '@sgratzl/chartjs-chart-boxplot';
// register controller in chart.js and ensure the defaults are set
BoxPlot.register();
...

new Chart(ctx, {
type: BoxPlot.id,
data: [...],
});
```

## Development Environment
Expand Down
3 changes: 1 addition & 2 deletions src/elements/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export const baseDefaults = Object.assign({}, defaults.elements.rectangle, {
outlierBackgroundColor: defaults.elements.rectangle.backgroundColor,
outlierBorderColor: defaults.elements.rectangle.borderColor,
outlierBorderWidth: 1,
outlierHitRadius: 4,

itemStyle: 'circle',
itemRadius: 0,
Expand All @@ -18,6 +17,7 @@ export const baseDefaults = Object.assign({}, defaults.elements.rectangle, {
itemBorderWidth: 0,

hitPadding: 2,
outlierHitRadius: 4,
});

export const baseOptionKeys = [
Expand Down Expand Up @@ -55,7 +55,6 @@ export class StatsBase extends Element {
ctx.lineWith = options.itemBorderWidth;
// jitter based on random data
// use the dataset index and index to initialize the random number generator
// TODO
const random = rnd(this._datasetIndex * 1000 + this._index);

const pointOptions = {
Expand Down
4 changes: 2 additions & 2 deletions src/elements/boxandwhiskers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defaults } from 'chart.js';
import { StatsBase, baseDefaults, baseOptionKeys } from './base';

export const boxOptionsKeys = baseOptionKeys.concat(['medianColor', 'lowerColor']);
export const boxOptionsKeys = baseOptionKeys.concat(['medianColor', 'lowerBackgroundColor']);

export class BoxAndWiskers extends StatsBase {
draw(ctx) {
Expand Down Expand Up @@ -198,7 +198,7 @@ export class BoxAndWiskers extends StatsBase {
}
}

BoxAndWiskers._type = 'boxAndWhiskers';
BoxAndWiskers._type = 'boxandwhiskers';
BoxAndWiskers.register = () => {
defaults.set('elements', {
[BoxAndWiskers._type]: Object.assign({}, baseDefaults, {
Expand Down
4 changes: 1 addition & 3 deletions src/elements/violin.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ export class ViolinElement extends StatsBase {
ViolinElement._type = 'violin';
ViolinElement.register = () => {
defaults.set('elements', {
[ViolinElement._type]: Object.assign({}, baseDefaults, {
points: 100,
}),
[ViolinElement._type]: baseDefaults,
});
return ViolinElement;
};

0 comments on commit 54176fc

Please sign in to comment.