Ordinal scales

Ordinal scales are the simplest; essentially just a dictionary, where keys are the domain and values are the range.

In the preceding example, we defined an ordinal scale by explicitly setting both the input domain and the output range. If we don't define a domain, it's inferred from use, but that can give unpredictable results.

A cool thing about ordinal scales is that having a range smaller than the domain makes the scale repeat values once used. Furthermore, we'd get the same result if the range was just ['red', 'yellow', 'green'].

Let's try a few out. We will create band and point scales, which are ordinal scales with extra pizazz. We also need to create a color scale that repeats itself. First, though, we need somewhere to put our scales. Create a new Immediately Invoked Function Expression (IIFE) in chapter4/index.js named ScalesDemo:

const scalesDemo = (enabled => {
if (enabled) { // main block, put code here }
})(true);

Next, we define the three scales we need and generate some data:

(function ordinalScales() {
const data = d3.range(30);
const colors = d3.scaleOrdinal(d3.schemeCategory10);
const points = d3.scalePoint()
.domain(data)
.range([0, chart.height])
.padding(1.0);
const bands = d3.scaleBand()
.domain(data)
.range([0, chart.width])
.padding(0.1);
}());

Our data is just a list of numbers going up to 30, and the colors scale is from Chapter 2, A Primer on DOM, SVG, and CSS. In D3 v3, it used to be a predefined ordinal scale with an undefined domain and a range of 10 colors, but now it's just an array containing those same colors. For it to be an ordinal scale, it now needs to be assigned to one, such as we did in the preceding data.

Then, we defined two scales that split our drawing into equal parts. points uses .scalePoints() to distribute 30 equally spaced points along the height of our drawing. We set the edge padding with a factor of 1.0 using the .padding() method, which sets the distance from the last point of the edge to half the distance between the points. Endpoints are moved inward from the range edge using point_distance*padding/2:

This graphic from the d3-scale documentation explains how point scales are calculated.

We then use .scaleBands() to divide the width into 30 equal bands with a padding factor of 0.1 between bands. This time, we're setting the distance between bands, using step*padding, and a third argument would set edge padding using step*outerPadding:

This, also from the d3-scale documentation, depicts the factors influencing the calculation of a band scale.

This is a fairly big API change from D3 v3. Instead of rangeBands() and rangePoints() being methods attached to an ordinal scale, they're now scales unto themselves. For more information, refer to https://github.com/d3/d3/blob/master/CHANGES.md#scales-d3-scale.

We'll use code you already know from Chapter 2, A Primer on DOM, SVG, and CSS, to draw two lines using these scales. Add the following to our IIFE:

chart.container.selectAll('path') 
.data(data)
.enter()
.append('path')
.attr('d', d3.symbol()
.type(d3.symbolCircle)
.size(10)
)
.attr('transform', d => `translate(${(chart.width / 2)}, ${points(d)})`)
.style('fill', d => colors(d));

chart.container.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', d => bands(d))
.attr('y', chart.height / 2)
.attr('width', bands.bandwidth)
.attr('height', 10)
.style('fill', d => colors(d));

To get the positions for each dot or rectangle, we called the scales as functions and used bands.rangeBand() to get the rectangle width.
The picture looks as follows:

You can get different effects by using different color schemes. Replace the whole bit starting with chart.container.selectAll('rect') with the following:

      ['10', '20', '20b', '20c'].forEach((scheme, i) => { 
const height = 10;
const padding = 5;
const categoryScheme = `schemeCategory${scheme}`;
const selector = `rect.scheme-${scheme}`;
const categoryColor = d3.scaleOrdinal(d3[categoryScheme]);

chart.container.selectAll(selector)
.data(data.slice())
.enter()
.append('rect')
.classed(selector, true)
.attr('x', d => bands(d))
.attr('y', (chart.height / 2) - ((i * height) +
(padding * i)))
.attr('width', bands.bandwidth)
.attr('height', height)
.style('fill', d => categoryColor(d));
});

This renders all of the color schemes. Snazzy!

For more on D3's category scales, visit https://github.com/d3/d3-scale#category-scales.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset