{"id":18376821,"url":"https://github.com/bbc/slayer","last_synced_at":"2025-04-05T11:13:13.607Z","repository":{"id":17922564,"uuid":"20891880","full_name":"bbc/slayer","owner":"bbc","description":"JavaScript time series spike detection for Node.js and the browser; like the Octave findpeaks function.","archived":false,"fork":false,"pushed_at":"2024-11-27T15:12:03.000Z","size":54,"stargazers_count":79,"open_issues_count":6,"forks_count":16,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-03-29T10:07:36.472Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://npmjs.org/slayer","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bbc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-06-16T16:25:31.000Z","updated_at":"2025-03-04T10:54:28.000Z","dependencies_parsed_at":"2025-01-31T20:30:41.464Z","dependency_job_id":null,"html_url":"https://github.com/bbc/slayer","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbc%2Fslayer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbc%2Fslayer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbc%2Fslayer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbc%2Fslayer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bbc","download_url":"https://codeload.github.com/bbc/slayer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247024144,"owners_count":20870939,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T00:24:52.555Z","updated_at":"2025-04-05T11:13:13.579Z","avatar_url":"https://github.com/bbc.png","language":"JavaScript","readme":"# Slayer [![Build Status](https://secure.travis-ci.org/bbc/slayer.png?branch=master)](http://travis-ci.org/bbc/slayer.js)\n\n\u003e JavaScript time series spike detection for Node.js; like the Octave [findpeaks](http://www.mathworks.co.uk/help/signal/ref/findpeaks.html) function.\n\nTime series are often displayed as bar, line or area charts.\nA _peak_ or _spike_ in a time series is a the highest value before the trend start to decrease.\n\nIn reality you do not need all the spikes. You only need **the highest spike amongst them**.\n_Slayer_ helps to identify these local peaks easily.\n\n[![](chart.png?raw=1)](http://blogs.sas.com/content/iml/2013/08/28/finite-diff-estimate-maxi/)\n\n# Install\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003enpm\u003c/th\u003e\n      \u003cth\u003ebower\u003c/th\u003e\n      \u003cth\u003eold school\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003ccode\u003enpm install --save slayer\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003e-\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/bbc/slayer/archive/master.zip\"\u003edownload zip file\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n# Usage\n\n_Slayer_ exposes a fluent JavaScript API and requires as little configuration as possible.\nThe following examples illustrates common use cases.\n\n## Flat array peak detection\n\n```js\nvar slayer = require('slayer');\nvar arrayData = [0, 0, 0, 12, 0, …];\n\nslayer().fromArray(arrayData).then(spikes =\u003e {\n  console.log(spikes);      // [ { x: 4, y: 12 }, { x: 12, y: 25 } ]\n});\n```\n\n## Object based peak detection\n\n```js\nvar slayer = require('slayer');\nvar arrayData = […, { date: '…', value: 12 }, …];\n\nslayer()\n  .y(item =\u003e item.value)\n  .fromArray(arrayData)\n  .then(spikes =\u003e {\n    console.log(spikes);    // [ { x: 4, y: 12 }, { x: 12, y: 25 } ]\n  });\n```\n\n## Streaming detection\n\n```js\nsomeStream\n  .pipe(slayer().createReadStream())\n  .on('error', err =\u003e console.error(err))\n  .on('data', spike =\u003e {\n    console.log(spike);      // { x: 4, y: 12 }\n  });\n```\n\n\n# API\n\nAccess the _Slayer_ API by requiring the CommonJS module:\n\n```js\nvar slayer = require('slayer');\n```\n\nA _spike_ object is an object composed of two keys:\n\n- `x`: the index value within the time series array;\n- `y`: the spike value within the time series array.\n\n## `slayer(config)`\n\nThe `slayer()` factory returns a new chainable instance of _Slayer_.\n\nThe optional `config` object enables you to adjust its behaviour according to your needs:\n\n- `minPeakDistance` (_Integer_): size of the values overlooked window. _Default is `30`_;\n- `minPeakHeight` (_Number_): discard any value below that threshold. _Default is `0`_.\n\nReturns a `slayer` chainable object.\n\n## `.y(fn)`\n\nData accessor applied to each series item and used to determine spike values.\n\nIt will return this value as the `y` value of a spike object.\n\n```js\nslayer()\n  .y(item =\u003e item.value)   // considering item looks like `{ value: 12 }`\n  .fromArray(arrayData)\n  .then(spikes =\u003e {\n    console.log(spikes);   // { x: 4, y: 12 }\n  });\n```\n\nReturns a mutated `slayer` chainable object.\n\n## `.x(fn)`\n\nIndex accessor applied to each series item.\n\nIt will return this value as the `x` value of a spike object.\n\n```js\nslayer()\n  .x((item, i) =\u003e item.date)  // considering item looks like `{ date: '2014-04-12T17:31:40.000Z', value: 12 }`\n  .fromArray(arrayData)\n  .then(spikes =\u003e {\n    console.log(spikes);      // { x: '2014-04-12T17:31:40.000Z', y: 12 }\n  });\n```\n\nReturns a mutated `slayer` chainable object.\n\n## `.transform(fn)`\n\nTransforms the spike object before returning it as part of the found spike collections.\n\nIt is useful if you want to add extra data to the returned spike object.\n\n```js\nslayer()\n  .transform((xyItem, originalItem, i) =\u003e {\n    xyItem.id = originalItem.id;\n\n    return xyItem;\n  })\n  .fromArray(arrayData)\n  .then(spikes =\u003e {\n    console.log(spikes);   // { x: 4, y: 12, id: '21232f297a57a5a743894a0e4a801fc3' }\n  });\n```\n\nReturns a mutated `slayer` chainable object.\n\n## `.fromArray(data)`\n\nProcesses a finite array of data and returns them at once.\n\n```js\nslayer()\n  .fromArray(arrayData)\n  .then(spikes =\u003e {\n\n    console.log(spikes);   // { x: 4, y: 12, id: '21232f297a57a5a743894a0e4a801fc3' }\n  });\n```\n\nReturns an [ES2015 `Promise` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).\n\n## `.createReadStream(options)`\n\nProcesses a stream of data and emits a `data` event each time a spike is found.\nAlthough you might notice a slight delay as *spike deduplication* happens under the hood.\n\nYou can optionally pass an `options` object to tweak and adjust the precision of the analysis:\n\n- `bufferingFactor` (_Number_): buffer ratio of the sliding window, against `minPeakDistance`. _Default is `4`_;\n- `lookAheadFactor` (_Number_): additional buffer ratio to look ahead, against the sliding window size. _Default is `0.33`_.\n\nWith this setup, `slayer` will buffer *4 times* the amount of `minPeakDistance` with an additional *0.33 times* before performing an analysis before moving from *4 times* the amount of `minPeakDistance`.\n\nThe following example demonstrates the streaming analysis of a file containing single values on each row of the document:\n\n```js\nvar split = require('split');\n\nfs.createReadStream('./big-big-data.txt')\n  .pipe(split())\n  .pipe(slayer().createReadStream())\n  .on('data', spike =\u003e console.log(spike));\n```\n\nReturns a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable).\n\n# Contributing and testing\n\nIf you wish to contribute the project with code but you fear to break something, no worries as [TravisCI](https://travis-ci.org/bbc/slayer)\ntakes care of this for each Pull Request.\n\nNobody will blame your code. And feel free to ask _before_ making a pull request.\nWe will try to provide you guidance for code design etc.\n\nIf you want to run the tests locally, simply run:\n\n```bash\nnpm test\n```\n\nIf you want to run them continuously, then run:\n\n```bash\nnpm test -- --watch\n```\n\n# Licence\n\n\u003e Copyright 2016 British Broadcasting Corporation\n\u003e\n\u003e Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at\n\u003e\n\u003e http://www.apache.org/licenses/LICENSE-2.0\n\u003e\n\u003e Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbc%2Fslayer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbbc%2Fslayer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbc%2Fslayer/lists"}