DEV Community

Cover image for Creating a Word Cloud in React βš›οΈπŸ”‘
Matt Lewandowski
Matt Lewandowski

Posted on

Creating a Word Cloud in React βš›οΈπŸ”‘

Have you ever wanted to visualize the most frequent words in a text dataset? Word clouds are an excellent way to do just that, providing a visually appealing and informative representation of text data. In this article, we'll walk through the process of creating a dynamic and customizable word cloud using React and the react-d3-cloud library.

What We'll Build

We're going to create a WordCloudComponent that takes an array of words and their frequencies as input and renders a beautifully formatted word cloud. Our component will have the following features:

  • Dynamic font sizing based on word frequency
  • Customizable font weights
  • Limit on the maximum number of words displayed
  • Responsive design

Let's dive in!

Setting Up the Project

Install the required dependencies:

npm install react-d3-cloud
Enter fullscreen mode Exit fullscreen mode

Building the WordCloudComponent

Let's start by creating our main component. Create a new file called WordCloudComponent.tsx (or .jsx if you're not using TypeScript) and add the following code:

import React, { forwardRef, useCallback, useMemo } from "react";
import WordCloud from "react-d3-cloud";

type Word = { text: string; value: number };

type Props = {
  words: Word[];
};

const MAX_FONT_SIZE = 200;
const MIN_FONT_SIZE = 30;
const MAX_FONT_WEIGHT = 700;
const MIN_FONT_WEIGHT = 400;
const MAX_WORDS = 150;

export const WordCloudComponent = forwardRef<HTMLDivElement, Props>(
  ({ words }, ref) => {
    // Component logic will go here
    return (
      <div ref={ref} style={{ width: "900px", height: "500px" }}>
        {/* WordCloud component will go here */}
      </div>
    );
  }
);

WordCloudComponent.displayName = "WordCloud";
Enter fullscreen mode Exit fullscreen mode

This sets up the basic structure of our component. Let's break down what we're doing here:

  • We're using forwardRef to allow the parent component to access the DOM node of our word cloud.
  • We define a Word type and a Props type to ensure type safety.
  • We set some constants for font size and weight ranges, as well as the maximum number of words to display.

Sorting and Limiting Words

Next, let's add logic to sort the words by frequency and limit the number displayed:

const sortedWords = useMemo(
  () => words.sort((a, b) => b.value - a.value).slice(0, MAX_WORDS),
  [words]
);
Enter fullscreen mode Exit fullscreen mode

We use useMemo to optimize performance by only recalculating when the words prop changes.

Calculating Font Size and Weight

To make our word cloud visually appealing, we'll scale the font size and weight based on the word frequency. Add these functions inside the component:

const [minOccurences, maxOccurences] = useMemo(() => {
  const min = Math.min(...sortedWords.map((w) => w.value));
  const max = Math.max(...sortedWords.map((w) => w.value));
  return [min, max];
}, [sortedWords]);

const calculateFontSize = useCallback(
  (wordOccurrences: number) => {
    const normalizedValue =
      (wordOccurrences - minOccurences) / (maxOccurences - minOccurences);
    const fontSize =
      MIN_FONT_SIZE + normalizedValue * (MAX_FONT_SIZE - MIN_FONT_SIZE);
    return Math.round(fontSize);
  },
  [maxOccurences, minOccurences]
);

const calculateFontWeight = useCallback(
  (wordOccurrences: number) => {
    const normalizedValue =
      (wordOccurrences - minOccurences) / (maxOccurences - minOccurences);
    const fontWeight =
      MIN_FONT_WEIGHT +
      normalizedValue * (MAX_FONT_WEIGHT - MIN_FONT_WEIGHT);
    return Math.round(fontWeight);
  },
  [maxOccurences, minOccurences]
);
Enter fullscreen mode Exit fullscreen mode

These functions calculate the font size and weight based on a linear scale between our defined minimum and maximum values.

Rendering the Word Cloud

Now, let's use the react-d3-cloud library to render our word cloud. Replace the placeholder in the return statement with:

<WordCloud
  width={1800}
  height={1000}
  font={"Poppins"}
  fontWeight={(word) => calculateFontWeight(word.value)}
  data={sortedWords}
  rotate={0}
  padding={1}
  fontSize={(word) => calculateFontSize(word.value)}
  random={() => 0.5}
/>
Enter fullscreen mode Exit fullscreen mode

This sets up the WordCloud component with our calculated font sizes and weights.

Using the WordCloudComponent

To use this component in your React application, you would do something like this:

import { WordCloudComponent } from './WordCloudComponent';

function App() {
  const words = [
    { text: 'React', value: 100 },
    { text: 'JavaScript', value: 80 },
    { text: 'TypeScript', value: 70 },
    // ... more words
  ];

  return (
    <div className="App">
      <h1>My Word Cloud</h1>
      <WordCloudComponent words={words} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Tokenization: Preparing Your Data

Now that we have our word cloud component, let's talk about how to prepare the data. Often, you'll start with raw text and need to tokenize it to get the word frequencies. Here's a simple tokenization function using the 'natural' package:

import { WordTokenizer } from 'natural';
import stopwords from 'natural/lib/natural/util/stopwords';

const tokenizer = new WordTokenizer();
const stopWords = new Set(stopwords);

export const getTokens = (text: string): string[] => {
  const lowerText = text.toLowerCase().replace(/[^\w\s]/g, "");
  return tokenizer
    .tokenize(lowerText)
    .filter((token) => token.length > 1 && !stopWords.has(token));
};
Enter fullscreen mode Exit fullscreen mode

This function does a few important things:

  1. Converts the text to lowercase
  2. Removes punctuation
  3. Tokenizes the text into individual words
  4. Removes stop words (common words like "the", "a", "an" that don't carry much meaning)
  5. Filters out single-character tokens

You can use this function to process your text data before counting word frequencies:

const text = "Your long text here...";
const tokens = getTokens(text);
const wordCounts = tokens.reduce((acc, token) => {
  acc[token] = (acc[token] || 0) + 1;
  return acc;
}, {});

const words = Object.entries(wordCounts).map(([text, value]) => ({ text, value }));
Enter fullscreen mode Exit fullscreen mode

The end

Word cloud

Creating a word cloud with react-d3-cloud is a powerful way to visualize text data. The WordCloudComponent we've built is flexible and can be easily integrated into larger React applications. By customizing font sizes and weights based on word frequencies, we create a visually appealing representation of our data.

Remember, the key steps are:

  1. Tokenize and process your text data
  2. Count word frequencies
  3. Pass the word data to the WordCloudComponent
  4. Render the beautiful word cloud!

Also, shameless plug πŸ”Œ. If you work in an agile dev team and use tools for your online meetings like planning poker or retrospectives, check out my free tool called Kollabe!

Top comments (0)