Use Barnes-Hut criterion (a fast multipole method) for approximating repulsive
charge forces between nodes. This replaces the previous approach using Floyd-
Warshall to compute the graph theoretic distance between all nodes, eliminating
O(n^3) initialization time. Additionally, the charge force is now O(n lg n) per
iteration rather than O(n^2).
Using the center of mass of the graph, apply gravitional attraction towards the
graph center (based on the layout size). This encourages the graph to stay near
the center rather than drifting away.
This makes the quadtree implementation more compatible with the force layout.
This change is backwards-compatible; if the points are not specified as x+y
objects, they are assumed to be tuples and converted to objects.
This is a utility for creating a Bézier curve between opposite corners of a
rectangle. This is commonly used to draw smooth curves connecting parent and
child nodes in a hierarchical node-link diagram. A projection may be specified
which allows the curve to be transformed from polar coordinates.
This commit also changes the semantics of the recently-added `links` method,
such that the objects have `source` and `target` properties that match the
default diagonal format.
This method can be used to generate an array of parent+child objects for a given
array of nodes. This is convenient for drawing paths from parent to child in
node-link diagrams.
The `cluster` layout is now more similar to the `tree` layout, using a
separation function rather than a group property. In addition, the breadth and
depth properties are replaced with x and y, respectively, and scaled according
to the size of the layout.
I've updated the examples to make them more consistent, as well, including the
pretty Bézier curves. In a future commit I'd like to take some of the duplicate
code in the examples and move that into reusable methods.
Preserving object constancy across transitions is tricky! For example, what
happens if we remove the whiskers in a transition? How do we join outliers? This
commit makes a few assumptions explicit:
1. The `quartiles` function must return exactly three elements. This property
must be specified as a function.
2. The `whiskers` function must return exactly 2 elements, or null if no
whiskers are to be displayed. This property must be specified as a function.
3. The `domain` function must return exactly 2 elements, or null if the default
domain should be used. This property can be specified either as a constant or as
a function.
We could generalize this chart to support more than two whiskers, but it doesn't
seem urgent, and it would complicate the transition if the number of whiskers
changes. In a related change, the `whiskers` function does not receive a third
argument containing the quartiles; instead, this is made available by the
`quartiles` property on the values array (the first argument).
The outliers are joined using the `Number` key function. The outlier data is now
stored as indices; this allows reasonable object constancy across transitions
with outliers. Similarly, the tick labels for the quartiles are whiskers are now
separated, such that the whisker labels can be added or removed without spurious
transition.
The outliers were being incorrectly excluded when computing the quartiles. I've
also added a +/-1.5 IQR whiskers computation for the Morley-Michelson example,
so it replicates the R plot exactly.
This specifies a function that takes the sorted data array, and returns an array
of datum positions that should marked with whiskers. The default implementation
is to return `[0, length-1]` i.e. the minimum and maximum.
Data outside of the whiskers are considered outliers, and are not included in
the quartile calculation.
The pack layout now sorts nodes by ascending value by default. The `radius`
property is removed, as the radius is always computed from the node value. The
`spacing` property is also removed; it doesn't seem particularly useful. The
`radius` property is renamed to `r` to match `x` and `y`.
I also optimized the implementation slightly, and namespaced temporary state
under the prefix `_pack_`.
Based on the Protovis version. The only difference is that I've dropped
the `orient`, `innerRadius` and `outerRadius` properties so that the D3
version is more flexible.
Based on the Protovis layout. I've kept the convention of using `size`
for the width/height and `separation` for the spacing. The Protovis
layout had a `size` property but this was used to compute the radius.
I've left this out as I've assumed it's straightforward enough to pass
in the appropriate `radius` function instead. Likewise, I think the
existing hierarchy `sort` property can handle situations that `order`
was intended for in the Protovis version.
Rather than specifying an orientation, compute the layout in normalized space. In a future change,
I'd also like to clean up the temporary state that is stored on tree nodes, and record dx and dy
attributes per node that could be used to compute a space-filling layout.
We were computing the tick join based on the (new) format function, but doesn't
produce the desired effect: the new format is applied on the old data. Thus, the
wrong join occurs if, say, the value 0.5 with the new format results in "0". The
correct join compares the old text content to the new format value.
This example shows how to preserve scales across multiples using a single chart
instance, as opposed to bullet-multiples which uses distinct chart instances to
supply separate scales. I still think it'd be better to use a single chart
instance in both cases, but then I need a different place to hide the scale
state.
This way, we get separate scales for the small multiples, which makes sense
given our data. However, I'm not totally convinced this is the right way to
implement separate scales, because it's a bit awkward to create separate chart
instances that look identical. Also, it's unfortunate that the charts are
stateful; it'd be better to somehow store the scale as data on the nodes, so
that chart specifications could be more easily reused. Then, there might be a
method to fix the domain rather than computing the domain per-chart.
It's nice, but I think it's a bit more flexible to not have it as part of the
chart specification. This way, people can define titles however they like. It
might be nice to take a similar approach with reference ticks in the future.