gigamonkey / gg

Implementation of some ideas from ggplot2 on top of d3.js
Other
123 stars 22 forks source link

Implement position_dodge for bar charts #5

Open imd opened 12 years ago

imd commented 12 years ago

Problem

Currently the interval geometry one can only graph one bar at each x coordinate. ggplot2 allows multiple bars using position_dodge: http://had.co.nz/ggplot2/position_dodge.html

Proposal

Implement position_dodge

gigamonkey commented 12 years ago

Yup. In the plans.

asolove commented 12 years ago

I started on this but then couldn't even figure out what the desired syntax would be. The ggplot examples I see just turn on position_dodge, but it seems like with our syntax you need to also specify which aesthetic the dodge is based on.

After that, I think what you want to do is implement a CompoundScale, which takes two pieces of data, and does the big step from the main one and the dodge step from the second.

One nice-to-have feature: ggplot calculates out the number points along the dodged scale and automatically sets the bar width to fit.

gigamonkey commented 12 years ago

I'm not sure either. I think in ggplot2 the positioning is part of the layer. At any rate, perhaps the syntax would be something like this:

var barchart = gg({
    layers: [{
        geometry: 'interval',
        group: 'foo',
        position: 'dodge',
        mapping: { x: 'd', y: 'r' },
        color: 'blue',
        width: 2
    }]
});

where 'foo' is the name of one of the columns in the data (i.e. each datum is { x: ..., y: ..., foo: ... }). So then the data is grouped (e.g. with d3.nest()) by 'foo' and then each one is rendered with the interval geometry but slightly repositioned. I think Nate is working on grouping so he may already be on this.

gigamonkey commented 12 years ago

I just made a change so that the render method on geometry objects is passed a G element rather than the graphic. This was to support facets which are responsible for actually creating the G and passing it to the layer which then passes it on to the geometry. But at least for dodging the layer could make a shifted G and pass that to the geometry and it would Just Work. However for stacking I don't think that works so it's probably not actually a good idea. I'll think more about this.

n8agrin commented 12 years ago

The following is my understanding and what I learned trying to previously write a ggplot clone: Positioners are part of the layers. You can think of them as interacting with the groups created by the group aesthetic. They are run after stats have been computed and before scales are trained. To understand why they must be run in this order consider a bar chart with position: dodge vs one with position: stack. In position: dodge your baseline y (y0) will be the same for each bar, generally y0 == 0, so training the scales should work fine. In position stack, however, your sub group's y0 will be the y value of the previous bar in the subgroup. When training the scales you then have to account not only for a bar's y value but the sum of y + y0.

When I previously wrote some code along these lines I ended up coming up with a 'common data format' for all points, which is to say when the data reached the render method each point always had at least x, x0, y, and y0 attributes. x0 let you handle position dodge, while y0 lets you handle position stack.

Does that make sense? It should be pretty straightforward to add them in now that grouping is available.