我有一组嵌套的json数据:
var data = [{"time":"2016-03-01","values":[{"specimen_count":1,"trap":"S0024", "species":1},{"specimen_count":2,"trap":"S0025", "species":2},{"specimen_count":2,"trap":"S0026", "species":2}]},{"time":"2016-03-15","values":[{"specimen_count":6,"trap":"S0024", "species":6},{"specimen_count":5,"trap":"S0025", "species":4},{"specimen_count":7,"trap":"S0026", "species":6}]}];
我想绘制一组分组条形图,每组代表一个时间间隔,每组有3个条形,每个条形代表一个陷阱,条形的高度是samples_count字段。
现在我想添加一个散点图,每个条形图一个点,点的高度是物种字段,使用相同的比例。但是我无法成功地将点放在分组条形图的顶部。我确实设法添加了一个包含物种数据的行,但我无法使用相同的逻辑添加点。
这是我的代码:
var margin = {top: 100, right: 20, bottom: 30, left: 40},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x0)
.tickSize(0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var color = d3.scale.ordinal()
.range(["#ca0020","#f4a582","#92c5de"]);
var svg = d3.select('#chart').append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var categoriesNames = data.map(function(d) { return d.time; }); // the 5 time periods
var trapNames = data[0].values.map(function(d) { return d.trap; }); // the name of the traps
console.log(trapNames);
x0.domain(categoriesNames);
x1.domain(trapNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(category) { return d3.max(category.values, function(d) { return d.specimen_count; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style('opacity','0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.text("Value");
svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "slice")
.attr("transform",function(d) { return "translate(" + x0(d.time) + ",0)"; });
slice.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.trap); })
.style("fill", function(d) { return color(d.trap) })
.attr("y", function(d) { return y(0); })
.attr("height", function(d) { return height - y(0); })
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.trap)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.trap));
});
slice.selectAll("rect")
.transition()
.delay(function (d) {return Math.random()*1000;})
.duration(1000)
.attr("y", function(d) { return y(d.specimen_count); })
.attr("height", function(d) { return height - y(d.specimen_count); });
var valueline = d3.svg.line()
.x(function (d) { return x1(d.trap) + x1.rangeBand()/2; })
.y(function (d) { return y(d.species); });
slice.enter()
.append('path')
.attr('class','line')
.style('stroke', "#0571b0")
.style('stroke-width', "3px")
.attr('fill', 'none')
.attr('d', function(d) { return valueline(d.values); });
slice.selectAll('.dot').data(data,function(d){return d.time;})
.enter()
.append("circle")
.attr("class", "dot")
.attr("r",5)
.attr("cx", function(d){
return x1(d.trap) + x1.rangeBand()/2;
})
.attr("cy",function(d){
return y(d.species);
})
.attr("fill","#0571b0");
我从圈子相关代码得到的错误是:d3.min.js:1错误:属性cx:预期长度," NaN"。
我认为条形图的嵌套数据和序数比例让我有点失望,所以在这些情况下我可能不理解完整的数据访问。
答案 0 :(得分:3)
如果您需要每个条形图上的点,那么data()回调必须返回一个条形列表而不是单个项目。您是否尝试将其替换为:
slice.selectAll('.dot')
.data(function(d) {
return d.values;
})
.enter()
.append("circle") //... and so on
执行此操作将使用现有的data
对象(具有5个条组),但为每个条形渲染一个点。
这里正在运行:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.17" data-semver="3.5.17" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
var data = [{
"time": "2016-03-01",
"values": [{
"specimen_count": 1,
"trap": "S0024",
"species": 1
}, {
"specimen_count": 2,
"trap": "S0025",
"species": 2
}, {
"specimen_count": 2,
"trap": "S0026",
"species": 2
}]
}, {
"time": "2016-03-15",
"values": [{
"specimen_count": 6,
"trap": "S0024",
"species": 6
}, {
"specimen_count": 5,
"trap": "S0025",
"species": 4
}, {
"specimen_count": 7,
"trap": "S0026",
"species": 6
}]
}];
var margin = {
top: 100,
right: 20,
bottom: 30,
left: 40
},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x0)
.tickSize(0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var color = d3.scale.ordinal()
.range(["#ca0020", "#f4a582", "#92c5de"]);
var svg = d3.select('#chart').append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var categoriesNames = data.map(function(d) {
return d.time;
}); // the 5 time periods
var trapNames = data[0].values.map(function(d) {
return d.trap;
}); // the name of the traps
console.log(trapNames);
x0.domain(categoriesNames);
x1.domain(trapNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(category) {
return d3.max(category.values, function(d) {
return d.specimen_count;
});
})]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style('opacity', '0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight', 'bold')
.text("Value");
svg.select('.y').transition().duration(500).delay(1300).style('opacity', '1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "slice")
.attr("transform", function(d) {
return "translate(" + x0(d.time) + ",0)";
});
slice.selectAll("rect")
.data(function(d) {
return d.values;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.trap);
})
.style("fill", function(d) {
return color(d.trap)
})
.attr("y", function(d) {
return y(0);
})
.attr("height", function(d) {
return height - y(0);
})
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.trap)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.trap));
});
slice.selectAll("rect")
.transition()
.delay(function(d) {
return Math.random() * 1000;
})
.duration(1000)
.attr("y", function(d) {
return y(d.specimen_count);
})
.attr("height", function(d) {
return height - y(d.specimen_count);
});
var valueline = d3.svg.line()
.x(function(d) {
return x1(d.trap) + x1.rangeBand() / 2;
})
.y(function(d) {
return y(d.species);
});
slice
.append('path')
.attr('class', 'line')
.style('stroke', "#0571b0")
.style('stroke-width', "3px")
.attr('fill', 'none')
.attr('d', function(d) {
return valueline(d.values);
});
slice.selectAll('.dot').data(function(d) {
return d.values;
})
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 5)
.attr("cx", function(d) {
return x1(d.trap) + x1.rangeBand() / 2;
})
.attr("cy", function(d) {
return y(d.species);
})
.attr("fill", "#0571b0");
</script>
</body>
</html>