Rendering postion is a key point to draw a graph.
D3.js has its own abstruction layer translating stastical values into SVG pixel postions.
Render data to visual coordinates
For basic graph area rendering, d3 provides a set of
d3-scale sub-modules.
The API reference shows example:
var x = d3.scaleLinear()
.domain([10, 130])
.range([0, 960]);
- d3-scale creates a function
- Resulting
x
can be used asx(val)
, convertingval
into x-coordinatte. - Basically each graph should have
x
andy
functions generatid with d3-scale.
- Resulting
- Map with shape, input and output
- scaleLinear() above is a shape with the most basic scale 1 by 1. There’re other shapes like scalePow(), scaleLog.
- domain() specifies the range of input values. The basic parameter is array of [min, max].
- range() specifies the range of output values. For rendering, it typically means [min, max] of SVG pixels.
For popular vertical coordinate like Y-axis, output range() parameter should be reversed like range([500, 0])
.
SVG pixels start from 0 at top-left that corresponds with max input value.
With scale functions like this, we can draw SVG circle as a data point of scatter plots as following:
d3.select('svg').selectAll('circle')
.data(data).enter()
.append('circle')
.attr('cx', function(d) { return x(d.val_x) })
.attr('cy', function(d) { return y(d.val_y) });
cx
means the position in SVG x-coordinate, ranging from 0px to 960px by range()
parameter of x()
.
Split graph area into sub-blocks
If you want to separate coordinates in several categories, you can use
Band scales.
It calculates positions from domain counts, optionally with padding. For a simple example, bar graphs have such a categorical domains.
var x = d3.scaleBand()
.domain(["category1", "category2", "category3"])
.range([0, 960]);
Parts composition
For composite rendering that have multiple sub parts, you can create each part with SVG g element.
var base = d3.select('svg');
var sub_area = base.append('g')
.attr('id', 'sub_area')
.attr('width', 300)
.attr('height', 200)
.attr("transform", `translate(100, 100)`);
id
, width
, height
, transform
are just HTML attributes or CSS properties.
CSS transform can move the left-top position with its translate()
function.
Now sub_area
has its own coordinates, you can just add any element inside range(300, 200)
starting from [0, 0]
position.
sub_area.data(data).enter()
.append('circle')
.attr('cx', function(d) { return x(d.val_x) })
.attr('cy', function(d) { return y(d.val_y) });
Chuma Takahiro