How can i draw a linechart like this in d3js?
CodePudding user response:
You can draw individual line charts which are translated vertically. Translating them vertically can be achieved by placing each chart into a SVG group (g
) and translating the group by setting the transform
attribute.
They all share the same x
axis with the same domain
and range
.
const x = d3.scaleLinear()
.domain([d3.min(t), d3.max(t)])
.range([0, width]);
Here is the entire code:
// dummy data with common domain for all charts
const t = d3.range(200).map(o => o * 0.1 1);
// three series of data => three charts
const data = [
t.map(t => (1 Math.cos(t))/2),
t.map(t => 1 - 1/Math.pow(0.2*t, 2)),
t.map(t => (1 Math.sin(t))/2),
];
// three different colors for three graphs
const graphColor = ['#F2CD5C', '#a71df2', '#A61f69'];
// we need to add some margin to see the full axis
const margin = { top: 10, bottom: 75, left: 30, right: 10 };
// static width and height - change this to whatever suits you
const width = 300;
const height = 400;
// the height of each stacked
const singleChartHeight = height / data.length;
const svg = d3.select('#stacked-charts')
.append('svg')
// set the size of the chart
.attr('width', width margin.left margin.right)
.attr('height', height margin.top margin.bottom)
.attr("viewBox", [0, 0, width, height]);
// create a common x-axis for all charts
const x = d3.scaleLinear()
.domain([d3.min(t), d3.max(t)])
.range([0, width]);
// a global group with padding
const coreGroup = svg.append('g')
.attr('class', 'stacked-charts')
// translate the padding
.attr('transform', 'translate(' margin.left ' 0)');
// create three different y-axes - one for each series
const y = data.map(dataSeries => {
return d3.scaleLinear()
.domain([d3.min(dataSeries), d3.max(dataSeries)])
.range([singleChartHeight, 0]);
});
// the line generator
const lineGenerator = d3.line();
// create a chart for each series of data
data.forEach((dataSeries, chartIndex) => {
// create an individual group
const chartGroup = coreGroup.append('g')
.attr('class', 'chart')
// stack by translating vertically
.attr('transform', 'translate(0 ' (chartIndex * singleChartHeight) ')');
// use x/y axes to create the points
const points = t.map((timestamp, timeStampIndex) => {
return [
// the x value
x(timestamp),
// the y value from one of the three axes
y[chartIndex](dataSeries[timeStampIndex])
]
});
// create the SVG path for the line
const path = lineGenerator(points);
// draw the graph
chartGroup.append('path')
.attr('class', 'graph')
.attr('d', path)
.attr('fill', 'none')
.attr('stroke', graphColor[chartIndex]);
// add x axis
chartGroup.append('g')
.attr('class', 'x-axis')
.call(d3.axisBottom(x))
.attr('transform', 'translate(0 ' singleChartHeight ')');
// add y axis
chartGroup.append('g')
.attr('class', 'y-axis')
.call(d3.axisLeft(y[chartIndex]));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div style="text-align: center;">
<h1>Stacked Linear Charts</h1>
<div id="stacked-charts"></div>
</div>
If you want all charts to have the same y-scale, they could also share the same y-axis.