d3中的小提琴情节

时间:2016-02-29 08:20:26

标签: d3.js

我需要在d3中建立一个带有离散数据点的小提琴点。

示例:

weight vs group discrete violin plot

我不确定如何在X轴上对齐每个值的中心。默认行为将覆盖具有相同X和Y值的所有点,但是我希望这些点在中心对齐时偏移,例如, 5.1在控制组中有3个值,4.5有2个值,所有中心对齐。通过将每个点转换指定的量,可以很容易地进行右对齐或左对齐。然而,中心对齐似乎很苛刻。

一种hacky方式是通过维护几个数组来手动转换X值,以查看这是第一个,偶数还是奇数个元素,并根据我指定的值放置它。有没有正确的方法来解决这个问题?

我发现d3中唯一的小提琴情节示例是here - 它实现了概率分布而不是我需要的离散值。

1 个答案:

答案 0 :(得分:2)

“一种hacky方式是通过维护几个数组手动转换X值” - 这几乎是大多数d3布局的工作方式:-)。通过y值(权重)对数据集进行分散,保留每个离散组中的数据点总数以及每个数据的组索引。然后使用它们来计算偏移x-way和舍入的y值。

请参阅https://jsfiddle.net/n444k759/4/

// below code assumes a svg and g group element are present (they are in the jsfiddle)
var yscale = d3.scale.linear().domain([0,10]).range([0,390]);
var xscale = d3.scale.linear().domain([0,2]).range ([0,390])
var color = d3.scale.ordinal().domain([0,1]).range(["red", "blue"]);
var data = [];
for (var n = 0; n <100; n++) {
    data.push({weight: Math.random() * 10.0, category: Math.floor (Math.random() * 2.0)});
}

var groups = {};
var circleR = 5;

var discreteTo = (circleR * 2) / (yscale.range()[1] / yscale.domain()[1]);
data.forEach (function(datum) {
    var g = Math.floor (datum.weight / discreteTo);
  var cat = datum.category;
  var ref = cat+"-"+g;
  if (!groups[ref]) { groups[ref] = 0; }
  datum.groupIndex = groups[ref];
  datum.discy = yscale (g * discreteTo);    // discrete
  groups[ref]++;
});
data.forEach (function(datum) {
 var cat = datum.category;
    var g = Math.floor (datum.weight / discreteTo);
  var ref = cat+"-"+g;
  datum.offset = datum.groupIndex - ((groups[ref] - 1) / 2);
});

d3.select("svg g").selectAll("circle").data(data)
.enter()
.append("circle")
  .attr("cx", function(d) { return 50 + xscale(d.category) + (d.offset * (circleR * 2)); })
  .attr("r", circleR)
  .attr("cy", function(d) { return 10 + d.discy; })
  .style ("fill", function(d) { return color(d.category); })
;

上述示例根据显示的大小和要显示的圆的大小分组。您可能希望按给定间隔离散,然后从中计算出圆的大小。

修改:已更新,以显示如何区分何时类别不同,如上面的屏幕截图