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
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;
};
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[]);
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],
});
The code defines and initializes several scales for data visualization:
-
parseDate
andformatDate
:-
parseDate
is a function that parses date strings in the format%Y-%m-%d
and converts them to JavaScriptDate
objects. -
formatDate
is a function that takes a date string as input, parses it usingparseDate
, 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.
-
-
getDate
:-
getDate
is a function that takes an object of typeCityTemperature
(presumably containing temperature data for a city) as input and returns thedate
property value from that object. It is used to extract the date values from thedata
array.
-
-
temperatureScale
,dateScale
, andcolorScale
:-
temperatureScale
is a linear scale that is defined usingscaleLinear
. It sets the domain from 0 to the maximum value oftemperatureTotals
, andnice: true
ensures the scale generates nice, human-readable tick values. -
dateScale
is a band scale that is defined usingscaleBand
. It sets the domain to an array of dates extracted from thedata
array using thegetDate
function. It also specifies a padding of 0.2 between the bands. -
colorScale
is an ordinal scale that is defined usingscaleOrdinal
. It sets the domain to thekeys
array, which presumably contains city names. Therange
is an array of color values (e.g.,red1
,red2
,red3
), which will be mapped to each unique city name in thekeys
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>)
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>
)}
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>
The result
This would be the result:
If you find the article is too hard to follow:
- The source code: https://github.com/superdev163/visx-poc
- The live demo: https://visx-poc.web.app/
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)