8

我使用 Jason Davies 的 d3 wordcloud 库(https://github.com/jasondavies/d3-cloud),我的问题是云中的单词重叠。

我知道在堆栈溢出(和其他站点)上已经存在关于此问题的问题,但这些对我的情况都没有帮助。

在下面的示例中,我使用来自 Jason Davies 站点的示例云,并且只更改了一些内容:

  • 我从外部文件中读取了我的单词及其大小。
  • 我将旋转设置为 0。但旋转角度似乎没有什么不同。
  • 我注释掉了“Impact”字体,以排除加载字体的任何问题。(不过也没什么区别。)

这是我的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="d3.js"></script>
<script src="d3.layout.cloud.js"></script>
<script>
   d3.tsv("testdata.txt", 
  function(error, data) {

  var fill = d3.scale.category20();



  d3.layout.cloud().size([300, 300])
      .words(data)
      .padding(1)
      .rotate(function(d) { return 0; })
  //    .font("Impact")
      .fontSize(function(d) { return d.size; })
      .on("end", draw)
      .start();

  function draw(words) {
    d3.select("body").append("svg")
        .attr("width", 300)
        .attr("height", 300)
      .append("g")
        .attr("transform", "translate(150,150)")
      .selectAll("text")
        .data(words)
      .enter().append("text")
        .style("font-size", function(d) { return d.size + "px"; })
    //    .style("font-family", "Impact")
        .style("fill", function(d, i) { return fill(i); })
        .attr("text-anchor", "middle")
        .attr("transform", function(d) {
          return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
        })
        .text(function(d) { return d.word; });
  }
  }
  )

</script>

测试数据如下所示(示例中未使用颜色信息):

word    size    color
der 39  #a9a9a9
die 37  #a9a9a9
und 30  #a9a9a9
athenischen 29  #a9a9a9
Die 29  #a9a9a9
eine    28  #a9a9a9
,   27  #a9a9a9
einer   26  #a9a9a9
attischen   26  #a9a9a9
liberalen   26  #1e90ff
zur 25  #a9a9a9
athenische  24  #a9a9a9
christliche 23  #a9a9a9
attische    23  #a9a9a9
_START_ 22  #a9a9a9 
reinen  22  #a9a9a9
englischen  21  #a9a9a9 
oder    21  #a9a9a9
--  21  #a9a9a9
radikalen   21  #a9a9a9
Q*M 21  #a9a9a9
Q*M 21  #a9a9a9
christlichen    20  #a9a9a9
schöne  20  #1e90ff
repräsentativen 20  #a9a9a9
sozialen    20  #a9a9a9
hellenische 19  #1e90ff
modernen    19  #a9a9a9
radikale    19  #a9a9a9
griechische 19  #a9a9a9
-   18  #a9a9a9
schönen 18  #1e90ff
alle    18  #a9a9a9
radicalen   18  #a9a9a9
als 17  #a9a9a9
neuen   17  #a9a9a9
perikleischen   16  #a9a9a9
bürgerlichen    16  #a9a9a9
Namen   16  #1e90ff

如果我用测试数据运行 js 脚本,我的词云就会出现重叠。有时它只在几次重新加载后才会发生,但它相当频繁。

其他人报告了同样的问题,发现它与使用网络字体或跳过旋转参数有关。这不适用于我的示例。

我怀疑这可能与画布大小有很多单词有关,但是,我也做了一些测试,我显着增加了画布大小并且它仍然发生(虽然不太频繁,因为单词的随机放置降低了可能性)。除此之外,您可以看到由于画布尺寸较小,根本没有显示几个单词。为什么要留下一些并为其他人创造重叠?所以我认为问题出在其他地方。

有任何想法吗?

谢谢!

4

3 回答 3

18

我最终问了 Jason Davies 本人,这实际上是一个非常简单的错误:您必须在第一条语句中指定文本访问器函数(不仅在“draw”函数中)。如果你像这样添加一行,它会起作用:

d3.layout.cloud().size([300, 300])
  .words(data)
  .padding(1)
  .rotate(function(d) { return 0; })
//    .font("Impact")
  .text(function(d) { return d.word; }) // THE SOLUTION
  .fontSize(function(d) { return d.size; })
  .on("end", draw)
  .start();
于 2014-05-12T15:56:47.590 回答
3

作者的修复对我不起作用。起作用的是在云布局设置中指定绘制代码中声明相同的字体系列 - 具有讽刺意味的是,上面的作者已经注释掉了。这为代码提供了计算尺寸的字体。没有它,它需要一个最好的猜测。.font()

d3.layout.cloud().size([800, 400])
  .words(words)
  .font('Impact') // <-- what mattered
  .fontSize(d => d.size)
  .on('end', draw)
  .start()

需要在函数中指定字体系列,draw()以便云以与您在上面声明的内容匹配的正确字体呈现单词:

.attr('font-family', 'Impact')
于 2018-12-19T04:47:45.840 回答
1

我已经尝试了一个样品供您摆弄,请看一下。 wordcloud 没有重叠

本质上:

<div id="cloud"></div> 

// First define your cloud data, using `text` and `size` properties:


var fill = d3.scale.category20();
var words = {
"Battery Related": "52382",
"Billing": "52412",
"Break Related": "52490",
"Chain Related": "52471",
"Clutch Related": "52468",
"Dealer attitude": "52488",
"Electrical Related": "52352",
"Engine Related": "52446",
"Handle Bar Related": "52486",
"Happy": "52472",
"Jerking": "52325",
"Jerking Problem": "52325",
"Low Mileage": "52489",
"Noise": "52462",
"Poor Pickup": "52406",
"Running Off": "52242",
"Service Quality": "52488",
"Silencer Problem": "52468",
"Starting Trouble": "52490",
"Suspension Related": "52365",
"Vehicle Noise": "52467",
"Vibration": "52463",
"Washing": "52488"
};
var max_freq = 52490;
var cloudwords = ["Battery Related", "Billing", "Break Related", "Chain Related", "Clutch Related", "Dealer attitude", "Electrical Related", "Engine Related", "Handle Bar Related", "Happy", "Jerking", "Jerking Problem", "Low Mileage", "Noise", "Poor Pickup", "Running Off", "Service Quality", "Silencer Problem", "Starting Trouble", "Suspension Related", "Vehicle Noise", "Vibration", "Washing"];
var url = 'http://xxx.yyyy.zz.ww/?q=abc/';
var width = 800,
height = 800;

var leaders = cloudwords
.map(function(d) {

return {
  text: d,
  size: 5 + (words[d] / max_freq) * 0.9 * 30 // *the size of the "box" occupied by each word. has no relation to text size.
};
})
 .sort(function(a, b) {
 return d3.descending(a.size, b.size)
});

var leaderScale = d3.scale.linear().range([1, 20]); // *scale range to plot the relative sizes of the words.

leaderScale.domain([d3.min(leaders, function(d) {
return d.size;
}),
d3.max(leaders, function(d) {
return d.size;
})
]);

 // Next you need to use the layout script to calculate the placement, rotation and size of each word:

 d3.layout.cloud().size([width, height])
.words(leaders)
.padding(0) //fiddle with padding here, does not really have any effect    on overlap.
.rotate(function() {
 return ~~0; //to keep the words horizontal 
 })
 .font("Impact")
 .fontSize(function(d) {
 return d.size;
 })
 .on("end", drawCloud)
 .start();

 function drawCloud(words) {
 d3.select("#cloud").append("svg")
 .attr("width", width)
 .attr("height", height)
 .attr("text-align", "center")
 .append("g")
 .attr("transform", "translate(" + [width >> 1, height >> 1] + ")")    //for transalting words to their different postions.
 .selectAll("text")
 .data(words)
 .enter().append("text")
 .style("font-size", function(d) {
  return leaderScale(d.size) + "px"; //used scale to resize words to a linear scale.
 })
 .style("font-family", "Impact")
 .style("fill", function(d, i) {
  return fill(i);
 })
 .attr("text-anchor", "middle")
 .attr("transform", function(d) {
  return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
 })
 .text(function(d) {
  return d.text;
 })
 .on("click", function(d, i) {
  window.open(url + d.text);
 });
 }

 // set the viewbox to content bounding box (zooming in on the content, effectively trimming whitespace)

 var svg = document.getElementsByTagName("svg")[0];
 var bbox = svg.getBBox();
 var viewBox = [bbox.x, bbox.y, bbox.width, bbox.height].join(" ");
 svg.setAttribute("viewBox", viewBox);
于 2017-02-08T10:59:49.630 回答