我需要制作一个D3 BoxPlot。 我有一个包含数十亿行的数据集,将原始数据发送到客户端是不可行的。所以,我创建了一个API,并且只发送了包含每列的max / min / std_dev值的汇总版本。
在所有示例中(one two)我看到使用D3 BoxPlot,数据摘要是在客户端完成的(与我的情况相反)。
是否可以将BoxPlot与已计算的数据一起使用?有人有例子吗?
答案 0 :(得分:4)
好吧,既然你已经获得了已经计算过的数据,那么这里的任务就更容易了!
首先,让我们设定比例。在您comment中复制/粘贴的数据中,您有max
和min
,我将用于第三和第一四分位数。由于您的数据中没有第二个四分位数(中位数),因此我会使用mean
。此外,由于您的数据有3个相同的对象,我会稍微更改它,以使框不同。
所以,设置y比例:
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.max
}) * 1.1])
.range([h - padding, padding]);
这是标准的线性刻度。
对于x刻度,我使用带刻度:
var xScale = d3.scaleBand()
.domain(data.map(function(d) {
return d.label
}))
.range([padding, w - padding])
.padding(0.4);
给我们矩形的左右限制是非常好的。
现在,只需要打印矩形和线条(中位数)。
对于矩形,请注意数学以将第三个四分位数作为矩形的顶部,并将第一个四分位数作为其高度(y
和height
属性):
var boxes = svg.selectAll("foo")
.data(data)
.enter()
.append("rect")
.attr("fill", "none")
.attr("stroke", "black")
.attr("x", function(d) {
return xScale(d.label)
})
.attr("width", xScale.bandwidth())
.attr("y", function(d) {
return yScale(d.max)
})
.attr("height", function(d) {
return yScale(d.min) - yScale(d.max)
});
最后,对于这些行,我们只对mean
和y1
值使用y2
:
var lines = svg.selectAll("foo")
.data(data)
.enter()
.append("line")
.attr("stroke", "black")
.attr("stroke-width", 4)
.attr("x1", function(d) {
return xScale(d.label)
})
.attr("x2", function(d) {
return xScale(d.label) + xScale.bandwidth()
})
.attr("y1", function(d) {
return yScale(d.mean)
})
.attr("y2", function(d) {
return yScale(d.mean)
})
以下是包含数据结构的演示:
var data = [{
"count": "2",
"min": "1.6",
"max": "4.1",
"label": "labelA",
"stddev": "0.72",
"mean": "3.1"
}, {
"count": "2",
"min": "1.1",
"max": "2.9",
"label": "labelB",
"stddev": "0.72",
"mean": "2.2"
}, {
"count": "2",
"min": "2.4",
"max": "3.6",
"label": "labelC",
"stddev": "0.72",
"mean": "2.7"
}];
var w = 500,
h = 200,
padding = 30,
padding2 = 20;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.max
}) * 1.1])
.range([h - padding2, 10]);
var xScale = d3.scaleBand()
.domain(data.map(function(d) {
return d.label
}))
.range([padding, w - padding])
.padding(0.4);
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
var gX = svg.append("g")
.attr("transform", "translate(0," + (h - padding2) + ")")
.call(xAxis);
var gY = svg.append("g")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
var boxes = svg.selectAll("foo")
.data(data)
.enter()
.append("rect")
.attr("fill", "none")
.attr("stroke", "black")
.attr("x", function(d) {
return xScale(d.label)
})
.attr("width", xScale.bandwidth())
.attr("y", function(d) {
return yScale(d.max)
})
.attr("height", function(d) {
return yScale(d.min) - yScale(d.max)
});
var lines = svg.selectAll("foo")
.data(data)
.enter()
.append("line")
.attr("stroke", "black")
.attr("stroke-width", 4)
.attr("x1", function(d) {
return xScale(d.label)
})
.attr("x2", function(d) {
return xScale(d.label) + xScale.bandwidth()
})
.attr("y1", function(d) {
return yScale(d.mean)
})
.attr("y2", function(d) {
return yScale(d.mean)
})

<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
PS:获得胡须的数据后,您可以按照相同的原则简单地添加用于创建此基本结构的行的代码。
答案 1 :(得分:1)
您可以在d3fc中找到boxplot渲染组件:
https://d3fc.io/api/series-api.html#boxplot
您可以使用此功能呈现已经汇总的数据
(完全披露:我是d3fc的作者之一)