This way, people can play with superformulas if they want them, but we keep the
core library small. If we want to replace the default symbol implementation with
superformulas in the future, we can do that too. For now, be conservative.
The subclasses can't use the same object as the parent class, because they are
functions. But, there's no reason to duplicate the code that rebinds the methods
onto the subclass.
Use width and height attributes instead of size, for consistency with other
chart templates. (Though, note that chart templates are inconsistent with
layouts in this regard, which use a size property. But let's remain locally
consistent for now.) Default x and y properties to [0] and [1] to match the
defaults of d3.svg.area.
Add support for mode and interpolate properties. The mode can be either "offset"
or "mirror", with the default being "offset". The interpolate property is the
same as that used by d3.svg.area, and defaults to "linear".
The horizon chart now properly clips the horizon layers, such that if a horizon
chart is use within a larger SVG element, it will not extend the chart bounds.
In addition, this commit fixes a bug in how unique IDs are assigned to the clip
and area paths; it's a shame that SVG does not support a way to refer to paths
locally.
Note that because negative values are offset or mirrored, the horizon chart will
render twice as many paths (use elements) as the requested number of bands. For
example, if the default bands of 1 is used, there will be one negative band and
one positive band. In the data has no negative values, then the negative band
will be empty. Keep this in mind as it affects the layer's class attribute
(such as "q0-3" and "q2-3" for the default single-band horizon).
Rename `ticks` to `bins` to match numpy, matplotlib, and Protovis. Also allow
the bins to be specified simply as a count, in which case the range is divided
uniformly into the specified number of bins.
The histogram layout now also takes a `range` property, which specifies the
minimum and maximum value of the histogram rather than implicitly computing it
from the values, which is nice if you expect values to fall in a specific range,
such as [0,1].
This is similar to pv.search, but more closely modeled after Python's bisect
methods to provide the desired flexibility in searching slices of arrays. This
includes good tests for bisect, and better tests for polylinear and quantile
scales (both of which now use bisect).
Simplify the implementation of parallel merge-sort, so that we have one pass per
swap across chunks. Use a data join so that the elements are translated rather
than rotated, since this better conveys the underlying sort. Auto-play the
animation in parallel, and restart a few seconds after it finishes.
Inspired by the phrase "reminiscent of wind gusting over tall grasses" in
<http://vis.stanford.edu/protovis/ex/sort.html>.
It seemed abominable not to animate the swaying tall grasses!
There will always be a single <path> element, so no need to handle enter, update
and exit cases. WebKit seems to erroneously warn (in the error console) that it
can't parse `d=""`. I can't see anything in the SVG spec disallowing an empty
`d` attribute so I think this is safe to ignore.
I've dropped path transitions on Mike's recommendation as D3 doesn't have smart
path interpolation at the moment so they don't work too well.
I've also fixed some issues with data joins.
If the simulation cools and stops, we need to restart it, rather than just
resetting the alpha parameter. So, it is useful to have both `resume` and
`start` methods on the force layout. This commit also fixes a bug where
mousedown events on draggable nodes would continue to propagate, interfering
with other events (such as clicking to add a node).
You can now register the "drag" behavior on nodes multiple times, and the
correct behavior will result. In addition, the gravitational force now handles
coincident nodes, computing a small random force to separate the nodes rather
than setting the position to NaN.
To demonstrate the new support for dynamic graphs, this commit includes a fun
example where you can click to add new nodes. Any existing nodes within a fixed
distance to the cursor on click will be linked to the new node.
Rather than applying gravity to the entire graph, we now apply it to individual
nodes, such that disconnected nodes and subgraphs still have a tendency to drift
towards the center. In addition, rather than using a standard gravitational
force that drops quadratically with distance, we use a weak spring who force
increases with distance. This makes the gravitational effect less noticeable
near the center, and also makes the effect stronger the more the nodes drift
from the center. To balance the center "gravity" with the repulsive charge
force, we also normalize the strength of the gravity based on the number of
nodes in the graph.
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.
We now preserve object constancy for ticks across transitions. By caching a
reference to the previous x-scale, we can initialize entering objects in the
correct location, then transition them to the new scale as they fade in. Also,
we use the `map` operator to convert the data to a standard representation that
is suitable for the bullet chart, and compute derivate data needed across
multiples.
The treemap layout can now be set to "sticky" mode, which preserves the row
arrangements from an earlier layout. This is particularly handy for animating
treemaps, as it avoids the temporary occlusion as nodes swap positions. Thanks
to @philogb and the New York Times for the inspiration!