Add a word cloud graph
Word cloud is part of Highcharts 6.
-
@Convergence Tester
You're probably a victim of https://github.com/highcharts/highcharts/issues/7300. It is fixed and will be part of the next release. -
Convergence Tester commented
It is showing all words same size. It is not working.
-
Prithvi Maddi commented
I am trying to make a word clickable and trying to change its style mark it as clicked. Is there a way to do that?
-
In my browser it takes consistently 50-60ms: https://jsfiddle.net/bpnq9px7/3/ . Do you have another example where it performs worse?
-
Harry commented
Unstable efficiency. Sometimes take less than a second, sometimes take more than 20 second for the same set of data.
-
Chris commented
When is the GA for Gucharts 6 planned?
Chris
-
Monte Shaffer commented
https://assets.mypatentideas.com/images/fiddle/jquery-words/index.html
This is the jquery plugin I was working on... It could output to canvas and/or div...
The place word correctly isn't fully functioning, and so I started working on
https://assets.mypatentideas.com/images/fiddle/jquery-words/div.html
to troubleshoot why.
I have used highcharts before, and it seems like the best place to develop the final working script. Hence the posts here.
I don't know your highchart-plugin logic, but I am certain you do. I believe most of the algorithm is outlined, with some minor bugs.
I am hoping the algorithm logic is outlined well in my two example pages.
Can your team take over the highchart-plugin? This would benefit me, since I am working on a project that could use this tool, but I am on a 30-day deadline to get a beta-launched, and for now, I can use your 3-d bubble charts.
-
Monte Shaffer commented
Hi,
I believe I have got most of the algorithm finished ...
https://assets.mypatentideas.com/images/fiddle/jquery-words/div.html
It uses the SAT-js algorithm to account for rotation of words, and fit the next words...
The idea would be ... an input would have the following:
word: "Big Font", font: "Times, san-serif", size: "14px"
...The system would have a fill region ... width by height, and
(1) loop over words to compute BBoxes for each, do some calculation to determine that they will fit into the fill region, if not, reduce the "fontFactor" internal number so we know they will fit.
(2) loop over the words again, based on rotation settings, and place each word... "top" "left" should be the anchor for each word, and rotation should happen from top/left... now rotated, loop through previous bboxes to make certain there isn't a rectangle collision (I also create outside border bboxes). If it doesn't collide, we place the word. If it collides, we loop over the next archimedean spiral location.
(3) The algorithm basically works here: https://assets.mypatentideas.com/images/fiddle/jquery-words/div.html ... I was trying to write as a jquery plugin, but ignore that (you can look at it, it does have some "stemming" and other functions to allow a text-string input to build the array of words and freq. The core algorithm is the div.html page itself... very linear logic.
(4) The algorithm would return an array that I could see would easily fit within your highcharts options framework.
-
A Highcharts plugin would be appreciated! Following the series-point concept, I would expect each word to be a point with a name and a value. The points would be laid out inside the plot area.
Use the renderer object for text, including its .getBBox function.
I've set up a boilerplate for you, where I demonstrate rotation, text sizing and tooltip support. Now what's missing is the algorithm itself: http://jsfiddle.net/highcharts/espnodxm/
-
Monte Shaffer commented
The placement / collision computations should probably happen as a thread "worker" ... and then you can create as much data as you want.
If I proceed, I will write as a highcarts plugin, but would prefer if you did so.
Nice work on highcharts...
-
Monte Shaffer commented
You want to allow words to rotate, and not collide, I was using a hidden div approach to identify a particular bbox for a given word, and then sat-js to see if the new word collides with previous words on the screen...
// Version 0.6.0 - Copyright 2012 - 2016 - Jim Riecken <jimr@jimr.ca>
//
// Released under the MIT License - https://github.com/jriecken/sat-js
//
// A simple library for determining intersections of circles and
// polygons using the Separating Axis Theorem.
/** @preserve SAT.js - Version 0.6.0 - Copyright 2012 - 2016 - Jim Riecken <jimr@jimr.ca> - released under the MIT License. https://github.com/jriecken/sat-js */... with canvas you could do a more expensive, tighter lookup to account for whitespace within a bbox...
... also, because these calculations get expensive, you may want to setup as a "worker" in a threaded environment ...
The basic logic:
self.options = $.extend(true, {}, $.fn.cloudMe.options, options ); // load options
self.prepareDrawOptions();
self.prepareStopWords(); // snowball, unbc, tennessess, glasgow ... and custom ... [with basic stemming]
// self.data is generated here
self.prepareInput();
self.prepareSorts();
self.drawMe();where drawMe
first-word is centered, with a given font-size (currently hacked based on freq)
initialBBOXES (get out-of-frame bboxes)
first-word added to BBOXESNEXT WORD
.. randomly determine if rotation will occur.
.. if so, select stepped rotation (we want some order, so rotations align) ... the rotation will alter the corner of the bbox, I rotate around a bbox center...
.. pick a random element on the screen so the rotated bbox will fit within the frame
.. see if this bbox doesn't collide with array of BBOXES previously placed (first-word, top-border, bottom-border, left-border, right-border, ... previous NEXT elements)
.. if it does collide, move the box along an archimedian spiral, and check again ... repeat until placed,
.. add current word to BBOXES stack, and proceed to next word. I place largest words first... the fontsize and color are related to the frequency of times the word appeared...After a few days working on this, I realized it is better within highcharts, if you can make that happen...
The source (not finished) of the logic is here:
https://assets.mypatentideas.com/images/fiddle/jquery-words/index.html
-
Monte Shaffer commented
The logic for the word cloud is rather straight forward, and I have been working on a jquery plugin to do the logic.
http://stackoverflow.com/questions/342687/algorithm-to-implement-a-word-cloud-like-wordle
I was using canvas to build, but highcharts seems the better solution.
$.fn.cloudMe.options = {
data: {
method: "val", // val for INPUT/TEXTAREA, html for DIV, direct for attachment to obj
identifier: "#my-text", // for val or html
object: {}, // you can directly attach
},
methods: {
pluginInitiated: function() {}, // custom function ... object has been initiated ...
preparePre: function(){}, // called before generic prepare function ... raw data is processing
preparePost: function(){}, // called after generic prepare function ... raw data is processing
customWeight: function(){}, // perform a custom weighting on object ... based on n... log(n), sqrt(n), quantile(n)
},
prepare: {
stopwords: {
enabled: true,
language: "en",
lists: ["snowball","tennessee","glasgow","unbc"],
custom: ["patent","claimed","claim","claims","fig"]
},
prepareDefault: true, // call preparePre, then this default function, then preparePost
removeTabsUnlessFirst: true,
cleanse72:true, // put in format of 72 characters per line, with line break, and double breaks between paragraphs
tabSpace:4,
removeNonAlphaNumeric: true,
stemmer: true, // in the default function, create stem objects as well
},
draw: {
width: 400, // this will override inline style
height: 600, // this is the DOM size
dpi: 300, // the canvas will scale for hi-res output ... e.g. 96 dpi (screen) -> 300 dpi (print)
which: "nonstop", // "original" or "non" (no stop words) or "nonstem" (no stop words, stemmed)
display: "original", // display the original word (lower cased)
scale: "n", // "n" is freq, "log(n)", "sqrt(n)"
weight: "freq", // obj element that is used to determine size
minFreq: 3, // n >= 3 to be included
maxWords: 250, // sort on frequency, stop when this many words are displayed ... Inf for Infinite, or 9999999,
rotateRatio: 0.7, // percent of elements that will be rotated
rotatePositions: 6, // number of rotated elements "6" means 7 with unrotated rectangle ... should be even here ... or not?
rotateMin: -30, // degrees to rotate back
rotateMax: 30, // degrees to rotate forward
fitSpiral: "Archimedean", // spiral approach to fit the current rectangle
fitFirst: "center center", // maybe other approaches?
fitNext: "random", // pic a random place on a screen, maybe a random grid if "workers"
fontFamily: 'Times, serif',
fontSizeMin: "12px", // or "8 pt" ... seems like pt is better than px ... or not
fontSizeMax: "67px", // or "18pt"
colorMin: '#ff0000',
colorMax: '#000000',
fontColorSteps: 11, // how many color/font combos (linked) ... numeric font-sizes (8,18px = 11 steps)
method: "canvas", // DOM as backup
title: "{word} appeared <BR /> {freq} times" // if DOM, append to title as "tooltip" with details for each span, {elements} must be object identifiers within a single element
}
}; -
Chris commented
+1