Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

new(wordcloud): add @visx/wordcloud #1311

Merged
merged 23 commits into from Aug 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
197daf9
Create wordcloud package
craciuncezar Jul 23, 2021
5fabf5e
Add wordcloud tile and doc page in demo
craciuncezar Jul 23, 2021
bd3b0e6
Implement wordcloud visualization
craciuncezar Jul 25, 2021
4b683f4
Add documentation and export useWordcloud
craciuncezar Jul 25, 2021
e1fa46b
Make datum generic
craciuncezar Jul 25, 2021
ba3e2dc
Use descriptive generic name
craciuncezar Jul 25, 2021
6ccb774
Accept function accessor for all fields
craciuncezar Jul 25, 2021
aec4b49
Test wordcloud
craciuncezar Jul 26, 2021
616afda
Datum generic type extends base datum type
craciuncezar Jul 26, 2021
46e1998
Add example controls
craciuncezar Jul 26, 2021
a0d36e6
Bump d3 cloud types
craciuncezar Aug 13, 2021
05812f1
Merge branch 'master' into Wordcloud-visualizaion
craciuncezar Aug 13, 2021
8d01f9d
Export wordcloud from @visx/visx
craciuncezar Aug 13, 2021
877c0df
Add test for @visx/visx index wordcloud export
craciuncezar Aug 13, 2021
978d0da
Replace test renderer with rtl
craciuncezar Aug 13, 2021
1beb2f6
Update package json dependencies
craciuncezar Aug 14, 2021
47d6ea4
Move types into own file
craciuncezar Aug 14, 2021
6df46d4
Make width and height required and exit early in hook
craciuncezar Aug 14, 2021
9ab99e3
Make words required
craciuncezar Aug 14, 2021
7866eb1
Use safer check for undefined
craciuncezar Aug 14, 2021
7a59954
Fix typos
craciuncezar Aug 14, 2021
4280df3
Refactor wordcloud example
craciuncezar Aug 14, 2021
430dc07
Use destructured versions of width and height
craciuncezar Aug 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/visx-demo/package.json
Expand Up @@ -65,6 +65,7 @@
"@visx/threshold": "2.0.1-alpha.0",
"@visx/tooltip": "2.0.1-alpha.0",
"@visx/voronoi": "2.0.1-alpha.0",
"@visx/wordcloud": "0.1.0",
"@visx/xychart": "2.0.1-alpha.0",
"@visx/zoom": "2.0.2-alpha.0",
"@zeit/next-css": "^1.0.1",
Expand Down
22 changes: 22 additions & 0 deletions packages/visx-demo/src/components/Gallery/WordcloudTile.tsx
@@ -0,0 +1,22 @@
import React from 'react';
import Wordcloud from '../../sandboxes/visx-wordcloud/Example';
import GalleryTile from '../GalleryTile';

export { default as packageJson } from '../../sandboxes/visx-wordcloud/package.json';

const tileStyles = { background: '#e4e3d8' };
const detailsStyles = { color: '#111' };

export default function WordcloudTile() {
return (
<GalleryTile
title="Wordcloud"
description="<Wordcloud />"
exampleRenderer={size => <Wordcloud width={size.width} height={size.height} />}
exampleUrl="/wordcloud"
tileStyles={tileStyles}
detailsStyles={detailsStyles}
detailsHeight={0}
/>
);
}
2 changes: 2 additions & 0 deletions packages/visx-demo/src/components/Gallery/index.tsx
Expand Up @@ -45,6 +45,7 @@ import * as TooltipTile from './TooltipTile';
import * as TreemapTile from './TreemapTile';
import * as TreesTile from './TreesTile';
import * as VoronoiTile from './VoronoiTile';
import * as WordcloudTile from './WordcloudTile';
import * as XYChartTile from './XYChartTile';
import * as ZoomITile from './ZoomITile';
import { VisxPackage } from '../../types';
Expand Down Expand Up @@ -98,6 +99,7 @@ export const tiles = [
TooltipTile,
TreesTile,
VoronoiTile,
WordcloudTile,
];

