Перерисовывание облака слов с помощью d3.wordcloud - PullRequest
0 голосов
/ 08 мая 2018

Я использую d3.wordcloud (https://github.com/wvengen/d3-wordcloud) и пытаюсь стереть мое текущее облако слов и нарисовать новое по нажатию кнопки. Это хорошо работает в первый раз, когда облако слов нарисовано, но при каждом последующем рисовании размеры шрифта все больше выходят из строя.

Вот как это выглядит при первом запуске и после пары последовательных прогонов:

первый запуск

последний запуск

Наблюдая, я вижу, что диапазон размеров шрифта уменьшается после каждого запуска, в конечном счете устанавливая каждое слово размером 10 или 100. Я считаю, что проблема происходит в обновлении функции в d3.wordcloud .js , но я не уверен, как решить эту проблему.

  function update() {
     var words = layout.words();
     fontSize = d3.scale[scale]().range([10, 100]);

     if (words.length) {
         fontSize.domain([+words[words.length - 1].size || 1, +words[0].size]);
       }
  }

Код, который я запускаю, основан на примере , предоставленном в хранилище, с меньшим объектом слова для целей тестирования и кнопкой для перерисовки кода.

А вот и живая демонстрация:

var test_words = [
        {text: 'have', size: 102},
        {text: 'Oliver', size: 47},
        {text: 'say', size: 46},
        {text: 'said', size: 36},
        {text: 'bumble', size: 29, href: 'https://en.wikipedia.org/wiki/Beadle'},
        {text: 'will', size: 29},
        {text: 'Mrs', size: 56, href: 'https://en.wikipedia.org/wiki/Mrs.'},
        {text: 'Mann', size: 27, href: 'http://educationcing.blogspot.nl/2012/06/oliver-twist-mrs-manns-character.html'},
        {text: 'Mr', size: 27},
        {text: 'very', size: 26},
        {text: 'child', size: 20},
        {text: 'all', size: 19},
        {text: 'boy', size: 19},
        {text: 'gentleman', size: 19, href: 'http://www.thefreelibrary.com/The+gentleman+in+the+white+waistcoat%3a+Dickens+and+metonymy.-a0154239625'},
        {text: 'great', size: 19},
        {text: 'take', size: 19},
        {text: 'but', size: 18},
        {text: 'beadle', size: 16},
        {text: 'twist', size: 16},
        {text: 'board', size: 15},
        {text: 'more', size: 15},
        {text: 'one', size: 15}
      ];
      
d3.wordcloud()
        .size([600, 275])
        .transitionDuration(1000)
        .fill(d3.scale.ordinal().range(["#884400", "#448800", "#888800", "#444400"]))
        .words(test_words)
        .onwordclick(function(d, i) {
          if (d.href) { window.location = d.href; }
        })
        .start();

      d3.select('#dataset-picker').selectAll('.dataset-button')
        .on("click", function() {
          //clear the wordcloud div
          document.getElementById("wordcloud").innerHTML = "";
          var a2 = d3.wordcloud()
            .size([600, 275])
            .transitionDuration(1000)
            .fill(d3.scale.ordinal().range(["#884400", "#448800", "#888800", "#444400"]))
            .words(test_words)
            .onwordclick(function(d, i) {
              if (d.href) { window.location = d.href; }
            })
            .start();
        });
<html>
  <head>
    <meta charset="UTF-8">
    <title>Word Cloud</title>
    <script src="https://cdn.rawgit.com/wvengen/d3-wordcloud/master/lib/d3/d3.js"></script>
    <script src="https://cdn.rawgit.com/wvengen/d3-wordcloud/master/lib/d3/d3.layout.cloud.js"></script>
    <script src="https://cdn.rawgit.com/wvengen/d3-wordcloud/master/d3.wordcloud.js"></script>
    <!-- <script src="test_words.js"></script> -->
  </head>
  <body style="text-align: center">
    <h1>Word Cloud</h1>
    <div id='wordcloud'></div>
    <div id="dataset-picker">
      <input id ="test" value="test" class="dataset-button" type="button">
    </div>
      </body>
</html>

Спасибо.

1 Ответ

0 голосов
/ 08 мая 2018

Это немного сложно. Плагин d3-wordcloud (точнее, базовый плагин d3.layout.cloud) изменит ваш входной набор слов слов, чтобы адаптировать размер слов.

Понемногу определенные слова будут все больше и больше, а другие все меньше и меньше.

Чтобы избежать этого, вы можете предоставлять плагин каждый раз, когда создаете новое облако с deep copy исходного набора данных. Таким образом, исходный набор данных всегда остается нетронутым:

Вот способ глубокого копирования json с помощью javascript:

function deepCopy(oldValue) { 
  var newValue
  strValue = JSON.stringify(oldValue)
  return newValue = JSON.parse(strValue)
}

который вы передаете плагину wordcloud следующим образом:

.words(deepCopy(test_words))

А вот демо:

var test_words = [
        {text: 'have', size: 102},
        {text: 'Oliver', size: 47},
        {text: 'say', size: 46},
        {text: 'said', size: 36},
        {text: 'bumble', size: 29, href: 'https://en.wikipedia.org/wiki/Beadle'},
        {text: 'will', size: 29},
        {text: 'Mrs', size: 56, href: 'https://en.wikipedia.org/wiki/Mrs.'},
        {text: 'Mann', size: 27, href: 'http://educationcing.blogspot.nl/2012/06/oliver-twist-mrs-manns-character.html'},
        {text: 'Mr', size: 27},
        {text: 'very', size: 26},
        {text: 'child', size: 20},
        {text: 'all', size: 19},
        {text: 'boy', size: 19},
        {text: 'gentleman', size: 19, href: 'http://www.thefreelibrary.com/The+gentleman+in+the+white+waistcoat%3a+Dickens+and+metonymy.-a0154239625'},
        {text: 'great', size: 19},
        {text: 'take', size: 19},
        {text: 'but', size: 18},
        {text: 'beadle', size: 16},
        {text: 'twist', size: 16},
        {text: 'board', size: 15},
        {text: 'more', size: 15},
        {text: 'one', size: 15}
      ];

      function deepCopy(oldValue) { 
        var newValue
        strValue = JSON.stringify(oldValue)
        return newValue = JSON.parse(strValue)
      }

      var cloud = d3.wordcloud()
        .size([500, 275])
        .transitionDuration(1000)
        .fill(d3.scale.ordinal().range(["#884400", "#448800", "#888800", "#444400"]))
        .words(deepCopy(test_words))
        .onwordclick(function(d, i) {
          if (d.href) { window.location = d.href; }
        })
        .start();

      d3.select('#dataset-picker').selectAll('.dataset-button')
        .on("click", function() {
          //clear the wordcloud div
          // cloud.remove();
          document.getElementById("wordcloud").innerHTML = "";
          var cloud = d3.wordcloud()
            .size([500, 275])
            .transitionDuration(1000)
            .fill(d3.scale.ordinal().range(["#884400", "#448800", "#888800", "#444400"]))
            .words(deepCopy(test_words))
            .onwordclick(function(d, i) {
              if (d.href) { window.location = d.href; }
            })
            .start();
        });
<html>
  <head>
    <meta charset="UTF-8">
    <title>Word Cloud</title>
    <script src="https://cdn.rawgit.com/wvengen/d3-wordcloud/master/lib/d3/d3.js"></script>
    <script src="https://cdn.rawgit.com/wvengen/d3-wordcloud/master/lib/d3/d3.layout.cloud.js"></script>
    <script src="https://cdn.rawgit.com/wvengen/d3-wordcloud/master/d3.wordcloud.js"></script>
  </head>
  <body style="text-align: center">
    <h1>Word Cloud</h1>
    <div id='wordcloud'></div>
    <div id="dataset-picker">
      <input id ="test" value="test" class="dataset-button" type="button">
    </div>
      </body>
</html>
...