简体   繁体   English

如何处理d3中的Beeswarm情节中的碰撞?

[英]How to handle collisions in Beeswarm plot in d3?

I've been playing around with this example here for a little while. 我一直在这里玩这个例子。 What I'm trying to do is highlight a single node/circle in the plot (by making it larger with a border; later I want to add text or a letter inside it too). 我要做的是在图中突出显示单个节点/圆(通过使边框更大;稍后我想在其中添加文本或字母)。

Currently, I've made the circle for Bhutan larger in the plot like the following: 目前,我已经在不同的情节中为Bhutan做了更大的圈子,如下所示:

.attr("r", 
    function(d){return ( d.countryName === "Bhutan" ? r + 4 : r);})
.attr("stroke", function(d){if (d.countryName==="Bhutan"){return "black"}})

However, it overlaps with the other circles. 但是,它与其他圆圈重叠。 What would be the best approach to avoid these collisions/overlaps? 什么是避免这些碰撞/重叠的最佳方法? Thanks in advance. 提前致谢。

Link to Plunkr - https://plnkr.co/edit/rG6X07Kzkg9LeVVuL0PH?p=preview 链接到Plunkr - https://plnkr.co/edit/rG6X07Kzkg9LeVVuL0PH?p=preview


I tried the following to add a letter inside the bhutan circle 我尝试了以下内容在不丹圈内添加一封信

    //find bhutan circle and add a "B" to it
    countriesCircles
    .data(data)
  .enter().append("text")
  .filter(function(d) { return d.countryName === "Bhutan"; })
    .text("B");

Updated Plunkr - https://plnkr.co/edit/Bza5AMxqUr2HW9CYdpC6?p=preview 更新了Plunkr - https://plnkr.co/edit/Bza5AMxqUr2HW9CYdpC6?p=preview

This is a slightly different problem than in this question here: How to change the size of dots in beeswarm plots in D3.js 这是一个与此问题略有不同的问题: 如何在D3.js中改变beeswarm图中点的大小

You have a few options that I can think of: 你有几个我能想到的选择:

  • Set the forceCollide to be your largest possible radius * 1.33 , eg (r + 4) * 1.33 . forceCollide设置为您largest possible radius * 1.33largest possible radius * 1.33 ,例如(r + 4) * 1.33 This will prevent overlapping, but spread things out a lot and doesn't look that great. 这样可以防止重叠,但会将事情分散开来,看起来并不那么好。
  • Add the radius property to each entry in your array and make the collide work based off that, which will look a bit better but not perform as awesomely for large sets. 将radius属性添加到数组中的每个条目,并使碰撞工作基于此,这看起来会更好但对大型集合执行效果不是很好。

Here's an example of how to do that: 这是一个如何做到这一点的例子:

...
d3.csv("co2bee.csv", function(d) {
    if (d.countryName === "Bhutan") {
      d.r = r + 4;
    } else {
      d.r = r;
    }
    return d;
}, function(error, data) {
    if (error) throw error;
    var dataSet = data;
...
var simulation = d3.forceSimulation(dataSet)
  ...
  .force("collide", d3.forceCollide(function(d) { return d.r * 1.33; }))
  ...

countriesCircles.enter()
    .append("circle")
    .attr("class", "countries")
    .attr("cx", 0)
    .attr("cy", (h / 2)-padding[2]/2)
    .attr("r",  function(d){ return d.r; })
....

Use the row function in d3.csv to add a property to each member of the array called r , and check the country name to determine which one gets the larger value. 使用d3.csvrow函数将属性添加到名为r的数组的每个成员,并检查国家/地区名称以确定哪个获取更大的值。 Then use that value wherever you need to mess with the radius. 然后在需要的地方使用该值来弄乱半径。

I guess it would've been possible to check the country name everywhere the radius was impacted (eg .force("collide", d3.forceCollide(function(d) { return d.countryName === "Bhutan" ? (r + 4) * 1.33 : r * 1.33; }) , etc.). This feels a bit cleaner to me, but it might be cleaner still by abstracting out the radius from the data entries themselves... 我想有可能在半径受影响的地方检查国名:例如.force("collide", d3.forceCollide(function(d) { return d.countryName === "Bhutan" ? (r + 4) * 1.33 : r * 1.33; })等。)这对我来说感觉有点干净,但是通过从数据条目本身中抽象出半径,它可能更清晰......

Forked your plunk here: https://plnkr.co/edit/Tet1DVvHtC7mHz91eAYW?p=preview 在这里分叉你的插件: https ://plnkr.co/edit/Tet1DVvHtC7mHz91eAYW ? p = preview

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM