Skip to content

Instantly share code, notes, and snippets.

@Kcnarf
Last active September 13, 2019 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Kcnarf/ccf9bef19eb85ed6a3a7f99824c2ccb4 to your computer and use it in GitHub Desktop.
Save Kcnarf/ccf9bef19eb85ed6a3a7f99824c2ccb4 to your computer and use it in GitHub Desktop.
Word cloud comparison
license: mit

This block experiments a way to compare two word clouds dealing of the same subject area.

In this experiment, comparison emerge from animation. The chalenge is to preserve the location of each word, in order to make the animation not disruptive. To do so, the overall placement is done thanks to the d3.layout.cloud plugin (by Jason Davies), where each word's weight is the maximum possible weight. Then, word cloud specificities (here, depending on the selected city) come by applying the adequate font size and opacity (if a word is not defined for a city, it disappears).

This technique works fine, but:

  • it can lead to some overlapping (cf. around Good word),
  • it can produce some sparsed word cloud when many words disappear;

Cloud storm is another technique to compare word clouds.

This experimentation is highly inspired from Nitaku's blocks:

** original README **

This word cloud shows polarized words from reviews of accommodations. Bigger words were identified more often by sentiment analyzers. Color represents polarity (green is positive, red is negative). Use the mouse to pan and zoom.

Data is obtained from the Tour-Pedia APIs, that in turn get their input from the sentiment analysis pipeline of the OpeNER project.

The implementation makes use of d3.layout.cloud by Jason Davies.

