downsample
Version:
Provides functions for time series data downsampling for visual representation
298 lines (218 loc) • 10.7 kB
Markdown
<h1 align="center">
downsample
</h1>
<p align="center">
Downsampling methods for time series visualisation.
</p>
<!-- The badges section -->
<p align="center">
<!-- Travis CI build status -->
<a href="https://travis-ci.org/janjakubnanista/downsample"><img alt="Build Status" src="https://travis-ci.org/janjakubnanista/downsample.svg?branch=master"/></a>
<!-- Fury.io NPM published package version -->
<a href="https://www.npmjs.com/package/downsample"><img alt="NPM Version" src="https://badge.fury.io/js/downsample.svg"/></a>
<!-- Shields.io dev dependencies status -->
<a href="https://github.com/janjakubnanista/downsample/blob/master/package.json"><img alt="Dev Dependency Status" src="https://img.shields.io/david/dev/janjakubnanista/downsample"/></a>
<!-- Snyk.io vulnerabilities badge -->
<a href="https://snyk.io/test/github/janjakubnanista/downsample"><img alt="Known Vulnerabilities" src="https://snyk.io/test/github/janjakubnanista/downsample/badge.svg"/></a>
<!-- Shields.io license badge -->
<a href="https://github.com/janjakubnanista/downsample/blob/master/LICENSE"><img alt="License" src="https://img.shields.io/npm/l/downsample"/></a>
</p>
<p align="center">
<a href="#installation">Installation</a>
<span>|</span>
<a href="#usage">Usage</a>
<span>|</span>
<a href="#api">API</a>
<span>|</span>
<a href="#demo">Demo</a>
<span>|</span>
<a href="#acknowledgement">Acknowledgement</a>
</p>
`downsample` is useful when, not extremely surprisingly, you need to downsample a numeric time series before visualizing it without losing the visual characteristics of the data.
<a id="installation"></a>
## Installation
[downsample](https://www.npmjs.com/package/downsample) is an NPM module. You can easily download it by typing something like the following in your project:
```bash
# for all the npm people out there
npm install downsample
# or if you are a fan of yarn
yarn add downsample
```
<a id="usage"></a>
## Usage
The package exports several methods for data downsampling:
- **ASAP** Automatic Smoothing for Attention Prioritization [read more here](http://futuredata.stanford.edu/asap/)
- **SMA** Simple moving average [read more here](https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average)
- **LTTB** Largest triangle three buckets [read more here](https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf)
- **LTOB** Largest triangle one bucket [read more here](https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf)
- **LTD** Largest triangle dynamic [read more here](https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf)
You can read more about the details of these in the [API](#api) section below.
<a id="api"></a>
## API
<a id="api/ASAP"></a>
### `ASAP` :boom: *new in 1.2.0* :boom:
Automatic Smoothing for Attention Prioritization ([read more here](http://futuredata.stanford.edu/asap/)) is a smoothing rather than downsampling method - it will remove the short-term noise and reveal the large-scale deviations.
`ASAP` accepts an array of data points (see [DataPoint](#api/DataPoint)) or a `TypedArray` (see [TypedArray support](#api/TypedArray)) and a target resolution (number of output data points) as arguments. It will always return the points in `XYDataPoint` format. [See advanced API if you need to work with a custom data type](#api/createASAP).
```typescript
function ASAP(data: DataPoint[], targetResolution: number): XYDataPoint[]
```
```typescript
import { ASAP } from 'downsample';
// Or if your codebase does not supprot tree-shaking
import { ASAP } from 'downsample/methods/ASAP';
const chartWidth = 1000;
const smooth = ASAP([
[0, 1000],
[1, 1243],
// ...
], chartWidth);
```
<a id="api/SMA"></a>
### `SMA` :boom: *new in 1.2.0* :boom:
Simple moving average with variable slide ([read more here](https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average)).
`SMA` accepts an array of data points (see [DataPoint](#api/DataPoint)) or a `TypedArray` (see [TypedArray support](#api/TypedArray)), size of a window over which to calculate average and a slide - an amount by which the window is shifted. It will always return the points in `XYDataPoint` format. [See advanced API if you need to work with a custom data type](#api/createSMA).
```typescript
function SMA(data: DataPoint[], windowSize: number, slide?: number = 1): XYDataPoint[]
```
```typescript
import { SMA } from 'downsample';
// Or if your codebase does not supprot tree-shaking
import { SMA } from 'downsample/methods/SMA';
const chartWidth = 1000;
const smooth = SMA([
[0, 1000],
[1, 1243],
// ...
], chartWidth);
```
<a id="api/LTTB"></a>
### `LTTB`
Largest triangle three buckets ([read more here](https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf)). If you are looking for the best performing downsampling method then look no more!
```typescript
function LTTB(data: DataPoint[], targetResolution: number): DataPoint[]
```
`LTTB` accepts an array of data points (see [DataPoint](#api/DataPoint)) or a `TypedArray` (see [TypedArray support](#api/TypedArray)) and a target resolution (number of output data points) as arguments. [See advanced API if you need to work with a custom data type](#api/createLTTB).
The format of the data will be preserved, i.e. if passing an array of `[number, number]` data points as `data`, you will get an array of `[number, number]` on the output.
```typescript
import { LTTB } from 'downsample';
// Or if your codebase does not supprot tree-shaking
import { LTTB } from 'downsample/methods/LTTB';
const chartWidth = 1000;
const downsampled = LTTB([
[0, 1000],
[1, 1243],
// ...
], chartWidth);
```
<a id="api/LTOB"></a>
### `LTOB`
Largest triangle one bucket ([read more here](https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf)). Performs only slightly worse than LTTB.
```typescript
function LTOB(data: DataPoint[], targetResolution: number): DataPoint[]
```
`LTOB` accepts an array of data points (see [DataPoint](#api/DataPoint)) or a `TypedArray` (see [TypedArray support](#api/TypedArray)) and a target resolution (number of output data points) as arguments. [See advanced API if you need to work with a custom data type](#api/createLTOB).
The format of the data will be preserved, i.e. if passing an array of `[number, number]` data points as `data`, you will get an array of `[number, number]` on the output.
```typescript
import { LTOB } from 'downsample';
// Or if your codebase does not supprot tree-shaking
import { LTOB } from 'downsample/methods/LTOB';
const chartWidth = 1000;
const downsampled = LTOB([
[0, 1000],
[1, 1243],
// ...
], chartWidth);
```
<a id="api/LTD"></a>
### `LTD`
Largest triangle dynamic ([read more here](https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf)). The simplest downsampling method.
```typescript
function LTD(data: DataPoint[], targetResolution: number): DataPoint[]
```
`LTD` accepts an array of data points (see [DataPoint](#api/DataPoint)) or a `TypedArray` (see [TypedArray support](#api/TypedArray)) and a target resolution (number of output data points) as arguments. [See advanced API if you need to work with a custom data type](#api/createLTD).
The format of the data will be preserved, i.e. if passing an array of `[number, number]` data points as `data`, you will get an array of `[number, number]` on the output.
```typescript
import { LTD } from 'downsample';
// Or if your codebase does not supprot tree-shaking
import { LTD } from 'downsample/methods/LTD';
const chartWidth = 1000;
const downsampled = LTD([
[0, 1000],
[1, 1243],
// ...
], chartWidth);
```
<a id="api/DataPoint"></a>
### `DataPoint` type
Represents a data point in the input data array. These formats are currently supported:
```typescript
type DataPoint =
[number, number] |
[Date, number] |
{ x: number; y: number } |
{ x: Date; y: number } |
```
<a id="api/TypedArray"></a>
### `TypedArray` support
It is now possible to pass `TypedArray` data to downsampling functions. The returned type will then match the input type, e.g. if `Int16Array` is passed in, the result will be a `Int16Array`:
```typescript
const input: Int16Array = new Int16Array(...);
const result: Int16Array = LTD(input, 1000);
```
## Advanced API
All the functions above work with `DataPoint` objects as a reasonable default. If however this does not fit your needs you can create your own version of a function using a downsampling function factory.
<a id="api/createASAP"></a>
### `createASAP`
Creates an [ASAP](#api/ASAP) smoothing function for a specific point data type `P`.
```typescript
function createASAP({
x: string | number | (point: P) => number,
y: string | number | (point: P) => number,
toPoint: (x: number, y: number) => P
}): ASAP;
```
<a id="api/createSMA"></a>
### `createSMA`
Creates a [SMA](#api/SMA) smoothing function for a specific point data type `P`.
```typescript
function createSMA({
x: string | number | (point: P) => number,
y: string | number | (point: P) => number,
toPoint: (x: number, y: number) => P
}): SMA;
```
<a id="api/createLTD"></a>
### `createLTD`
Creates an [LTD](#api/LTD) downsampling function for a specific point data type `P`.
```typescript
function createLTD({
x: string | number | (point: P) => number,
y: string | number | (point: P) => number
}): LTD;
```
<a id="api/createLTOB"></a>
### `createLTOB`
Creates an [LTOB](#api/LTOB) downsampling function for a specific point data type `P`.
```typescript
function createLTOB({
x: string | number | (point: P) => number,
y: string | number | (point: P) => number
}): LTOB;
```
<a id="api/createLTTB"></a>
### `createLTTB`
Creates an [LTTB](#api/LTTB) downsampling function for a specific point data type `P`.
```typescript
function createLTTB({
x: string | number | (point: P) => number,
y: string | number | (point: P) => number
}): LTTB;
```
<a id="demo"></a>
## Demo
There is a very minimal interactive demo app available if you want to play around with the results of downsampling. [Check it out here](https://janjakubnanista.github.io/downsample/).
<a id="acknowledgement"></a>
## Acknowledgement
The implementation of `LTD`, `LTOB` and `LTTB` is based on Sveinn Steinarsson's 2013 paper _Downsampling Time Series for
Visual Representation_ that can be found [here](https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf).
The implementation of `ASAP` is based on Kexin Rong's and Peter Bailis's 2017 paper. _ASAP: Prioritizing Attention via Time Series Smoothing_ that can be found [here](https://arxiv.org/pdf/1703.00983.pdf). The original code can be found [here](https://github.com/stanford-futuredata/ASAP/blob/master/ASAP-optimized.js)