I have data in the following format which I would like to plot using d3:
data = [
{ x: 0.2, y: [ 1, 2, 4 ] },
{ x: 0.3, y: [ 2 ] },
{ x: 0.5, y: [ 4, 7, 8, 12, 19 ] }
{ x: 1.4, y: [ 1, 3 ] }
]
Normally the y-axis values are integers, but here they are arrays, so the following code doesn't work as intended:
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d){ return x(d.x) })
.attr("cy", function(d){ return y(d.y) })
.attr("r", 2)
Instead of getting multiple circles plotted for each of the values in the array, I only get one.
Other similar questions on this website deal only with data that has a fixed number of y-axis values, so I haven't found a way to modify those solutions for this problem.
The traditional D3 answer here would be appending a group for each object and then appending a circle for each y
value for each group.
However, since you seem to be a D3 beginner (correct me if I'm wrong), I'd suggest to just create a single array of objects, that you can pass to data
.
There are several ways for doing this, such as:
const newData = data.reduce(function(a, c) {
return a.concat(c.y.map(function(d) {
return {
x: c.x,
y: d
}
}));
}, []);
Here is your code with that change:
const data = [{
x: 0.2,
y: [1, 2, 4]
},
{
x: 0.3,
y: [2]
},
{
x: 0.5,
y: [4, 7, 8, 12, 19]
}, {
x: 1.4,
y: [1, 3]
}
];
const newData = data.reduce(function(a, c) {
return a.concat(c.y.map(function(d) {
return {
x: c.x,
y: d
}
}));
}, []);
const x = d3.scaleLinear()
.domain([0, 2])
.range([0, 300]);
const y = d3.scaleLinear()
.domain([0, 20])
.range([0, 150]);
const svg = d3.select("svg");
svg.selectAll("circle")
.data(newData)
.enter()
.append("circle")
.attr("cx", function(d) {
return x(d.x)
})
.attr("cy", function(d) {
return y(d.y)
})
.attr("r", 4)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>