React has a number of great charting options to choose from. Not all have the same charts available, but most touch on the staples, such as line, bar, and pie charts. We’ll be focusing on an area chart, which is similar to a line chart, but with the area underneath the line shaded in.
The charting libraries we will be looking at are Recharts, Victory, and Nivo. React-Vis is another nice option, but we’ll be focusing on the aforementioned three in this article, and on Recharts and Victory in this accompanying video.
React area chart comparison
Try LogRocket for free: https://logrocket.com/?yt11 Compare an area chart in Victory and Recharts 0:00 Introduction 1:17 Getting started with Victory Charts 5:28 Learning how to use Recharts 11:00 Comparing Victory Charts and Recharts Link to the codebase: https://github.com/leighhalliday/victory-recharts-area LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser.
The full source code can be found here.
Assuming that multiple libraries can accomplish what you need to do, how you choose depends a little bit on preference and a little bit on what you value. Things I value when choosing a library are (in no particular order):
Here are a few high-level numbers and stats about the charting packages we are covering today:
Charting always requires that you not only have data, but also that it is in the correct format required by the library. All three libraries we are working with want the data in an array of objects, with x
and y
as the keys:
const data = [ { x: "2015", y: 6 }, { x: "2016", y: 13 }, { x: "2017", y: 17 }, { x: "2018", y: 26 }, { x: "2019", y: 38 } ];
The data above represents the number of repositories each year I have created (over my last 100 repos) on GitHub. Unfortunately, GitHub doesn’t provide the data in this format. I started by pulling the createdAt
field using their GraphQL Explorer, with the following query:
{ viewer { repositories(last: 100) { nodes { createdAt name } } } }
It returned a result which resembles this abbreviated list below:
{ "data": { "viewer": { "repositories": { "nodes": [ { "createdAt": "2019-11-15T14:44:19Z", "name": "redux-context-reducers" }, { "createdAt": "2019-11-30T22:26:28Z", "name": "mobx2020" }, { "createdAt": "2019-12-11T20:58:05Z", "name": "victory-recharts-area" }, { "createdAt": "2019-12-15T17:47:24Z", "name": "crime-mapping" } ] } } } }
From this we can do some data wrangling in JavaScript to count how many times each year occurs, converting it into the desired format.
// Extract year from each repo createdAt const repoYears = raw.data.viewer.repositories.nodes.map(repo => parseInt(repo.createdAt.substr(0, 4), 10) ); // Build object with each year initialized to 0 const years = {}; for (let i = Math.min(...repoYears); i <= Math.max(...repoYears); i++) { years[i] = 0; } // Populate years object with actual counts const countsByYearObject = repoYears.reduce( (acc, year) => { acc[year] += 1; return acc; }, { ...years } ); // Convert object into array format victory wants const countsByYear = Object.keys(countsByYearObject).map(year => ({ x: year.toString(), y: countsByYearObject[year] }));
Victory is a great option if you also need to build a similar chart in React Native. It has great React Native support and the API is almost identical between it and the web version of the library. It actually doesn’t take very much code at all to produce a nice looking area chart.
import { VictoryChart, VictoryArea, VictoryTheme } from "victory"; function VictoryDemo() { return ( <div style={{ maxWidth: "800px", margin: "0 auto" }}> <VictoryChart theme={VictoryTheme.material} width={800} height={400}> <VictoryArea data={data} labels={({ datum }) => datum.y} style={{ data: { fill: colors.teal } }} /> </VictoryChart> </div> ); }
You can place multiple area/bar/line charts inside the VictoryChart
container, allowing you to overlay data provided they share the same axes. Victory comes with a couple predefined themes to get your charts looking great, but you can always override these themes with your own values, like I did on the fill color using the style
prop.
The width
and height
properties are in pixels, but they represent more of a ratio rather than an absolute. As you resize the screen, Victory will resize the chart to keep it from going outside of its parent container.
If Victory’s beauty is in its simplicity, Recharts shines when it comes to flexibility. Everything is a component in this package. From the AreaChart
component, right down to the CartesianGrid
component that draws that nice looking dashed grid onto the chart.
I personally have enjoyed working with Recharts a lot. Rather than complicated options, you can mix and match the components together to get exactly what you want. You can even combine multiple charts together within a single ResponsiveContainer
.
Recharts doesn’t assume you will be passing your data with the labels x
and y
, which is why you have to specify the dataKey
props on a number of the different components for it to know where to pull the data from.
import { AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip, ResponsiveContainer, LabelList } from "recharts"; function RechartsDemo() { return ( <div style={{ maxWidth: "800px", margin: "0 auto", height: "400px" }}> <ResponsiveContainer> <AreaChart data={data} margin={{ top: 25, right: 25, bottom: 25, left: 0 }} > <XAxis dataKey="x" /> <YAxis dataKey="y" /> <Area dataKey="y" isAnimationActive={false} name="Repos" fill={colors.teal} stroke={colors.blueGrey} > <LabelList dataKey="y" position="top" offset={10} /> </Area> <CartesianGrid stroke={colors.lightGrey} strokeDasharray="5 5" /> <Tooltip /> </AreaChart> </ResponsiveContainer> </div> ); }
Although I never covered Nivo in the video, it’s such a beautiful library with fantastic documentation that I wanted to include it in this article. The documentation is interactive, and you are able to change options and toggle properties to see in real-time what changes on the chart. It even updates the code as you change properties so that when it looks exactly how you want it to, you can copy and paste the code into your own project.
To produce an area chart, you will start with a line chart, filling in the area underneath the line with a simple option. This was done by passing enableArea={true}
to the ResponsiveLine
component. Nivo feels similar to Victory, in that you deal with fewer components which receive more props to customize the look and feel of the chart:
function NivoDemo() { return ( <div style={{ maxWidth: "800px", margin: "0 auto", height: "400px" }}> <ResponsiveLine data={[ { id: "repos", color: colors.teal, data } ]} margin={{ top: 25, right: 25, bottom: 25, left: 60 }} xScale={{ type: "point" }} yScale={{ type: "linear", min: "auto", max: "auto" }} colors={d => d.color} enableArea={true} useMesh={true} /> </div> ); }
Bringing data alive has always been fun for me. I enjoy wrangling the data into the correct format and then getting the chart to look just right. Charts can convey so much more information to a user than a simple table of numbers. In this article we compared building a very similar area chart in Victory, Recharts, and Nivo, allowing us to compare and contrast them, seeing what makes them tick.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowHandle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
Design React Native UIs that look great on any device by using adaptive layouts, responsive scaling, and platform-specific tools.
Angular’s two-way data binding has evolved with signals, offering improved performance, simpler syntax, and better type inference.