html, body {
margin: 0;
padding: 0;
background: white;
}
select {
position: absolute;
top: 10px;
left: 10px;
}
text {
pointer-events:none;
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Experimenting word clouds comparison with D3.js" />
<meta charset="utf-8">
<title>Word cloud comparison</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src='layout.cloud.js'></script>
<script src="https://d3js.org/queue.v1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.4/seedrandom.min.js"></script>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<script src='index.js'></script>
<select id="select_city" onchange="update()">
<option value="amsterdam" selected="selected">Amsterdam</option>
<option value="london">London</option>
</select>
</body>
</html>
// DATA
var words_amsterdam = {"good":{"polarity":195,"count":195},"dream":{"polarity":1,"count":1},"clean":{"polarity":78,"count":78},"nice":{"polarity":114,"count":114},"friendly":{"polarity":59,"count":59},"free":{"polarity":156,"count":156},"cheap":{"polarity":-10,"count":10},"far":{"polarity":-18,"count":18},"ok":{"polarity":18,"count":18},"small":{"polarity":-54,"count":54},"incredibly":{"polarity":1,"count":1},"ugly":{"polarity":-1,"count":1},"awful":{"polarity":-3,"count":3},"slow":{"polarity":-11,"count":11},"expensive":{"polarity":-26,"count":26},"amazing":{"polarity":35,"count":35},"delicious":{"polarity":14,"count":14},"bunk":{"polarity":-1,"count":1},"wait":{"polarity":-3,"count":3},"help":{"polarity":4,"count":4},"bad":{"polarity":-30,"count":30},"worry":{"polarity":-1,"count":1},"well":{"polarity":27,"count":27},"tidy":{"polarity":1,"count":1},"fast":{"polarity":6,"count":6},"break":{"polarity":-2,"count":2},"impossible":{"polarity":-1,"count":1},"great":{"polarity":144,"count":144},"decorate":{"polarity":3,"count":3},"horror":{"polarity":-1,"count":1},"excellent":{"polarity":27,"count":27},"secret":{"polarity":-3,"count":3},"hop":{"polarity":2,"count":2},"buy":{"polarity":1,"count":1},"10min":{"polarity":2,"count":2},"modern":{"polarity":19,"count":19},"like":{"polarity":8,"count":8},"beautiful":{"polarity":19,"count":19},"design":{"polarity":20,"count":20},"change":{"polarity":2,"count":2},"hard":{"polarity":-3,"count":3},"impressed":{"polarity":2,"count":2},"perfect":{"polarity":11,"count":11},"fresh":{"polarity":3,"count":3},"comfort":{"polarity":5,"count":5},"stylish":{"polarity":1,"count":1},"comfortable":{"polarity":24,"count":24},"nearby":{"polarity":9,"count":9},"fun":{"polarity":-4,"count":4},"large":{"polarity":5,"count":5},"need":{"polarity":-12,"count":12},"calm":{"polarity":3,"count":3},"pretty":{"polarity":8,"count":8},"recommend":{"polarity":15,"count":15},"sorry":{"polarity":-1,"count":1},"chaos":{"polarity":-2,"count":2},"easy":{"polarity":8,"count":8},"close":{"polarity":13,"count":19},"noise":{"polarity":-6,"count":6},"famous":{"polarity":6,"count":6},"iron":{"polarity":-3,"count":3},"neat":{"polarity":3,"count":3},"comfy":{"polarity":17,"count":17},"love":{"polarity":21,"count":21},"reward":{"polarity":2,"count":2},"reliable":{"polarity":2,"count":2},"thank":{"polarity":2,"count":2},"enjoy":{"polarity":11,"count":11},"please":{"polarity":4,"count":4},"travel":{"polarity":2,"count":2},"soft":{"polarity":-2,"count":2},"fantastic":{"polarity":10,"count":10},"fitness":{"polarity":1,"count":1},"safe":{"polarity":2,"count":2},"central":{"polarity":15,"count":15},"worth":{"polarity":14,"count":14},"trust":{"polarity":1,"count":1},"okay":{"polarity":4,"count":4},"high":{"polarity":-5,"count":5},"stink":{"polarity":-2,"count":2},"lie":{"polarity":-1,"count":1},"lazy":{"polarity":-2,"count":2},"grill":{"polarity":-2,"count":2},"perfection":{"polarity":1,"count":1},"disappointing":{"polarity":-2,"count":2},"warm":{"polarity":3,"count":3},"reasonable":{"polarity":2,"count":2},"avoid":{"polarity":-7,"count":7},"fight":{"polarity":-1,"count":1},"unstable":{"polarity":-1,"count":1},"awesome":{"polarity":7,"count":7},"wholesome":{"polarity":1,"count":1},"try":{"polarity":-1,"count":1},"steal":{"polarity":-1,"count":1},"pillar":{"polarity":1,"count":1},"weird":{"polarity":-1,"count":1},"creative":{"polarity":2,"count":2},"delight":{"polarity":1,"count":1},"smell":{"polarity":-3,"count":3},"seriously":{"polarity":-3,"count":3},"special":{"polarity":6,"count":6},"miss":{"polarity":-10,"count":10},"dirty":{"polarity":-6,"count":6},"poor":{"polarity":-8,"count":8},"helpful":{"polarity":18,"count":18},"quality":{"polarity":5,"count":5},"problem":{"polarity":-4,"count":4},"pricey":{"polarity":-3,"count":3},"funny":{"polarity":2,"count":2},"cozy":{"polarity":6,"count":6},"cosy":{"polarity":3,"count":3},"impress":{"polarity":2,"count":2},"decent":{"polarity":4,"count":4},"cleanliness":{"polarity":3,"count":3},"quiet":{"polarity":15,"count":15},"hero":{"polarity":1,"count":1},"wonderful":{"polarity":6,"count":6},"cheerful":{"polarity":2,"count":2},"shiny":{"polarity":1,"count":1},"admire":{"polarity":1,"count":1},"favorite":{"polarity":1,"count":1},"fine":{"polarity":2,"count":6},"one":{"polarity":1,"count":1},"poorly":{"polarity":-1,"count":1},"helpfull":{"polarity":2,"count":2},"line":{"polarity":-4,"count":4},"pleasant":{"polarity":2,"count":2},"responsive":{"polarity":1,"count":1},"sharp":{"polarity":-1,"count":1},"low":{"polarity":2,"count":2},"classic":{"polarity":2,"count":2},"run":{"polarity":-1,"count":1},"convenient":{"polarity":2,"count":2},"ridiculous":{"polarity":-2,"count":2},"bloody":{"polarity":-1,"count":1},"grab":{"polarity":-1,"count":1},"charge":{"polarity":-5,"count":5},"robbery":{"polarity":-1,"count":1},"dedicated":{"polarity":2,"count":2},"sunny":{"polarity":2,"count":2},"unique":{"polarity":3,"count":3},"unlimited":{"polarity":3,"count":3},"acceptable":{"polarity":3,"count":3},"kind":{"polarity":5,"count":5},"divine":{"polarity":1,"count":1},"impeccable":{"polarity":2,"count":2},"notch":{"polarity":1,"count":1},"complaint":{"polarity":-3,"count":3},"witty":{"polarity":1,"count":1},"functional":{"polarity":2,"count":2},"trendy":{"polarity":3,"count":3},"weary":{"polarity":-1,"count":1},"welcome":{"polarity":4,"count":4},"lovely":{"polarity":13,"count":13},"gorgeous":{"polarity":2,"count":2},"madness":{"polarity":-1,"count":1},"well-designed":{"polarity":1,"count":1},"healthy":{"polarity":2,"count":2},"light":{"polarity":2,"count":2},"affordable":{"polarity":8,"count":8},"super":{"polarity":4,"count":4},"inspiring":{"polarity":1,"count":1},"inspire":{"polarity":2,"count":2},"luxury":{"polarity":6,"count":6},"incredible":{"polarity":4,"count":4},"disposal":{"polarity":-1,"count":1},"clever":{"polarity":1,"count":1},"downside":{"polarity":-2,"count":2},"interesting":{"polarity":2,"count":2},"pleasure":{"polarity":3,"count":3},"noisy":{"polarity":-7,"count":7},"fancy":{"polarity":1,"count":1},"relax":{"polarity":2,"count":2},"superb":{"polarity":1,"count":1},"serious":{"polarity":-3,"count":3},"jam":{"polarity":-4,"count":4},"ideal":{"polarity":1,"count":1},"polite":{"polarity":2,"count":2},"care":{"polarity":1,"count":1},"exclusive":{"polarity":1,"count":1},"spectacular":{"polarity":2,"count":2},"limited":{"polarity":-2,"count":2},"popular":{"polarity":3,"count":3},"costly":{"polarity":-1,"count":1},"greatest":{"polarity":2,"count":2},"compliment":{"polarity":2,"count":2},"fix":{"polarity":-1,"count":1},"hot":{"polarity":5,"count":5},"glad":{"polarity":1,"count":1},"call":{"polarity":5,"count":5},"freak":{"polarity":-1,"count":1},"cold":{"polarity":-1,"count":1},"meet":{"polarity":2,"count":2},"enjoyable":{"polarity":1,"count":1},"star":{"polarity":1,"count":1},"perfectly":{"polarity":2,"count":2},"celebrity":{"polarity":1,"count":1},"horribly":{"polarity":-1,"count":1},"happy":{"polarity":2,"count":2},"mistake":{"polarity":-1,"count":1},"stylishly":{"polarity":1,"count":1},"sort":{"polarity":-3,"count":3},"plenty":{"polarity":4,"count":4},"tiny":{"polarity":-10,"count":10},"fabulous":{"polarity":2,"count":2},"courtesy":{"polarity":1,"count":1},"posh":{"polarity":1,"count":1},"trouble":{"polarity":-1,"count":1},"premium":{"polarity":1,"count":1},"frustrating":{"polarity":-1,"count":1},"recommendation":{"polarity":1,"count":1},"smartly":{"polarity":1,"count":1},"conveniently":{"polarity":2,"count":2},"hell":{"polarity":-1,"count":1},"chic":{"polarity":1,"count":1},"pure":{"polarity":2,"count":2},"lumpy":{"polarity":-1,"count":1},"charming":{"polarity":1,"count":1},"careful":{"polarity":1,"count":1},"easily":{"polarity":6,"count":6},"shot":{"polarity":-1,"count":1},"lay":{"polarity":-1,"count":1},"dodgy":{"polarity":-1,"count":1},"steep":{"polarity":-1,"count":1},"crazy":{"polarity":-1,"count":1},"chill":{"polarity":-1,"count":1},"bit":{"polarity":-1,"count":1},"near":{"polarity":1,"count":1},"terrible":{"polarity":-8,"count":8},"down":{"polarity":-1,"count":1},"peaceful":{"polarity":1,"count":1},"enthusiast":{"polarity":1,"count":1},"spacious":{"polarity":2,"count":2},"professional":{"polarity":2,"count":2},"tender":{"polarity":1,"count":1},"unbearable":{"polarity":-1,"count":1},"disappointment":{"polarity":-1,"count":1},"horrible":{"polarity":-4,"count":4},"unfriendly":{"polarity":-1,"count":1},"sweet":{"polarity":2,"count":2},"amenity":{"polarity":1,"count":1},"trumpet":{"polarity":1,"count":1},"worthy":{"polarity":1,"count":1},"rude":{"polarity":-3,"count":3},"sarcastic":{"polarity":-1,"count":1},"treat":{"polarity":2,"count":2},"nicely":{"polarity":2,"count":2},"double":{"polarity":-1,"count":1},"precaution":{"polarity":1,"count":1},"assistance":{"polarity":1,"count":1},"unhappy":{"polarity":-1,"count":1},"lack":{"polarity":-1,"count":1},"return":{"polarity":1,"count":1},"personal":{"polarity":1,"count":1},"bonus":{"polarity":2,"count":2},"worthwhile":{"polarity":1,"count":1},"kill":{"polarity":-1,"count":1},"tax":{"polarity":-1,"count":1},"error":{"polarity":-1,"count":1},"nervous":{"polarity":-1,"count":1},"odd":{"polarity":-2,"count":2},"wow":{"polarity":2,"count":2},"plain":{"polarity":-2,"count":2},"sympathetic":{"polarity":-1,"count":1},"willing":{"polarity":1,"count":1},"difficult":{"polarity":-1,"count":1},"drag":{"polarity":-1,"count":1},"sexy":{"polarity":1,"count":1},"frank":{"polarity":1,"count":1},"default":{"polarity":-1,"count":1},"beautifully":{"polarity":1,"count":1},"fascinating":{"polarity":1,"count":1},"tradition":{"polarity":1,"count":1},"modernity":{"polarity":1,"count":1},"restore":{"polarity":1,"count":1},"ridiculously":{"polarity":-1,"count":1},"unable":{"polarity":-1,"count":1},"warn":{"polarity":-1,"count":1},"ignore":{"polarity":-1,"count":1},"permit":{"polarity":1,"count":1},"elegant":{"polarity":1,"count":1},"imaginative":{"polarity":1,"count":1},"romantic":{"polarity":1,"count":1},"entertain":{"polarity":1,"count":1},"haven":{"polarity":1,"count":1},"spotty":{"polarity":-2,"count":2},"flexible":{"polarity":1,"count":1},"boring":{"polarity":-1,"count":1},"incompetent":{"polarity":-1,"count":1},"bother":{"polarity":-1,"count":1},"proper":{"polarity":1,"count":1},"ready":{"polarity":1,"count":1},"shabby":{"polarity":-1,"count":1},"amaze":{"polarity":1,"count":1},"rival":{"polarity":-1,"count":1},"patience":{"polarity":1,"count":1},"annoy":{"polarity":-1,"count":1},"awfully":{"polarity":-1,"count":1},"empty":{"polarity":-1,"count":1},"greet":{"polarity":1,"count":1},"bright":{"polarity":1,"count":1},"safely":{"polarity":1,"count":1},"heaven":{"polarity":1,"count":1},"unexpected":{"polarity":-1,"count":1},"basic":{"polarity":1,"count":1},"cut":{"polarity":-2,"count":2},"smaller":{"polarity":-1,"count":1},"loud":{"polarity":-2,"count":2},"oddly":{"polarity":-1,"count":1},"outrageous":{"polarity":-1,"count":1},"live":{"polarity":1,"count":1},"disappointed":{"polarity":-1,"count":1},"delightful":{"polarity":1,"count":1}};
var words_london = {"steal":{"polarity":-2,"count":2},"nice":{"polarity":58,"count":58},"afford":{"polarity":1,"count":1},"great":{"polarity":114,"count":114},"fine":{"polarity":4,"count":6},"large":{"polarity":10,"count":10},"well":{"polarity":30,"count":30},"good":{"polarity":138,"count":138},"squash":{"polarity":-1,"count":1},"wonderful":{"polarity":5,"count":5},"amazing":{"polarity":23,"count":23},"enjoy":{"polarity":14,"count":14},"like":{"polarity":7,"count":7},"miss":{"polarity":-8,"count":8},"guarantee":{"polarity":2,"count":2},"beautiful":{"polarity":8,"count":8},"notch":{"polarity":1,"count":1},"free":{"polarity":88,"count":88},"iconic":{"polarity":4,"count":4},"break":{"polarity":-3,"count":3},"helpful":{"polarity":17,"count":17},"decent":{"polarity":10,"count":10},"stylish":{"polarity":7,"count":7},"central":{"polarity":7,"count":7},"exceptional":{"polarity":1,"count":1},"beware":{"polarity":-4,"count":4},"sharp":{"polarity":-1,"count":1},"light":{"polarity":2,"count":2},"treat":{"polarity":2,"count":2},"spectacular":{"polarity":1,"count":1},"awesome":{"polarity":6,"count":6},"chill":{"polarity":-3,"count":3},"expensive":{"polarity":-12,"count":12},"noisy":{"polarity":-9,"count":9},"recommend":{"polarity":11,"count":11},"easy":{"polarity":4,"count":4},"need":{"polarity":-18,"count":18},"load":{"polarity":-5,"count":5},"hot":{"polarity":12,"count":12},"problem":{"polarity":-4,"count":4},"easily":{"polarity":2,"count":2},"wait":{"polarity":-5,"count":5},"pathetic":{"polarity":-1,"count":1},"close":{"polarity":15,"count":23},"quiet":{"polarity":10,"count":10},"personal":{"polarity":2,"count":2},"special":{"polarity":10,"count":10},"trouble":{"polarity":-1,"count":1},"sumptuous":{"polarity":1,"count":1},"professional":{"polarity":1,"count":1},"deserve":{"polarity":2,"count":2},"fabulous":{"polarity":3,"count":3},"shoot":{"polarity":-1,"count":1},"funny":{"polarity":2,"count":2},"cut":{"polarity":-1,"count":1},"outrageously":{"polarity":-1,"count":1},"excellent":{"polarity":11,"count":11},"lovely":{"polarity":29,"count":29},"inspire":{"polarity":2,"count":2},"happy":{"polarity":9,"count":9},"support":{"polarity":3,"count":3},"accomplish":{"polarity":1,"count":1},"raise":{"polarity":-1,"count":1},"exciting":{"polarity":1,"count":1},"delight":{"polarity":1,"count":1},"promise":{"polarity":1,"count":1},"practical":{"polarity":1,"count":1},"rank":{"polarity":-1,"count":1},"enjoying":{"polarity":1,"count":1},"unfortunate":{"polarity":-1,"count":1},"sweet":{"polarity":1,"count":1},"beauty":{"polarity":2,"count":2},"shot":{"polarity":-3,"count":3},"thank":{"polarity":2,"count":2},"help":{"polarity":4,"count":4},"love":{"polarity":10,"count":10},"unlimited":{"polarity":1,"count":1},"adult":{"polarity":1,"count":1},"pleasurable":{"polarity":1,"count":1},"friendliness":{"polarity":1,"count":1},"wonder":{"polarity":1,"count":1},"unbelievable":{"polarity":-1,"count":1},"prize":{"polarity":1,"count":1},"one":{"polarity":6,"count":6},"smile":{"polarity":2,"count":2},"clean":{"polarity":39,"count":39},"fantastic":{"polarity":4,"count":4},"pricey":{"polarity":-3,"count":3},"perfect":{"polarity":11,"count":11},"cosy":{"polarity":3,"count":3},"warm":{"polarity":4,"count":4},"friendly":{"polarity":46,"count":46},"charge":{"polarity":-5,"count":5},"handy":{"polarity":2,"count":2},"commission":{"polarity":1,"count":1},"polite":{"polarity":3,"count":3},"luxury":{"polarity":2,"count":2},"high":{"polarity":-9,"count":9},"disappointed":{"polarity":-1,"count":1},"trendy":{"polarity":1,"count":1},"efficient":{"polarity":1,"count":1},"convenient":{"polarity":3,"count":3},"nearby":{"polarity":6,"count":6},"modern":{"polarity":6,"count":6},"design":{"polarity":3,"count":3},"return":{"polarity":3,"count":3},"amenity":{"polarity":4,"count":4},"affordable":{"polarity":2,"count":2},"restore":{"polarity":1,"count":1},"gem":{"polarity":1,"count":1},"cheap":{"polarity":-7,"count":9},"bother":{"polarity":-4,"count":4},"reward":{"polarity":1,"count":1},"pound":{"polarity":-5,"count":5},"slow":{"polarity":-9,"count":9},"ok":{"polarity":13,"count":13},"damn":{"polarity":-2,"count":2},"horrible":{"polarity":-8,"count":8},"snore":{"polarity":-1,"count":1},"bunk":{"polarity":-1,"count":1},"securely":{"polarity":1,"count":1},"bit":{"polarity":-2,"count":2},"cramped":{"polarity":-2,"count":2},"please":{"polarity":3,"count":3},"careful":{"polarity":2,"count":2},"lousy":{"polarity":-1,"count":1},"bad":{"polarity":-30,"count":30},"dark":{"polarity":-3,"count":3},"straight":{"polarity":1,"count":1},"rude":{"polarity":-5,"count":5},"complain":{"polarity":-3,"count":3},"luck":{"polarity":1,"count":1},"bury":{"polarity":-1,"count":1},"noise":{"polarity":-2,"count":2},"double":{"polarity":-1,"count":1},"fair":{"polarity":2,"count":2},"incredibly":{"polarity":2,"count":2},"empty":{"polarity":-4,"count":4},"poor":{"polarity":-14,"count":14},"stun":{"polarity":-1,"count":1},"incredible":{"polarity":4,"count":4},"pamper":{"polarity":1,"count":1},"glorious":{"polarity":1,"count":1},"decadent":{"polarity":-1,"count":1},"unimpressed":{"polarity":-2,"count":2},"far":{"polarity":-6,"count":6},"incompetent":{"polarity":-1,"count":1},"quality":{"polarity":1,"count":1},"sort":{"polarity":-1,"count":1},"painfully":{"polarity":-1,"count":1},"interested":{"polarity":1,"count":1},"limited":{"polarity":-2,"count":2},"fast":{"polarity":6,"count":6},"suspect":{"polarity":-1,"count":1},"line":{"polarity":-3,"count":3},"unjustified":{"polarity":-1,"count":1},"reasonable":{"polarity":9,"count":9},"default":{"polarity":-1,"count":1},"survive":{"polarity":1,"count":1},"drop":{"polarity":-2,"count":2},"spacious":{"polarity":2,"count":2},"safety":{"polarity":1,"count":1},"delicious":{"polarity":3,"count":3},"pleasant":{"polarity":5,"count":5},"superb":{"polarity":4,"count":4},"pretty":{"polarity":10,"count":10},"small":{"polarity":-42,"count":42},"run":{"polarity":-3,"count":3},"join":{"polarity":1,"count":1},"rip":{"polarity":-2,"count":2},"generous":{"polarity":1,"count":1},"hard":{"polarity":-5,"count":5},"get":{"polarity":-1,"count":1},"worst":{"polarity":-2,"count":2},"disaster":{"polarity":-1,"count":1},"mislead":{"polarity":-1,"count":1},"super":{"polarity":3,"count":3},"agree":{"polarity":1,"count":1},"uncomfortable":{"polarity":-1,"count":1},"cramp":{"polarity":-1,"count":1},"relax":{"polarity":2,"count":2},"impress":{"polarity":1,"count":1},"beat":{"polarity":-2,"count":2},"bargain":{"polarity":1,"count":1},"definite":{"polarity":1,"count":1},"waste":{"polarity":-1,"count":1},"kick":{"polarity":-1,"count":1},"blame":{"polarity":-1,"count":1},"incorrectly":{"polarity":-1,"count":1},"terrible":{"polarity":-7,"count":7},"hardly":{"polarity":-1,"count":1},"jam":{"polarity":-1,"count":1},"patience":{"polarity":1,"count":1},"patient":{"polarity":1,"count":1},"useful":{"polarity":1,"count":1},"worth":{"polarity":11,"count":11},"live":{"polarity":1,"count":1},"attention":{"polarity":2,"count":2},"fun":{"polarity":-2,"count":2},"famous":{"polarity":2,"count":2},"classic":{"polarity":2,"count":2},"easiest":{"polarity":1,"count":1},"quickly":{"polarity":1,"count":1},"angry":{"polarity":-1,"count":1},"awe":{"polarity":1,"count":1},"hate":{"polarity":-1,"count":1},"proper":{"polarity":3,"count":3},"comfy":{"polarity":5,"count":5},"change":{"polarity":2,"count":2},"ideal":{"polarity":1,"count":1},"fitness":{"polarity":2,"count":2},"mystery":{"polarity":-1,"count":1},"plenty":{"polarity":3,"count":3},"welcome":{"polarity":4,"count":4},"outstanding":{"polarity":1,"count":1},"comfortable":{"polarity":12,"count":12},"festive":{"polarity":1,"count":1},"impeccably":{"polarity":1,"count":1},"train":{"polarity":1,"count":1},"hug":{"polarity":1,"count":1},"unbelievably":{"polarity":-1,"count":1},"crappy":{"polarity":-1,"count":1},"smaller":{"polarity":-3,"count":3},"comfort":{"polarity":2,"count":2},"bore":{"polarity":-2,"count":2},"secret":{"polarity":-2,"count":2},"conveniently":{"polarity":2,"count":2},"dedicated":{"polarity":1,"count":1},"exclusive":{"polarity":1,"count":1},"trial":{"polarity":-1,"count":1},"sparkle":{"polarity":1,"count":1},"weak":{"polarity":-2,"count":2},"thoughtful":{"polarity":1,"count":1},"significant":{"polarity":1,"count":1},"decorate":{"polarity":1,"count":1},"quick":{"polarity":1,"count":1},"shabby":{"polarity":-2,"count":2},"desperate":{"polarity":-1,"count":1},"ideally":{"polarity":2,"count":2},"unfriendly":{"polarity":-2,"count":2},"horror":{"polarity":-1,"count":1},"warn":{"polarity":-1,"count":1},"downgrade":{"polarity":-2,"count":2},"complaint":{"polarity":-2,"count":2},"inept":{"polarity":-1,"count":1},"displeasure":{"polarity":-1,"count":1},"fire":{"polarity":-1,"count":1},"magnificent":{"polarity":1,"count":1},"freezing":{"polarity":-1,"count":1},"tiny":{"polarity":-11,"count":11},"refuse":{"polarity":-1,"count":1},"ugly":{"polarity":-2,"count":2},"insanely":{"polarity":-1,"count":1},"worry":{"polarity":-1,"count":1},"calm":{"polarity":1,"count":1},"awful":{"polarity":-4,"count":4},"positively":{"polarity":1,"count":1},"lie":{"polarity":-1,"count":1},"disturb":{"polarity":-1,"count":1},"safe":{"polarity":1,"count":1},"suitable":{"polarity":1,"count":1},"unusual":{"polarity":-1,"count":1},"avoid":{"polarity":-6,"count":6},"pleasure":{"polarity":1,"count":1},"iron":{"polarity":-1,"count":1},"foreign":{"polarity":-2,"count":2},"perfectly":{"polarity":1,"count":1},"encourage":{"polarity":1,"count":1},"ample":{"polarity":1,"count":1},"travel":{"polarity":1,"count":1},"essential":{"polarity":1,"count":1},"wrong":{"polarity":-2,"count":2},"unhelpful":{"polarity":-1,"count":1},"cross":{"polarity":-1,"count":1},"competitive":{"polarity":1,"count":1},"loud":{"polarity":-2,"count":2},"legendary":{"polarity":1,"count":1},"adequate":{"polarity":1,"count":1},"rudest":{"polarity":-1,"count":1},"nasty":{"polarity":-2,"count":2},"fancy":{"polarity":1,"count":1},"shocking":{"polarity":-2,"count":2},"disappointing":{"polarity":-1,"count":1},"ruin":{"polarity":-1,"count":1},"refreshing":{"polarity":1,"count":1},"relevant":{"polarity":1,"count":1},"acceptable":{"polarity":1,"count":1},"poorly":{"polarity":-1,"count":1},"regret":{"polarity":-1,"count":1},"greatest":{"polarity":1,"count":1},"consistent":{"polarity":1,"count":1},"impressed":{"polarity":1,"count":1},"okay":{"polarity":2,"count":2},"elegant":{"polarity":1,"count":1},"creative":{"polarity":1,"count":1},"positive":{"polarity":2,"count":2},"relaxation":{"polarity":2,"count":2},"greet":{"polarity":1,"count":1},"inconvenience":{"polarity":-1,"count":1},"champion":{"polarity":1,"count":1},"disappoint":{"polarity":-1,"count":1},"tranquil":{"polarity":1,"count":1},"justify":{"polarity":1,"count":1},"soft":{"polarity":-1,"count":1},"sufficient":{"polarity":1,"count":1},"shock":{"polarity":-1,"count":1},"worthy":{"polarity":1,"count":1},"celebrity":{"polarity":1,"count":1},"success":{"polarity":1,"count":1},"upside":{"polarity":1,"count":1},"odd":{"polarity":-1,"count":1},"tired":{"polarity":-3,"count":3},"unacceptable":{"polarity":-1,"count":1},"upset":{"polarity":-1,"count":1},"peaceful":{"polarity":2,"count":2},"oasis":{"polarity":1,"count":1},"eclectic":{"polarity":1,"count":1},"mix":{"polarity":-1,"count":1},"helpfull":{"polarity":2,"count":2},"star":{"polarity":1,"count":1},"restful":{"polarity":1,"count":1},"appealing":{"polarity":1,"count":1},"tastefully":{"polarity":1,"count":1},"rubbish":{"polarity":-1,"count":1},"enemy":{"polarity":-1,"count":1},"difficult":{"polarity":-2,"count":2},"grim":{"polarity":-1,"count":1},"weirdly":{"polarity":-1,"count":1},"unique":{"polarity":1,"count":1},"tidy":{"polarity":1,"count":1},"unkind":{"polarity":-1,"count":1},"dirty":{"polarity":-1,"count":1},"cold":{"polarity":-1,"count":1},"complex":{"polarity":-1,"count":1},"too":{"polarity":-1,"count":1},"sorry":{"polarity":-1,"count":1},"valuable":{"polarity":1,"count":1},"hand":{"polarity":-1,"count":1},"narrow":{"polarity":-1,"count":1},"accessible":{"polarity":1,"count":1},"near":{"polarity":1,"count":1},"impossible":{"polarity":-2,"count":2},"outdated":{"polarity":-1,"count":1},"blast":{"polarity":-1,"count":1},"unusable":{"polarity":-1,"count":1},"disgusting":{"polarity":-1,"count":1},"rat":{"polarity":-1,"count":1},"satisfy":{"polarity":1,"count":1},"fix":{"polarity":-1,"count":1},"utterly":{"polarity":-1,"count":1},"hell":{"polarity":-1,"count":1},"ignore":{"polarity":-1,"count":1},"gorgeous":{"polarity":1,"count":1},"disturbance":{"polarity":-1,"count":1},"utter":{"polarity":-1,"count":1}};
var shuffling = true; // shuffling make less-sparsed word clouds
var spiral = "archimedean"; // 'archimedean or 'rectangular'
var outter = true; // (try to) make disappearing words outter
var city = "amsterdam";
var zoom_group; // reusable d3 selection
var words = {};
Object.keys(words_amsterdam).forEach(function(word_lemma){
words[word_lemma] = {
"amsterdam": words_amsterdam[word_lemma],
"london": {"polarity":words_amsterdam[word_lemma].polarity,"count":0}
}
});
Object.keys(words_london).forEach(function(word_lemma){
if (words[word_lemma]) {
words[word_lemma].london = words_london[word_lemma];
} else {
w = words[word_lemma] = {
"amsterdam": {"polarity":words_london[word_lemma].polarity,"count":0},
"london": words_london[word_lemma]
}
}
});
Math.seedrandom('abcde'); // define a fixed random seed, to avoid to have a different layout on each page reload. change the string to randomize
var words_frequency = [];
var max = -Infinity;
Object.keys(words).forEach(function(word_lemma){
o = words[word_lemma];
o.lemma = word_lemma;
o.maxCount = Math.max(o.amsterdam.count, o.london.count);
words_frequency.push(o);
if (max < o.maxCount) {
max = o.maxCount;
}
});
console.log("max: "+max);
var font_size = d3.scale.linear()
.domain([1, max])
.range([10,100]);
/*
var color = d3.scale.linear()
.domain([-max, 0, max])
.range([d3.hcl(36, 65, 50), d3.hcl(95, 65, 80), d3.hcl(150, 65, 50)])
.interpolate(d3.interpolateHcl);*/
var color = d3.scale.quantize()
.domain([-max, max])
.range([d3.hcl(36, 65, 50), d3.hcl(150, 65, 50)]);
if (shuffling) {
shuffle(words_frequency);
}
words_frequency.sort(function(a,b){
if (outter) {
return (b.maxCount - a.maxCount)
+ (((b.amsterdam.count === 0) || (b.london.count === 0))? 1 : 0);
} else {
return (b.maxCount - a.maxCount);
}
});
d3.layout.cloud().size([960, 500])
.words(words_frequency)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.spiral(spiral)
.text(function(d){ return d.lemma; })
.fontSize(function(d){ return font_size(d.maxCount); })
.on("end", draw)
.start();
function draw(words) {
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
// append a group for zoomable content
zoom_group = svg.append('g');
// define a zoom behavior
var zoom = d3.behavior.zoom()
.scaleExtent([1,4]) // min-max zoom
.on('zoom', function() {
// whenever the user zooms,
// modify translation and scale of the zoom group accordingly
zoom_group.attr('transform', 'translate('+zoom.translate()+')scale('+zoom.scale()+')');
});
// bind the zoom behavior to the main SVG
svg.call(zoom);
zoom_group.append("g")
.attr("transform", "translate(480,250)")
.selectAll("text")
.data(words)
.enter()
.append("text")
.style("font-size", function(d){ return font_size(d[city].count) + "px"; })
.style("font-family", "Impact")
.style("fill", function(d) { return color(d[city].polarity); })
.style("fill-opacity", function(d) { return (d[city].count>0)? 1 : 0; })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
var far = 1500*(Math.random() > 0.5 ? +1 : -1);
if(d.rotate === 0)
return "translate("+far+",0)rotate(" + d.rotate + ")";
else
return "translate(0,"+far+")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.lemma; })
.transition()
.duration(2000)
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
});
}
function update() {
if (city === "london") {
city = "amsterdam";
} else {
city = "london";
}
zoom_group.selectAll("text")
.data(words_frequency)
.transition()
.duration(1000)
.style("font-size", function(d){ return font_size(d[city].count) + "px"; })
.style("fill", function(d) { return color(d[city].polarity); })
.style("fill-opacity", function(d) { return (d[city].count>0)? 1 : 0; });
}
function shuffle(array) {
let counter = array.length;
// While there are elements in the array
while (counter > 0) {
// Pick a random index
let index = Math.floor(Math.random() * counter);
// Decrease counter by 1
counter--;
// And swap the last element with it
let temp = array[counter];
array[counter] = array[index];
array[index] = temp;
}
return array;
}
// Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/
// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf
(function() {
function cloud() {
var size = [256, 256],
text = cloudText,
font = cloudFont,
fontSize = cloudFontSize,
fontStyle = cloudFontNormal,
fontWeight = cloudFontNormal,
rotate = cloudRotate,
padding = cloudPadding,
spiral = archimedeanSpiral,
words = [],
timeInterval = Infinity,
event = d3.dispatch("word", "end"),
timer = null,
cloud = {};
cloud.start = function() {
var board = zeroArray((size[0] >> 5) * size[1]),
bounds = null,
n = words.length,
i = -1,
tags = [],
data = words.map(function(d, i) {
d.text = text.call(this, d, i);
d.font = font.call(this, d, i);
d.style = fontStyle.call(this, d, i);
d.weight = fontWeight.call(this, d, i);
d.rotate = rotate.call(this, d, i);
d.size = ~~fontSize.call(this, d, i);
d.padding = padding.call(this, d, i);
return d;
}).sort(function(a, b) { return b.size - a.size; });
if (timer) clearInterval(timer);
timer = setInterval(step, 0);
step();
return cloud;
function step() {
var start = +new Date,
d;
while (+new Date - start < timeInterval && ++i < n && timer) {
d = data[i];
d.x = (size[0] * (Math.random() + .5)) >> 1;
d.y = (size[1] * (Math.random() + .5)) >> 1;
cloudSprite(d, data, i);
if (d.hasText && place(board, d, bounds)) {
tags.push(d);
event.word(d);
if (bounds) cloudBounds(bounds, d);
else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}];
// Temporary hack
d.x -= size[0] >> 1;
d.y -= size[1] >> 1;
}
}
if (i >= n) {
cloud.stop();
event.end(tags, bounds);
}
}
}
cloud.stop = function() {
if (timer) {
clearInterval(timer);
timer = null;
}
return cloud;
};
cloud.timeInterval = function(x) {
if (!arguments.length) return timeInterval;
timeInterval = x == null ? Infinity : x;
return cloud;
};
function place(board, tag, bounds) {
var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}],
startX = tag.x,
startY = tag.y,
maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]),
s = spiral(size),
dt = Math.random() < .5 ? 1 : -1,
t = -dt,
dxdy,
dx,
dy;
while (dxdy = s(t += dt)) {
dx = ~~dxdy[0];
dy = ~~dxdy[1];
if (Math.min(dx, dy) > maxDelta) break;
tag.x = startX + dx;
tag.y = startY + dy;
if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 ||
tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue;
// TODO only check for collisions within current bounds.
if (!bounds || !cloudCollide(tag, board, size[0])) {
if (!bounds || collideRects(tag, bounds)) {
var sprite = tag.sprite,
w = tag.width >> 5,
sw = size[0] >> 5,
lx = tag.x - (w << 4),
sx = lx & 0x7f,
msx = 32 - sx,
h = tag.y1 - tag.y0,
x = (tag.y + tag.y0) * sw + (lx >> 5),
last;
for (var j = 0; j < h; j++) {
last = 0;
for (var i = 0; i <= w; i++) {
board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);
}
x += sw;
}
delete tag.sprite;
return true;
}
}
}
return false;
}
cloud.words = function(x) {
if (!arguments.length) return words;
words = x;
return cloud;
};
cloud.size = function(x) {
if (!arguments.length) return size;
size = [+x[0], +x[1]];
return cloud;
};
cloud.font = function(x) {
if (!arguments.length) return font;
font = d3.functor(x);
return cloud;
};
cloud.fontStyle = function(x) {
if (!arguments.length) return fontStyle;
fontStyle = d3.functor(x);
return cloud;
};
cloud.fontWeight = function(x) {
if (!arguments.length) return fontWeight;
fontWeight = d3.functor(x);
return cloud;
};
cloud.rotate = function(x) {
if (!arguments.length) return rotate;
rotate = d3.functor(x);
return cloud;
};
cloud.text = function(x) {
if (!arguments.length) return text;
text = d3.functor(x);
return cloud;
};
cloud.spiral = function(x) {
if (!arguments.length) return spiral;
spiral = spirals[x + ""] || x;
return cloud;
};
cloud.fontSize = function(x) {
if (!arguments.length) return fontSize;
fontSize = d3.functor(x);
return cloud;
};
cloud.padding = function(x) {
if (!arguments.length) return padding;
padding = d3.functor(x);
return cloud;
};
return d3.rebind(cloud, event, "on");
}
function cloudText(d) {
return d.text;
}
function cloudFont() {
return "serif";
}
function cloudFontNormal() {
return "normal";
}
function cloudFontSize(d) {
return Math.sqrt(d.value);
}
function cloudRotate() {
return (~~(Math.random() * 6) - 3) * 30;
}
function cloudPadding() {
return 1;
}
// Fetches a monochrome sprite bitmap for the specified text.
// Load in batches for speed.
function cloudSprite(d, data, di) {
if (d.sprite) return;
c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio);
var x = 0,
y = 0,
maxh = 0,
n = data.length;
--di;
while (++di < n) {
d = data[di];
c.save();
c.font = d.style + " " + d.weight + " " + ~~((d.size + 1) / ratio) + "px " + d.font;
var w = c.measureText(d.text + "m").width * ratio,
h = d.size << 1;
if (d.rotate) {
var sr = Math.sin(d.rotate * cloudRadians),
cr = Math.cos(d.rotate * cloudRadians),
wcr = w * cr,
wsr = w * sr,
hcr = h * cr,
hsr = h * sr;
w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5;
h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));
} else {
w = (w + 0x1f) >> 5 << 5;
}
if (h > maxh) maxh = h;
if (x + w >= (cw << 5)) {
x = 0;
y += maxh;
maxh = 0;
}
if (y + h >= ch) break;
c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio);
if (d.rotate) c.rotate(d.rotate * cloudRadians);
c.fillText(d.text, 0, 0);
if (d.padding) c.lineWidth = 2 * d.padding, c.strokeText(d.text, 0, 0);
c.restore();
d.width = w;
d.height = h;
d.xoff = x;
d.yoff = y;
d.x1 = w >> 1;
d.y1 = h >> 1;
d.x0 = -d.x1;
d.y0 = -d.y1;
d.hasText = true;
x += w;
}
var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data,
sprite = [];
while (--di >= 0) {
d = data[di];
if (!d.hasText) continue;
var w = d.width,
w32 = w >> 5,
h = d.y1 - d.y0;
// Zero the buffer
for (var i = 0; i < h * w32; i++) sprite[i] = 0;
x = d.xoff;
if (x == null) return;
y = d.yoff;
var seen = 0,
seenRow = -1;
for (var j = 0; j < h; j++) {
for (var i = 0; i < w; i++) {
var k = w32 * j + (i >> 5),
m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0;
sprite[k] |= m;
seen |= m;
}
if (seen) seenRow = j;
else {
d.y0++;
h--;
j--;
y++;
}
}
d.y1 = d.y0 + seenRow;
d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32);
}
}
// Use mask-based collision detection.
function cloudCollide(tag, board, sw) {
sw >>= 5;
var sprite = tag.sprite,
w = tag.width >> 5,
lx = tag.x - (w << 4),
sx = lx & 0x7f,
msx = 32 - sx,
h = tag.y1 - tag.y0,
x = (tag.y + tag.y0) * sw + (lx >> 5),
last;
for (var j = 0; j < h; j++) {
last = 0;
for (var i = 0; i <= w; i++) {
if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0))
& board[x + i]) return true;
}
x += sw;
}
return false;
}
function cloudBounds(bounds, d) {
var b0 = bounds[0],
b1 = bounds[1];
if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0;
if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0;
if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1;
if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1;
}
function collideRects(a, b) {
return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y;
}
function archimedeanSpiral(size) {
var e = size[0] / size[1];
return function(t) {
return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)];
};
}
function rectangularSpiral(size) {
var dy = 4,
dx = dy * size[0] / size[1],
x = 0,
y = 0;
return function(t) {
var sign = t < 0 ? -1 : 1;
// See triangular numbers: T_n = n * (n + 1) / 2.
switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) {
case 0: x += dx; break;
case 1: y += dy; break;
case 2: x -= dx; break;
default: y -= dy; break;
}
return [x, y];
};
}
// TODO reuse arrays?
function zeroArray(n) {
var a = [],
i = -1;
while (++i < n) a[i] = 0;
return a;
}
var cloudRadians = Math.PI / 180,
cw = 1 << 11 >> 5,
ch = 1 << 11,
canvas,
ratio = 1;
if (typeof document !== "undefined") {
canvas = document.createElement("canvas");
canvas.width = 1;
canvas.height = 1;
ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2);
canvas.width = (cw << 5) / ratio;
canvas.height = ch / ratio;
} else {
// Attempt to use node-canvas.
canvas = new Canvas(cw << 5, ch);
}
var c = canvas.getContext("2d"),
spirals = {
archimedean: archimedeanSpiral,
rectangular: rectangularSpiral
};
c.fillStyle = c.strokeStyle = "red";
c.textAlign = "center";
if (typeof module === "object" && module.exports) module.exports = cloud;
else (d3.layout || (d3.layout = {})).cloud = cloud;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment