You need to use x, y, cx and cy to position your elements on the page, but how do you translate your data (number of ducks, weight of gold, etc) into a number of pixels on the screen? SCALES!
How scales work
When you use a scale, you need to decide on three things.
Scale type: What type of scale are you using?
Domain: What values are you going to send the scale? (from your data)
Range: What values do you expect to get back? (pixels on screen)
For example d3.scaleLinear().domain([0,10]).range([0,960]): it’s a linear scale that expects inputs between 0 and 10 and translates them into numbers between 0 to 960. If I send it 10, it’ll send me back 960. If I send it 5, it’ll return 480.
What scale do I use?
If your data is quantitative, it’s usually a scaleLinear(). If you’re dealing with a circle’s radius, though, it’s scaleSqrt().
If your data is nominal, it gets a little more complicated with d3.ordinal(), d3.scalePoint(), d3.scaleBand() etc.
NOTE: In the examples below, ... means I’ve hidden some code from you. If you’d like to view the code, first click the Open Example In New Window link. Then select View from your top menu, then Developer > View Source.
Numeric/quantitative variables on the x or y axis
When you’re working with quantitative variables on a plane, you generally use d3.scaleLinear().
Look at how I use the scale for cx to position both the circles and the text in the example below.
Nominal/categorical variables on the x or y axis (POINTS ONLY)
If you’re putting evenly spaced circles on the screen, a.k.a. putting a nominal category on a planar variable (x or y), you’ll use d3.scalePoint(). You give it a list of all of your quantitative variables and it evenly spaces them out for you.
Look at how I use the scale to set the cx for circles and x for the text below.
Instead of giving the list of names manually, you can also use .map to translate the list of data points into a list of names.
Nominal/categorical variables on the x or y axis (BARS ONLY)
If you’re putting evenly spaced bars on the screen, a.k.a. putting a nominal category on a planar variable (x or y), you’ll use d3.scaleBand(). You give it a list of all of your quantitative variables and it evenly spaces out the bars out for you.
Along with the x, this also gives you the width of your rectangles (or if you’re going on the y axis, the height). If you don’t want all of the bars squished together, you’ll want to add .padding(0.1) when you’re working on the scaleBand.
If you’d like to take categories and turn them into colors, you use a d3.scaleOrdinal(d3.schemeCategory10), which is horrible to read, yes. You don’t need to specify a domain or range - it just works automatically, and it comes with default colors which we’ll just use for now.
When you’re dealing with area of circles, you increase the radius not linearly but rather as a square root. Don’t worry about why yet, just know it’s how you do it.
Remember when we used d3.scaleBand() up above to space out some bars? The bars get pretty boring if you don’t bring something quantitative in. So let’s space the bars out with one scale, then change their size/length with another scale.
We’re going to use a d3.scaleLinear() because we want the bars to increase in size/length just as the data points are increasing.
But hey… Did you notice that the bars are, uh, going in the wrong direction? That’s because x and y set the top left-hand side, and height grows DOWN from there, so if y is always the same, our bars always going to be growing DOWN from the same line on the y axis.
The solution is instead of basing our y on a set number, we say “start drawing the rect from [bar height] pixels from the bottom of the screen”, a.k.a. height - heightScale(y.ducks). If you don’t get it, that’s perfectly fine, just memorize it for now.