【问题标题】:Overlap in d3 wordcloudd3 wordcloud中的重叠
【发布时间】:2014-05-09 16:24:18
【问题描述】:

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

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

在以下示例中,我使用来自 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>

testdata是这样的(例子中没有用到颜色信息):

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 脚本,我的词云就会出现重叠。有时它只在几次重新加载后才会发生,但它相当频繁。

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

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

有什么想法吗?

谢谢!

【问题讨论】:

  • 同意有困难。然而,稍微调整一下尺寸(布局和 svg 尺寸)和字体系列,可能会达到偶尔且相对温和的重叠(但这些重叠的可接受程度可能有点主观)。无论如何,这是我创建的plunk 来玩它。至少,我相信这些维度在排除单词后得到了改善……看起来它们中的大多数都在那里(尽管它们需要全部都在那里)。
  • 是的,谢谢。据我所知,您更改了尺寸和字体?对于这个例子来说,它确实工作得很好。但是,我真的很想解决这个问题。实际上,我很惊讶它的发生,因为词云布局的重点应该是避免重叠,我看到了很多赞誉。
  • 你是对的。这就是我所做的。同意你的看法,需要一个通用的解决方案。我们可能会遗漏一些东西......我没有时间深入研究它。你也可以写邮件到Jason

标签: javascript d3.js overlap word-cloud


【解决方案1】:

我最终问了 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();

【讨论】:

  • 不,它只是调整了屏幕上单词的分布,使框更小,导致更多重叠
  • 常见问题: 未将 SVG 文本锚定到中心,.attr("text-anchor", "middle")
  • 我的问题仍然存在
【解决方案2】:

作者的修复对我不起作用。 所做的工作是在云布局设置中指定.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')

【讨论】:

    【解决方案3】:

    我已经尝试了一个样本供你摆弄, 请看一看。 wordcloud without overlap

    基本上:

    <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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-08
      • 1970-01-01
      • 2013-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多