export default function Gallery() {
Expand Down
6 changes: 6 additions & 0 deletions packages/visx-demo/src/components/PackageList.tsx
Expand Up @@ -132,6 +132,12 @@ export default function PackageList({
</Link>
{!compact && <p>Difference charts to compare the delta between two time series</p>}
</li>
<li className={cx(emphasizePackage === 'wordcloud' && 'emphasize')}>
<Link href="/docs/wordcloud">
<a>wordcloud</a>
</Link>
{!compact && <p>Visualize word frequency</p>}
</li>
<li className={cx(emphasizePackage === 'xychart' && 'emphasize')}>
<Link href="/docs/xychart">
<a>xychart</a>
Expand Down
19 changes: 19 additions & 0 deletions packages/visx-demo/src/pages/docs/wordcloud.tsx
@@ -0,0 +1,19 @@
import React from 'react';
import WordcloudReadme from '!!raw-loader!../../../../visx-wordcloud/Readme.md';
import Wordcloud from '../../../../visx-wordcloud/src/Wordcloud';
import DocPage from '../../components/DocPage';
import WordcloudTile from '../../components/Gallery/WordcloudTile';

const components = [Wordcloud];

const examples = [WordcloudTile];

const WordcloudDocs = () => (
<DocPage
components={components}
examples={examples}
readme={WordcloudReadme}
visxPackage="wordcloud"
/>
);
export default WordcloudDocs;
19 changes: 19 additions & 0 deletions packages/visx-demo/src/pages/wordcloud.tsx
@@ -0,0 +1,19 @@
import React from 'react';
import WordcloudSource from '!!raw-loader!../sandboxes/visx-wordcloud/Example';
import Show from '../components/Show';
import Wordcloud from '../sandboxes/visx-wordcloud/Example';
import packageJson from '../sandboxes/visx-wordcloud/package.json';

const WordcloudPage = () => {
return (
<Show
component={({ width, height }) => <Wordcloud width={width} height={height} showControls />}
title="Wordcloud"
codeSandboxDirectoryName="visx-wordcloud"
packageJson={packageJson}
>
{WordcloudSource}
</Show>
);
};
export default WordcloudPage;
Expand Up @@ -37,6 +37,7 @@ import thresholdPackageJson from './visx-threshold/package.json';
import treePackageJson from './visx-tree/package.json';
import treemapPackageJson from './visx-treemap/package.json';
import voronoiPackageJson from './visx-voronoi/package.json';
import wordcloudPackageJson from './visx-wordcloud/package.json';
import zoomPackageJson from './visx-zoom-i/package.json';

import extractVisxDepsFromPackageJson from '../components/util/extractVisxDepsFromPackageJson';
Expand Down Expand Up @@ -82,6 +83,7 @@ const examples = [
treePackageJson,
treemapPackageJson,
voronoiPackageJson,
wordcloudPackageJson,
zoomPackageJson,
];

Expand Down
128 changes: 128 additions & 0 deletions packages/visx-demo/src/sandboxes/visx-wordcloud/Example.tsx
@@ -0,0 +1,128 @@
import React, { useState } from 'react';
import { Text } from '@visx/text';
import { scaleLog } from '@visx/scale';
import Wordcloud from '../../../../visx-wordcloud/src/Wordcloud';
import { totoAfricaLyrics } from './text.fixture';

interface ExampleProps {
width: number;
height: number;
showControls?: boolean;
}

export interface WordData {
text: string;
value: number;
}

const colors = ['#143059', '#2F6B9A', '#82a6c2'];

function wordFreq(text: string): WordData[] {
const words: string[] = text.replace(/\./g, '').split(/\s/);
const freqMap: Record<string, number> = {};

for (const w of words) {
if (!freqMap[w]) freqMap[w] = 0;
freqMap[w] += 1;
}
return Object.keys(freqMap).map(word => ({ text: word, value: freqMap[word] }));
}

function getRotationDegree() {
const rand = Math.random();
const degree = rand > 0.5 ? 60 : -60;
return rand * degree;
}

const words = wordFreq(totoAfricaLyrics);

const fontScale = scaleLog({
domain: [Math.min(...words.map(w => w.value)), Math.max(...words.map(w => w.value))],
range: [10, 100],
});
const fontSizeSetter = (datum: WordData) => fontScale(datum.value);

const fixedValueGenerator = () => 0.5;

type SpiralType = 'archimedean' | 'rectangular';

export default function Example({ width, height, showControls }: ExampleProps) {
const [spiralType, setSpiralType] = useState<SpiralType>('archimedean');
const [withRotation, setWithRotation] = useState(false);

return (
<div className="wordcloud">
<Wordcloud
words={words}
width={width}
height={height}
fontSize={fontSizeSetter}
font={'Impact'}
padding={2}
spiral={spiralType}
rotate={withRotation ? getRotationDegree : 0}
random={fixedValueGenerator}
>
{cloudWords =>
cloudWords.map((w, i) => (
<Text
key={w.text}
fill={colors[i % colors.length]}
textAnchor={'middle'}
transform={`translate(${w.x}, ${w.y}) rotate(${w.rotate})`}
fontSize={w.size}
fontFamily={w.font}
>
{w.text}
</Text>
))
}
</Wordcloud>
{showControls && (
<div>
<label>
Spiral type &nbsp;
<select onChange={e => setSpiralType(e.target.value as SpiralType)} value={spiralType}>
<option key={'archimedean'} value={'archimedean'}>
archimedean
</option>
<option key={'rectangular'} value={'rectangular'}>
rectangular
</option>
</select>
</label>
<label>
With rotation &nbsp;
<input
type="checkbox"
checked={withRotation}
onChange={() => setWithRotation(!withRotation)}
/>
</label>
<br />
</div>
)}
<style jsx>{`
.wordcloud {
display: flex;
flex-direction: column;
user-select: none;
}
.wordcloud svg {
margin: 1rem 0;
cursor: pointer;
}

.wordcloud label {
display: inline-flex;
align-items: center;
font-size: 14px;
margin-right: 8px;
}
.wordcloud textarea {
min-height: 100px;
}
`}</style>
</div>
);
}
11 changes: 11 additions & 0 deletions packages/visx-demo/src/sandboxes/visx-wordcloud/index.tsx
@@ -0,0 +1,11 @@
import React from 'react';
import { render } from 'react-dom';
import ParentSize from '@visx/responsive/lib/components/ParentSize';

import Example from './Example';
import './sandbox-styles.css';

render(
<ParentSize>{({ width, height }) => <Example width={width} height={height} />}</ParentSize>,
document.getElementById('root'),
);
25 changes: 25 additions & 0 deletions packages/visx-demo/src/sandboxes/visx-wordcloud/package.json
@@ -0,0 +1,25 @@
{
"name": "@visx/demo-wordcloud",
"description": "Standalone visx wordcloud demo.",
"main": "index.tsx",
"private": true,
"dependencies": {
"@visx/responsive":"latest",
"@visx/scale":"latest",
"@visx/text":"latest",
"@visx/wordcloud":"latest",
"react": "^16.8",
"react-dom": "^16.8"
},
"devDependencies": {
"@types/react": "^16.8",
"@types/react-dom": "^16.8",
"typescript": "^3"
},
"keywords": [
"visualization",
"d3",
"react",
"visx"
]
}
@@ -0,0 +1,8 @@
html,
body,
#root {
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 2em;
}
30 changes: 30 additions & 0 deletions packages/visx-demo/src/sandboxes/visx-wordcloud/text.fixture.ts
@@ -0,0 +1,30 @@
export const totoAfricaLyrics = `I hear the drums echoing tonight
But she hears only whispers of some quiet conversation
She's coming in, 12:30 flight
The moonlit wings reflect the stars that guide me towards salvation
I stopped an old man along the way
Hoping to find some old forgotten words or ancient melodies
He turned to me as if to say, Hurry boy, it's waiting there for you
It's gonna take a lot to drag me away from you
There's nothing that a hundred men or more could ever do
I bless the rains down in Africa
Gonna take some time to do the things we never had ooh, ooh
The wild dogs cry out in the night
As they grow restless, longing for some solitary company
I know that I must do what's right
As sure as Kilimanjaro rises like Olympus above the Serengeti
I seek to cure what's deep inside, frightened of this thing that I've become
It's gonna take a lot to drag me away from you
There's nothing that a hundred men or more could ever do
I bless the rains down in Africa
Gonna take some time to do the things we never had ooh, ooh
Hurry boy, she's waiting there for you
It's gonna take a lot to drag me away from you
There's nothing that a hundred men or more could ever do
I bless the rains down in Africa
I bless the rains down in Africa
I bless the rain
I bless the rains down in Africa I bless the rain
I bless the rains down in Africa
I bless the rains down in Africa ah, gonna take the time
Gonna take some time to do the things we never had ooh, ooh`;
1 change: 1 addition & 0 deletions packages/visx-demo/src/types/index.ts
Expand Up @@ -50,6 +50,7 @@ export type VisxPackage =
| 'tooltip'
| 'voronoi'
| 'visx'
| 'wordcloud'
| 'xychart'
| 'zoom';

Expand Down
1 change: 1 addition & 0 deletions packages/visx-visx/package.json
Expand Up @@ -60,6 +60,7 @@
"@visx/text": "2.0.1-alpha.0",
"@visx/tooltip": "2.0.1-alpha.0",
"@visx/voronoi": "2.0.1-alpha.0",
"@visx/wordcloud":"0.1.0",
"@visx/xychart": "2.0.1-alpha.0",
"@visx/zoom": "2.0.2-alpha.0"
}
Expand Down
2 changes: 2 additions & 0 deletions packages/visx-visx/src/index.ts
Expand Up @@ -26,6 +26,7 @@ import * as Shape from '@visx/shape';
import * as Text from '@visx/text';
import * as Tooltip from '@visx/tooltip';
import * as Voronoi from '@visx/voronoi';
import * as Wordcloud from '@visx/wordcloud';
import * as Zoom from '@visx/zoom';

export {
Expand Down Expand Up @@ -57,5 +58,6 @@ export {
Text,
Tooltip,
Voronoi,
Wordcloud,
Zoom,
};
4 changes: 4 additions & 0 deletions packages/visx-visx/test/index.test.ts
Expand Up @@ -117,4 +117,8 @@ describe('visx', () => {
it('should export @visx/zoom', () => {
expect(visx.Zoom.Zoom).toBeDefined();
});

it('should export @visx/wordcloud', () => {
expect(visx.Wordcloud.Wordcloud).toBeDefined();
});
});
1 change: 1 addition & 0 deletions packages/visx-wordcloud/.npmrc
@@ -0,0 +1 @@
package-lock=false
williaster marked this conversation as resolved.
Show resolved Hide resolved
14 changes: 14 additions & 0 deletions packages/visx-wordcloud/Readme.md
@@ -0,0 +1,14 @@
# `@visx/wordcloud`

<a title="@visx/wordcloud npm downloads" href="https://www.npmjs.com/package/@visx/wordcloud">
<img src="https://img.shields.io/npm/dm/@visx/wordcloud.svg?style=flat-square" />
</a>

Word clouds are visual representations of text data in which each word's value is indicated by its
font size or color.

## Installation

```
npm install --save @visx/wordcloud
```