DEV Community

Cover image for Utilizing VisX for React Data Visualization
Super
Super

Posted on

Utilizing VisX for React Data Visualization

Overview

Welcome to our comprehensive guide on data visualization in React using VisX! Data visualization plays a crucial role in making complex information more understandable and actionable. In this article, we will explore how VisX, a powerful data visualization library built on top of D3, empowers React developers to create stunning and interactive visualizations with ease. Whether you are a seasoned React developer looking to enhance your data presentation skills or a beginner eager to dive into the world of data visualization, this article is your gateway to mastering VisX and unleashing the full potential of data-driven web applications. Join us as we embark on an exciting journey of transforming raw data into beautiful, informative, and impactful visuals with VisX in React. Let's dive in!

The Demo

Charts are among the fundamental examples in data visualization. In this article, we will delve into creating a functional Line Chart demo using VisX

Set up

VisX is all you going to need in this example:

yarn add @visx/visx 
Enter fullscreen mode Exit fullscreen mode

Typings

First, we need to define some types so It will be safer when coding our app

type CityName = 'New York' | 'San Francisco' | 'Austin';

type TooltipData = {
  bar: SeriesPoint<CityTemperature>;
  key: CityName;
  index: number;
  height: number;
  width: number;
  x: number;
  y: number;
  color: string;
};

type BarStackHorizontalProps = {
  width: number;
  height: number;
  margin?: { top: number; right: number; bottom: number; left: number };
  events?: boolean;
};
Enter fullscreen mode Exit fullscreen mode

This code defines three TypeScript types: CityName, TooltipData, and BarStackHorizontalProps. CityName is a union of three string literals, representing city names. TooltipData holds data for displaying tooltips in a chart. BarStackHorizontalProps defines properties for configuring a horizontal bar stack chart.

Mock Data

import cityTemperature, { CityTemperature } from '@visx/mock-data/lib/mocks/cityTemperature';

const data = cityTemperature.slice(0, 20);
const keys = Object.keys(data[0]).filter((d) => d !== 'date') as CityName[];

const temperatureTotals = data.reduce((allTotals, currentDate) => {
  const totalTemperature = keys.reduce((dailyTotal, k) => {
    dailyTotal += Number(currentDate[k]);
    return dailyTotal;
  }, 0);
  allTotals.push(totalTemperature);
  return allTotals;
}, [] as number[]);
Enter fullscreen mode Exit fullscreen mode

The library itself provides us with plenty of mock data built in. This TypeScript code utilizes the VisX library to work with mock temperature data for cities. It creates a subset of the data, filters and extracts relevant keys, and calculates total temperature values for each entry. The results are stored in the temperatureTotals array.

Utilities

const parseDate = timeParse('%Y-%m-%d');
const format = timeFormat('%b %d');
const formatDate = (date: string) => format(parseDate(date) as Date);

const getDate = (d: CityTemperature) => d.date;

const temperatureScale = scaleLinear<number>({
  domain: [0, Math.max(...temperatureTotals)],
  nice: true,
});
const dateScale = scaleBand<string>({
  domain: data.map(getDate),
  padding: 0.2,
});
const colorScale = scaleOrdinal<CityName, string>({
  domain: keys,
  range: [red1, red2, red3],
});
Enter fullscreen mode Exit fullscreen mode

The code defines and initializes several scales for data visualization:

  1. parseDate and formatDate:

    • parseDate is a function that parses date strings in the format %Y-%m-%d and converts them to JavaScript Date objects.
    • formatDate is a function that takes a date string as input, parses it using parseDate, and then formats it to a new string in the format %b %d. This new formatted string represents the date in abbreviated month and day format.
  2. getDate:

    • getDate is a function that takes an object of type CityTemperature (presumably containing temperature data for a city) as input and returns the date property value from that object. It is used to extract the date values from the data array.
  3. temperatureScale, dateScale, and colorScale:

    • temperatureScale is a linear scale that is defined using scaleLinear. It sets the domain from 0 to the maximum value of temperatureTotals, and nice: true ensures the scale generates nice, human-readable tick values.
    • dateScale is a band scale that is defined using scaleBand. It sets the domain to an array of dates extracted from the data array using the getDate function. It also specifies a padding of 0.2 between the bands.
    • colorScale is an ordinal scale that is defined using scaleOrdinal. It sets the domain to the keys array, which presumably contains city names. The range is an array of color values (e.g., red1, red2, red3), which will be mapped to each unique city name in the keys array.

