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

d3-scale-cluster

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

d3-scale-cluster - npm Package Compare versions

Comparing version 1.1.7 to 1.2.0

.eslintrc.js

4

CHANGELOG.md
# Changelog
### 1.2.0
* Add helpers for computation in web worker (thanks @furstenheim-geoblink)
### 1.1.7

@@ -4,0 +8,0 @@

2

dist/d3-scale-cluster.min.js

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

!function(r,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("d3scaleCluster",[],t):"object"==typeof exports?exports.d3scaleCluster=t():r.d3scaleCluster=t()}(this,function(){return function(r){function t(e){if(n[e])return n[e].exports;var o=n[e]={exports:{},id:e,loaded:!1};return r[e].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=r,t.c=n,t.p="",t(0)}([function(r,t,n){function e(){function r(){if(!(a.length<=2)){t=o(n,Math.min(n.length,a.length)),u=[];for(var r=0;r<t.length;r++)u.push(t[r][0])}}var t=[],n=[],a=[],u=[],f=function(r){if(0!==t.length){for(var n=u.length-1;n>=0;n--)if(r>=u[n])return a[n];return a[0]}};return f.domain=function(){return arguments.length?(n=arguments[0],r(),f):n},f.range=function(){if(arguments.length){var t=arguments[0],n=t.length!==a.length;return a=t,n&&r(),f}return a},f.invertExtent=function(r){for(var t=NaN,n=NaN,e=0;e<a.length;e++)if(a[e]===r){t=u[e],n=e+1<a.length?u[e+1]:NaN;break}return[t,n]},f.clusters=function(){return u.slice(1)},f.copy=function(){return e().domain(n).range(a)},f}var o=n(1);"object"==typeof d3&&(d3.scaleCluster=e),r.exports=e},function(r,t){function n(r){return r.slice().sort(function(r,t){return r-t})}function e(r){for(var t,n=0,e=0;e<r.length;e++)0!==e&&r[e]===t||(t=r[e],n++);return n}function o(r,t){for(var n=[],e=0;e<r;e++){for(var o=[],a=0;a<t;a++)o.push(0);n.push(o)}return n}function a(r,t,n,e){var o;if(r>0){var a=(n[t]-n[r-1])/(t-r+1);o=e[t]-e[r-1]-(t-r+1)*a*a}else o=e[t]-n[t]*n[t]/(t+1);return o<0?0:o}function u(r,t,n,e,o,f,i){if(!(r>t)){var l=Math.floor((r+t)/2);e[n][l]=e[n-1][l-1],o[n][l]=l;var c=n;r>n&&(c=Math.max(c,o[n][r-1]||0)),c=Math.max(c,o[n-1][l]||0);var h=l-1;t<e.length-1&&(h=Math.min(h,o[n][t+1]||0));for(var s,v,g,p,d=h;d>=c&&(s=a(d,l,f,i),!(s+e[n-1][c-1]>=e[n][l]));--d)v=a(c,l,f,i),g=v+e[n-1][c-1],g<e[n][l]&&(e[n][l]=g,o[n][l]=c),c++,p=s+e[n-1][d-1],p<e[n][l]&&(e[n][l]=p,o[n][l]=d);u(r,l-1,n,e,o,f,i),u(l+1,t,n,e,o,f,i)}}function f(r,t,n){for(var e=t[0].length,o=new Array(e),f=new Array(e),i=r[Math.floor(e/2)],l=0;l<e;++l)0===l?(o[0]=r[0]-i,f[0]=(r[0]-i)*(r[0]-i)):(o[l]=o[l-1]+r[l]-i,f[l]=f[l-1]+(r[l]-i)*(r[l]-i)),t[0][l]=a(0,l,o,f),n[0][l]=0;for(var c,h=1;h<t.length;++h)c=h<t.length-1?h:e-1,u(c,e-1,h,t,n,o,f)}function i(r,t){if(t>r.length)throw new Error("Cannot generate more classes than there are data values");var a=r.length,u=n(r),i=e(u);if(1===i)return[u];t=Math.min(i,t);var l=o(t,a),c=o(t,a);f(u,l,c);for(var h=[],s=c[0].length-1,v=c.length-1;v>=0;v--){var g=c[v][s];h[v]=u.slice(g,s+1),v>0&&(s=g-1)}return h}r.exports=i}])});
!function(r,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("d3scaleCluster",[],n):"object"==typeof exports?exports.d3scaleCluster=n():r.d3scaleCluster=n()}(this,function(){return function(r){function n(e){if(t[e])return t[e].exports;var o=t[e]={exports:{},id:e,loaded:!1};return r[e].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var t={};return n.m=r,n.c=t,n.p="",n(0)}([function(r,n,t){function e(){function r(){if(!(a.length<=2)){var r=o(t,Math.min(t.length,a.length));n=0!==r.length,u=[];for(var e=0;e<r.length;e++)u.push(r[e][0])}}var n=!1,t=[],a=[],u=[],i=function(r){if(n){for(var t=u.length-1;t>=0;t--)if(r>=u[t])return a[t];return a[0]}};return i.domain=function(){return arguments.length?(t=arguments[0],r(),i):t},i.range=function(){if(arguments.length){var n=arguments[0],t=n.length!==a.length;return a=n,t&&r(),i}return a},i.invertExtent=function(r){for(var n=NaN,t=NaN,e=0;e<a.length;e++)if(a[e]===r){n=u[e],t=e+1<a.length?u[e+1]:NaN;break}return[n,t]},i.clusters=function(){return u.slice(1)},i.export=function(){return{isReady:n,domain:t,range:a,breakpoints:u}},i.import=function(r){if(!r)throw new Error("Import requires parameters");return n=r.isReady,t=r.domain,a=r.range,u=r.breakpoints,i},i.copy=function(){return e().domain(t).range(a)},i}var o=t(1);"object"==typeof d3&&(d3.scaleCluster=e),r.exports=e},function(r,n){function t(r){return r.slice().sort(function(r,n){return r-n})}function e(r){for(var n,t=0,e=0;e<r.length;e++)0!==e&&r[e]===n||(n=r[e],t++);return t}function o(r,n){for(var t=[],e=0;e<r;e++){for(var o=[],a=0;a<n;a++)o.push(0);t.push(o)}return t}function a(r,n,t,e){var o;if(r>0){var a=(t[n]-t[r-1])/(n-r+1);o=e[n]-e[r-1]-(n-r+1)*a*a}else o=e[n]-t[n]*t[n]/(n+1);return o<0?0:o}function u(r,n,t,e,o,i,f){if(!(r>n)){var l=Math.floor((r+n)/2);e[t][l]=e[t-1][l-1],o[t][l]=l;var c=t;r>t&&(c=Math.max(c,o[t][r-1]||0)),c=Math.max(c,o[t-1][l]||0);var s=l-1;n<e.length-1&&(s=Math.min(s,o[t][n+1]||0));for(var h,p,g,v,d=s;d>=c&&(h=a(d,l,i,f),!(h+e[t-1][c-1]>=e[t][l]));--d)p=a(c,l,i,f),g=p+e[t-1][c-1],g<e[t][l]&&(e[t][l]=g,o[t][l]=c),c++,v=h+e[t-1][d-1],v<e[t][l]&&(e[t][l]=v,o[t][l]=d);u(r,l-1,t,e,o,i,f),u(l+1,n,t,e,o,i,f)}}function i(r,n,t){for(var e=n[0].length,o=new Array(e),i=new Array(e),f=r[Math.floor(e/2)],l=0;l<e;++l)0===l?(o[0]=r[0]-f,i[0]=(r[0]-f)*(r[0]-f)):(o[l]=o[l-1]+r[l]-f,i[l]=i[l-1]+(r[l]-f)*(r[l]-f)),n[0][l]=a(0,l,o,i),t[0][l]=0;for(var c,s=1;s<n.length;++s)c=s<n.length-1?s:e-1,u(c,e-1,s,n,t,o,i)}function f(r,n){if(n>r.length)throw new Error("Cannot generate more classes than there are data values");var a=r.length,u=t(r),f=e(u);if(1===f)return[u];n=Math.min(f,n);var l=o(n,a),c=o(n,a);i(u,l,c);for(var s=[],h=c[0].length-1,p=c.length-1;p>=0;p--){var g=c[p][h];s[p]=u.slice(g,h+1),p>0&&(h=g-1)}return s}r.exports=f}])});
{
"name": "d3-scale-cluster",
"version": "1.1.7",
"version": "1.2.0",
"description": "D3 scale that clusters data into discrete groups",

@@ -8,4 +8,5 @@ "repository": "schnerd/d3-scale-cluster",

"scripts": {
"test": "node spec/index.js",
"build": "webpack"
"test": "npm run lint && node spec/index.js",
"build": "webpack",
"lint": "eslint src/* spec/*"
},

@@ -15,7 +16,8 @@ "author": "David Schnurr",

"devDependencies": {
"d3": "^4.2.2",
"eslint": "^3.5.0",
"eslint-config-standard": "^6.0.0",
"eslint-plugin-promise": "^2.0.1",
"eslint-plugin-standard": "^2.0.0",
"eslint": "^4.15.0",
"eslint-config-standard": "^11.0.0-beta.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"jasmine": "^2.5.1",

@@ -22,0 +24,0 @@ "jasmine-console-reporter": "^1.2.7",

# d3-scale-cluster
A custom D3 scale powered by a 1-dimensional clustering algoirthm. Similar to [quantile scales](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantile), the cluster scale maps a continuous input domain to a discrete range. The number of values in the output range determines the number of clusters that will be computed from the domain. The graphic below demonstrates how cluster compares to D3's quantile and quantize scales:
A custom D3 scale powered by a 1-dimensional clustering algorithm. Similar to [quantile scales](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantile), the cluster scale maps a continuous input domain to a discrete range. The number of values in the output range determines the number of clusters that will be computed from the domain. The graphic below demonstrates how cluster compares to D3's quantile and quantize scales:

@@ -13,5 +13,5 @@ <img width="420" alt="d3 scale cluster example" src="https://cloud.githubusercontent.com/assets/875591/18608070/0213d7ce-7cdf-11e6-89aa-1b0e18e63cc8.png">

###Getting Started
### Getting Started
#####Using npm
##### Using npm

@@ -27,3 +27,3 @@ Install the npm package

```es6
// Using ES6 imports
// Using ES6 imports
import scaleCluster from 'd3-scale-cluster';

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

#####Using a `<script>` tag
##### Using a `<script>` tag

@@ -49,3 +49,3 @@ Include the following script tag on your page after D3

```
###Example Usage
### Example Usage

@@ -64,3 +64,3 @@ This scale largely has the same API as [d3.scaleQuantile](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantile) (however we use `clusters()` instead of `quantiles()`)

###API
### API

@@ -95,5 +95,32 @@ d3.**scaleCluster**()

###Contributing
_cluster_.**import**()
Updates the scale with the result of a _cluster_.**export**() call. Useful for offloading computation into a webworker.
_cluster_.**export**()
Exports the internals of the scale as an object, for use with _cluster_.**import**(). Useful for offloading computation into a webworker.
### Using in a Web Worker
For data sets of significant size, you may want to offload computation into a Web Worker so that it does not block the main thread. You can use _cluster_.**import**() and _cluster_.**export**() as follows:
**worker.js**
```js
const scale = scaleCluster().domain(domain).range(range);
self.postMessage({scale: scale.export()});
```
**Main thread**
```js
worker.onmessage = function (event) {
const scale = scaleCluster().import(event.data.scale)
};
```
### Contributing
```
npm install

@@ -104,4 +131,10 @@ npm run test # run tests

###Thanks
### Thanks
Thanks to Haizhou Wang and Mingzhou Song for developing the original [Ckmeans 1D clustering algorithm](https://cran.r-project.org/web/packages/Ckmeans.1d.dp/), and Tom MacWright for his [previous work](http://www.macwright.org/2013/02/18/literate-jenks.html) in bringing these techniques to the web.
### Links & Resources
- [Using clustering to create a new D3.js color scale](https://medium.com/@dschnr/using-clustering-to-create-a-new-d3-js-color-scale-dec4ccd639d2) - Medium post describing this project
- [Choropleth with d3-scale-cluster](https://bl.ocks.org/schnerd/99767e64051096388078913afca3ff4e) - Interactive block comparing cluster, quantile, and quantize scales
- [Interactive d3-scale-cluster demo](http://bl.ocks.org/tomshanley/raw/2de81c66fbe4cab9dc4e4e4c579a4d1a/) - Paste in your data to see clusters. By [@tomshanleynz](https://twitter.com/tomshanleynz)

@@ -6,21 +6,19 @@ var Jasmine = require('jasmine');

jasmine.loadConfig({
spec_dir: 'spec',
spec_files: [
'**/*[sS]pec.js'
],
helpers: [
'helpers/**/*.js'
],
stopSpecOnExpectationFailure: false,
random: false
spec_dir: 'spec',
spec_files: ['**/*[sS]pec.js'],
helpers: ['helpers/**/*.js'],
stopSpecOnExpectationFailure: false,
random: false
});
jasmine.addReporter(new JasmineConsoleReporter({
colors: 1, // (0|false)|(1|true)|2
cleanStack: 1, // (0|false)|(1|true)|2|3
verbosity: 4, // (0|false)|1|2|(3|true)|4
listStyle: 'indent', // "flat"|"indent"
activity: false
}));
jasmine.addReporter(
new JasmineConsoleReporter({
colors: 1, // (0|false)|(1|true)|2
cleanStack: 1, // (0|false)|(1|true)|2|3
verbosity: 4, // (0|false)|1|2|(3|true)|4
listStyle: 'indent', // "flat"|"indent"
activity: false
})
);
jasmine.execute();

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

/* globals describe, beforeEach, it, expect */
describe('Scale', function () {

@@ -13,5 +14,3 @@ var d3scaleCluster = require('../src/index.js');

it('should find clusters', function () {
scale
.domain(DEFAULT_DOMAIN)
.range(DEFAULT_RANGE);
scale.domain(DEFAULT_DOMAIN).range(DEFAULT_RANGE);

@@ -21,8 +20,10 @@ var clusters = scale.clusters();

expect(scale(52)).toEqual('c');
var exported = scale.export();
var newScale = d3scaleCluster().import(exported);
expect(newScale(52)).toEqual('c');
});
it('should be able to invert extent', function () {
scale
.domain(DEFAULT_DOMAIN)
.range(DEFAULT_RANGE);
scale.domain(DEFAULT_DOMAIN).range(DEFAULT_RANGE);
expect(scale.invertExtent('c')).toEqual([43, 123]); // Up to but not including 123

@@ -32,5 +33,3 @@ });

it('should return NaNs inverting an invalid value', function () {
scale
.domain(DEFAULT_DOMAIN)
.range(DEFAULT_RANGE);
scale.domain(DEFAULT_DOMAIN).range(DEFAULT_RANGE);
expect(scale.invertExtent('lol')).toEqual([NaN, NaN]);

@@ -44,7 +43,9 @@ });

it('should "gracefully" handle cases where range has more values than domain', function () {
scale
.domain([1, 2, 4])
.range(DEFAULT_RANGE);
scale.domain([1, 2, 4]).range(DEFAULT_RANGE);
expect(scale(4)).toEqual('c');
var exported = scale.export();
var newScale = d3scaleCluster().import(exported);
expect(newScale(4)).toEqual('c');
});
});
var ckmeans = require('./ckmeans.js');
function d3scaleCluster () {
var clusters = [];
var isReady = false;
var domain = [];

@@ -10,3 +10,3 @@ var range = [];

var scale = function (x) {
if (clusters.length === 0) return undefined;
if (!isReady) return undefined;

@@ -26,4 +26,4 @@ for (var i = breakpoints.length - 1; i >= 0; i--) {

clusters = ckmeans(domain, Math.min(domain.length, range.length));
var clusters = ckmeans(domain, Math.min(domain.length, range.length));
isReady = clusters.length !== 0;
breakpoints = [];

@@ -77,2 +77,22 @@ for (var i = 0; i < clusters.length; i++) {

scale.export = function () {
return {
isReady: isReady,
domain: domain,
range: range,
breakpoints: breakpoints
};
};
scale.import = function (params) {
if (!params) {
throw new Error('Import requires parameters');
}
isReady = params.isReady;
domain = params.domain;
range = params.range;
breakpoints = params.breakpoints;
return scale;
};
scale.copy = function () {

@@ -90,2 +110,1 @@ return d3scaleCluster().domain(domain).range(range);

module.exports = d3scaleCluster;
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