add bars that have no data in an Ordinal barChart?

52 views
Skip to first unread message

Matt Aze

unread,
Mar 14, 2017, 12:34:49 PM3/14/17
to dc-js user group
Hi,

Wondering is I can set the range of an Ordinal barChart, so see all possible ordinals even if not in dataset?

dc_chart.ordinalColors(["red","green","blue"]);
dc_chart
.colorAccessor(function (p, i) { return i; });

dc_chart.x(d3.scale.ordinal().domain(["red","green","blue"]));

dc_chart.xUnits(dc.units.ordinal);

Also might be a version issue i have (2 something), that on a barChart the ordinalColors needed an colorAccessor so uses "i", unless confusing that with rowChart which does that by default?

in the lines above, tried .x with a d3.scale, adding domain, also tried setting with .range. No change, but nothing breaks either.

Is this possible, or will I need to look at adding in fake data into dataset?

thanks


Gordon Woodhull

unread,
Mar 14, 2017, 1:01:38 PM3/14/17
to dc.js user group
For an ordinal bar chart, dc.js will automatically set the domain if you have .elasticX true, or if you don't set a domain yourself. So maybe you need to turn off elasticX so that it uses your domain?


        } else { // _chart.isOrdinal()
            if (_chart.elasticX() || _x.domain().length === 0) {
                _x.domain(_chart._ordinalXDomain());
            }


By default, stacked charts will use coloring for the stacks, not for the individual items. So yes, if you want the bars in a single stack individually colored, you need to set the color accessor, e.g.

chart.colorAccessor(function(d) { return d.key; })


--
You received this message because you are subscribed to the Google Groups "dc-js user group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dc-js-user-gro...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dc-js-user-group/d8dee037-9bea-40bc-a2f6-cc1cb151b85e%40googlegroups.com.

Matt Aze

unread,
Mar 15, 2017, 7:11:05 AM3/15/17
to dc-js user group
1. thanks, I did have elasticX(true), earlier in the code.

2. now i'm struggling with colorAccessor/ordinal.range. incorrect colors matching to ordinal order.

a fiddle

and code at end

  a: issue: colors not matching what i expect with array order.

  b: it occurs to me that d3 is changing the order of the color_range given.
    Meaning given "r", "g", "b":   it switchs it around in alphabetical order.
    But the xUnits stay in the original order.

  c: colorAccessor makes no difference if    return p.key;    or   return color_range.indexOf(p.key);
     But: if i do    return 1; or any number, all of them are red?


var data= crossfilter(
[
  {"color":"green"},{"color":"green"},{"color":"blue"},{"color":"red"},
  // {"color":"yellow"},
  ]
);

var dimension = data.dimension(function (d) { return d.color; });
var group = dimension.group();

//var color_range = ["red", "yellow", "green", "blue"];
var color_range = ['red','green','blue'];
//var color_range = ['blue', 'green', 'yellow', 'red'];

var bar = dc.barChart("#bar-chart")
    .dimension(dimension) 
    .group(group) 
    .x(d3.scale.ordinal().domain(color_range)) // Need the empty val to offset the first value
   
    .xUnits(dc.units.ordinal) // Tell Dc.js that we're using an ordinal x axis
    .brushOn(false);
    
//bar.ordinalColors(color_range);
bar.colors(d3.scale.ordinal().range(color_range));
bar.colorAccessor(function (p, i) {
  //return color_range.indexOf(p.key);
  //return ['red','green','blue'].indexOf(p.key);
  return p.key;
});

dc.renderAll();


Gordon Woodhull

unread,
Mar 15, 2017, 11:32:59 AM3/15/17
to dc.js user group
Hi Matt,

Thing to remember about d3 scales is they always have both a domain and a range. For ordinal scales, if you don't assign a domain, d3 will start assigning to the domain as it sees items. 

Since the crossfilter group will sort the keys in alphabetical order, (b) dc.js will see 'blue' first, thus 'blue' gets mapped to red. If your accessor returns a constant value (c), then the ordinal scale only ever assigns the first color.

To get your example working, you could set the same domain and range for your ordinal scale:

bar.colors(d3.scale.ordinal().domain(color_range).range(color_range));

Or, if your data always has the actual color values in it, you could even supply the identity function as your color scale:
function identity(x) { return x; }
bar.colors(identity);

This works because dc.js usually just passes the data through the color accessor value, then passes that result through the color scale to get the value to put into the SVG.

Cheers,
Gordon


--
You received this message because you are subscribed to the Google Groups "dc-js user group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dc-js-user-gro...@googlegroups.com.

Matt Aze

unread,
Mar 16, 2017, 10:31:30 AM3/16/17
to dc-js user group
Again, thank you so much.

the second approach is what i'm ending with, using a pass through function for color. In colorAccessor i actually have it figure out based on domain range set and and color array set, which color to return.

I used the color example in code as a quick, not realising what confusion the underlying d3 functions might be doing.

thank you again.

Gordon Woodhull

unread,
Mar 16, 2017, 12:02:42 PM3/16/17
to dc.js user group
Glad to help!

In colorAccessor i actually have it figure out based on domain range set and and color array set, which color to return.

Unless you're doing something really exotic, there is probably a d3 scale that does what you're doing. colorMixin.calculateColorDomain is also helpful when you're using the min and max of some colorAccessor values to initialize the domain of a d3 scale. Usually the idea is to call calculateColorDomain in a preRender and/or preRedraw event handler.

But none of this is rocket science, and the scales are IMO mostly for convenience and a nice conceptual framework. So doing everything in the colorAccessor is completely valid too.

Reply all
Reply to author
Forward
0 new messages