These scales are commonly used in data visualization to map data values to visual properties such as positions, sizes, and colors. The scales play a crucial role in creating meaningful and visually appealing data visualizations.

Tooltip

I have to go to the tooltip first or else the article would be pretty hard to follow. We have to wrap our component with withTooltip from VisX like this:

withTooltip<BarStackHorizontalProps, TooltipData>(
  ({
    width,
    height,
    events = false,
    margin = defaultMargin,
    tooltipOpen,
    tooltipLeft,
    tooltipTop,
    tooltipData,
    hideTooltip,
    showTooltip,
  }: BarStackHorizontalProps & WithTooltipProvidedProps<TooltipData>)
Enter fullscreen mode Exit fullscreen mode

Then we can show the tooltip:

{tooltipOpen && tooltipData && (
          <Tooltip top={tooltipTop} left={tooltipLeft} style={tooltipStyles}>
            <div style={{ color: colorScale(tooltipData.key) }}>
              <strong>{tooltipData.key}</strong>
            </div>
            <div>{tooltipData.bar.data[tooltipData.key]}℉</div>
            <div>
              <small>{formatDate(getDate(tooltipData.bar.data))}</small>
            </div>
          </Tooltip>
        )}
Enter fullscreen mode Exit fullscreen mode

Full code

This is the full implementation of the line chart:

<svg width={width} height={height}>
          <rect width={width} height={height} fill={background} rx={14} />
          <Group top={margin.top} left={margin.left}>
            <BarStackHorizontal<CityTemperature, CityName>
              data={data}
              keys={keys}
              height={yMax}
              y={getDate}
              xScale={temperatureScale}
              yScale={dateScale}
              color={colorScale}
            >
              {(barStacks) =>
                barStacks.map((barStack) =>
                  barStack.bars.map((bar) => (
                    <rect
                      key={`barstack-horizontal-${barStack.index}-${bar.index}`}
                      x={bar.x}
                      y={bar.y}
                      width={bar.width}
                      height={bar.height}
                      fill={bar.color}
                      onClick={() => {
                        if (events) alert(`clicked: ${JSON.stringify(bar)}`);
                      }}
                      onMouseLeave={() => {
                        tooltipTimeout = window.setTimeout(() => {
                          hideTooltip();
                        }, 300);
                      }}
                      onMouseMove={() => {
                        if (tooltipTimeout) clearTimeout(tooltipTimeout);
                        const top = bar.y + margin.top;
                        const left = bar.x + bar.width + margin.left;
                        showTooltip({
                          tooltipData: bar,
                          tooltipTop: top,
                          tooltipLeft: left,
                        });
                      }}
                    />
                  )),
                )
              }
            </BarStackHorizontal>
            <AxisLeft
              hideAxisLine
              hideTicks
              scale={dateScale}
              tickFormat={formatDate}
              stroke={red3}
              tickStroke={red3}
              tickLabelProps={{
                fill: red3,
                fontSize: 11,
                textAnchor: 'end',
                dy: '0.33em',
              }}
            />
            <AxisBottom
              top={yMax}
              scale={temperatureScale}
              stroke={red3}
              tickStroke={red3}
              tickLabelProps={{
                fill: red3,
                fontSize: 11,
                textAnchor: 'middle',
              }}
            />
          </Group>
        </svg>
Enter fullscreen mode Exit fullscreen mode

The result

This would be the result:

Image description

If you find the article is too hard to follow:

Conclusion

In conclusion, VisX shines as a powerful data visualization library for React applications. Its seamless integration with React empowers developers to create visually stunning and interactive data visualizations with ease. By utilizing VisX's extensive array of scales, the process of mapping data to visual elements becomes highly efficient and dynamic. The combination of React and VisX unlocks a world of possibilities for presenting complex data in a clear and engaging manner. Whether you are a seasoned developer or just starting, VisX's strength lies in its ability to transform raw data into compelling visual narratives, making it a valuable asset for any data-driven project. Embrace VisX's capabilities and embark on a journey of crafting captivating and informative data visualizations that leave a lasting impact on your audience.

Top comments (0)