Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/Kcnarf/d3-beeswarm

D3 plugin which computes a 'beeswarm' arrangement
https://github.com/Kcnarf/d3-beeswarm

Last synced: 2 months ago
JSON representation

D3 plugin which computes a 'beeswarm' arrangement

Awesome Lists containing this project

README

        

# d3-beeswarm

This d3 plugin produces a _beeswarm_ arrangement, thanks to a dedicated algorithm and without the use a the d3.force layout.

Available only for **d3 v3.x** and **d3 v4**.

## Context

Beeswarm is a one-dimensional scatter plot with closely-packed, non-overlapping points. The beeswarm plot is a useful technique when we wish to see not only the measured values of interest for each data point, but also the distribution of these values

Some beeswarm-like plot implementation uses force layout, but the force layout simulation has some drawbacks:

- it naturally tries to reach its equilibrium by rearranging data points in the 2D space, which can be disruptive to the ordering of the data
- it requires several iterations to reach its equilibrium

This _beeswarm_ plugin uses a dedicated one pass algorithm. By default, this plugin arranges data in an horizontal way, ie. along the x-axis. In this case, the final arrangement is constraint in _x_ and free in _y_. This means that the position of each data reflects its precise _x_ value, while _y_ position doesn't reflect any data-related value (and only serves the non-overlapping constraint). This plugin can also arrange data in a vertical way.

## Examples

- [Universities of Berlin and Germany](https://lab.technologiestiftung-berlin.de/projects/unis/index_en.html): Where do people study most? How does the academic landscape look like?
- [White House Salaries - Obama '16 VS Trump '17](https://bl.ocks.org/Kcnarf/4608704a70fc24e2c06ca0116830de47).
- This [post](http://poly-graph.co/vocabulary.html) uses a beeswarm plot (but not this plugin).
- This [block](http://bl.ocks.org/Kcnarf/5c989173d0e0c74ab4b62161b33bb0a8) allows to play with the options of this **d3-beeswarm** plugin.

## Installing

If you use NPM, `npm install d3-beeswarm`. Otherwise, load `https://rawgit.com/Kcnarf/d3-beeswarm/master/build/d3-beeswarm.js` to make it available in AMD, CommonJS, or vanilla environments. In vanilla, a d3 global is exported:

```html

var swarm = d3.beeswarm();

```

## TL;DR;

In your javascript, in order to define the arrangement:

```javascript
var swarm = d3
.beeswarm()
.data(data) // set the data to arrange
.distributeOn(function(d) {
// set the value accessor to distribute on
return xScale(d.foo); // evaluated once on each element of data
}) // when starting the arrangement
.radius(4) // set the radius for overlapping detection
.orientation('horizontal') // set the orientation of the arrangement
// could also be 'vertical'
.side('symetric') // set the side(s) available for accumulation
// could also be 'positive' or 'negative'
.arrange(); // launch arrangement computation;
// return an array of {datum: , x: , y: }
// where datum refers to an element of data
// each element of data remains unchanged
```

Then, later in your javascript, in order to draw the swarm:

```javascript
d3.selectAll('circle')
.data(swarm)
.enter()
.append('circle')
.attr('cx', function(bee) {
return bee.x;
})
.attr('cy', function(bee) {
return bee.y;
})
.attr('r', 4)
.style('fill', function(bee) {
return fillScale(bee.datum.bar);
});
```

In the last line, `bee.datum` refers to the original datum.

## Reference

- R package: [http://www.cbs.dtu.dk/~eklund/beeswarm](http://www.cbs.dtu.dk/~eklund/beeswarm/)

## API

# d3.beeswarm()

Creates a new beeswarm with the default settings:

```javascript
distributeOn = function(d) {
return d.x;
};
radius = 4;
orientation = 'horizontal';
side = 'symetric';
```

# beeswarm.datadata([data])

If _data_ is specified, set the array of data to arrange and returns this beeswarm. If _data_ is not specified, returns the current array of data to arrange.

# beeswarm.distributeOn([callback])

If _callback_ is specified, set the callback that evaluates the value to distribute on and returns this beeswarm. If _callback_ is not specified, return the current callback, which defaults to `function(d) { return d.x; }`.

The callback is evaluated once, on each element to arrange, at the beginning of the arrangement computation. The callback must return the final x-coordinate for an horizontal arrangement (or the final y-coordinate for a vertical arrangement). So if you use a d3.scale, your code should look like:

```javascript
d3.beeswarm()
.data(data)
.distributeOn(function(d) {
return xScale(d.foo);
});
```

# beeswarm.radius([radius])

Without any argument, returns the current radius of the layout.
If _radius_ is specified, sets the radius of each datum to the specified number. If _radius_ is not specified, returns the current radius, which defaults to 4.

The arrangement uses this _radius_ as a constraint, and arranges each datum so that there is no overlapping. However, when its time to draw each datum, you can use another rendering radius:

- a lower rendering radius will add some padding between data
- a higher rendering radius will add some overlapping between data (making the final viz more compacted as if there wasn't any overlapping, but with the drawback to not meet the non-overlapping constraint of beeswarm arrangement)

# beeswarm.orientation([orientation])

If _orientation_ is specified, set the orientation to the specified value (within `'horizontal'` or `'vertical'`) and returns this beeswarm. If _orientation_ is not specified, returns the current orientation, which defaults to `'horizontal'`.

A `'horizontal'` orientation will arrange data along the x-axis. A `'vertical'` arrangement will arrange data along the y-axis.

# beeswarm.side([side])

If _side_ is specified, set the side to the specified value (within `'symetric'`, `'positive'` or `'negative'`) and returns this beeswarm. If _side_ is not specified, returns the current side, which defaults to `'symetric'`.

A `'symetric'` side arranges data around the main axis, placing data above and below the axis. A `'positive'`side arranges data only above the main axis. A `'negative'`side arranges data only below the main axis.

# beeswarm.arrange()

Launches the arrangement computation. Return an array of `{x: , y: , datum: }`, where `x` and `y` are the computed coordinates, and `datum` refers to the original element of data.

## How To

- issue [option to arrange from minToMax, maxToMin, extremeToCenter, shuffled](https://github.com/Kcnarf/d3-beeswarm/issues/7) explains how to arrange in a particular order. It can be tested in [this block](http://bl.ocks.org/Kcnarf/5c989173d0e0c74ab4b62161b33bb0a8).
- issue [add a maximum size, and provide strategies if exceeded](https://github.com/Kcnarf/d3-beeswarm/issues/2) explains how to handle too large viz due to extreme accumulations. It can be tested in [this block](http://bl.ocks.org/Kcnarf/5c989173d0e0c74ab4b62161b33bb0a8).