const fruits = ["Apples", "Oranges", "Bananas"];
const colors = ["red", "orange", "yellowgreen"];
const rawData = fruits.map((obj, f) => {
let v = 1;
return d3.range(30).map(i => ({
fruit: f,
index: i,
value: v *= (0.95 + Math.random() * 0.1)
}));
}).flat();
const nestedData = d3.nest()
.key(d => d.fruit)
.entries(rawData);
const width = 800,
height = 200;
const x = d3.scaleLinear()
.domain([0, 29])
.range([0, width]);
const y = d3.scaleLinear()
.domain(d3.extent(rawData, d => d.value))
.range([height, 0])
.nice();
const color = d3.scaleOrdinal()
.domain(fruits)
.range(colors);
const line = d3.line()
.x(d => x(d.index))
.y(d => y(d.value));
const svg = d3.select("svg")
.attr("width", width)
.attr("height", height);
const lineGroup = svg.selectAll(".line-group")
.data(nestedData)
.enter()
.append("g")
.attr("class", "line-group");
lineGroup.append("path")
.datum(d => d.values)
.attr("class", "line")
.attr("stroke", d => color(d[0].fruit))
.attr("d", line);
lineGroup.selectAll("circle")
.data(d => d.values)
.enter()
.append("circle")
.attr("class", "dot")
.attr("stroke", d => color(d.fruit))
.attr("r", 5)
.attr("cx", d => x(d.index))
.attr("cy", d => y(d.value));
.line {
fill: none;
stroke-width: 2px;
}
.dot {
stroke-width: 2px;
fill: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>