DEV Community

Cover image for React Visualization Libraries in 2019
Artyom Keydunov for Cube

Posted on • Edited on • Originally published at cube.dev

React Visualization Libraries in 2019

While working on Cube.js, we’re seeing a lot of different visualization libraries. Given that Cube.js provides an API layer for analytics on top of an SQL database and doesn’t play on the visualization field, any charting library can be used to build dashboards with it. That’s why we’re always on a search for a nice and developer-friendly visualization library.

The list below is for React-specific libraries. I’ll try to build almost the same stacked bar chart with axes formatting, legend and tooltip using every one of it. For the data backend, we’ll use Cube.js hosted on Heroku. I’ll also use Cube.js React binding, which uses the render props technique and doesn’t render anything itself, letting us build whatever we want with any charting library.

Along the way, I’ll also use two very handy libraries—moment.js and numeral.js for dates and numbers formatting, respectively.

As a data input, we are going to use the resultSet.chartPivot() method from the Cube.js Javascript client. It returns an array of data, and in our case, it looks like this:

[
  {
    "x": "2017-01-01T00:00:00.000",
    "completed, Orders.count": 208,
    "processing, Orders.count": 252,
    "shipped, Orders.count": 233
  },
  {
    "x": "2017-02-01T00:00:00.000",
    "completed, Orders.count": 188,
    "processing, Orders.count": 209,
    "shipped, Orders.count": 222
  },
  
]

Now, let’s jump to the list.

If don’t see your favorite library or just want me to add one more—just ping me in this Public Slack Community. I’m happy to add as many libraries as I can to the list.

Recharts

Recharts provides a set of modular charting components and does a great job by letting you mix those components together to easily build things like a composed line and bar chart.

It is the most popular library to date. It has more than 11k stars on Github, but a huge number (600 to date) of open issues as well.

The documentation is quite extensive but lacks details in some parts. You can find a bunch of examples at Rechart’s website, which could be a good starting point to building your own charts.

Recharts has a bunch of options for customization. Besides that, it allows low-level customization via custom SVG elements.

Here is how to build our stacked bar chart in Recharts.

In this and all the following examples I'm using colors, dateFormatter, and numberFormatter variables. Here is how they are defined:

const numberFormatter = item => numeral(item).format("0,0");
const dateFormatter = item => moment(item).format("MMM YY");
const colors = ["#7DB3FF", "#49457B", "#FF7C78"];
export default ({ resultSet, colors, dateFormatter, numberFormatter }) => (
  <ResponsiveContainer width="100%" height={300}>
    <BarChart data={resultSet.chartPivot()}>
      <XAxis tickFormatter={dateFormatter} dataKey="x" />
      <YAxis tickFormatter={numberFormatter} />
      {resultSet.seriesNames().map((series, i) => (
        <Bar
          stackId="a"
          dataKey={series}
          name={series.split(",")[0]}
          fill={colors[i]}
        />
      ))}
      <Legend />
      <Tooltip labelFormatter={dateFormatter} formatter={numberFormatter} />
    </BarChart>
  </ResponsiveContainer>
);

Victory

Victory follows the same composable pattern as Recharts. It is developed by Formidable, which has other solid open-source libraries besides Victory as well. It is the only library on the list that also works with React Native.

It’s the second most popular library after Recharts with more than 7K stars on Github, but has 5 times less open issues than Recharts. Victory has a community chat on Spectrum.

It is well documented and has an examples gallery.

Victory comes with two themes: grayscale and material, and allows you to create customer themes to have a consistent look across all the charts.

Below you can see the code for our stacked bar chart with Victory:

const transformResult = (series, resultSet) =>
  resultSet.chartPivot().map(element => ({ x: element.x, y: element[series] }));

export default ({ resultSet, dateFormatter, colors, numberFormatter }) => (
  <div height={300}>
    <VictoryChart
      containerComponent={
        <VictoryVoronoiContainer
          voronoiDimension="x"
          labels={(d, i) => `${resultSet.seriesNames()[i]}: ${d.y}`}
          labelComponent={
            <VictoryTooltip cornerRadius={0} flyoutStyle={{ fill: "white" }} />
          }
        />
      }
      domainPadding={{ x: 20, y: [0, 20] }}
    >
      <VictoryLegend
        colorScale={colors}
        data={resultSet.seriesNames().map(series => ({
          name: series.split(",")[0]
        }))}
        orientation="horizontal"
        y={275}
        x={130}
      />
      <VictoryAxis tickFormat={dateFormatter} tickCount={8} />
      <VictoryAxis dependentAxis />
      <VictoryStack colorScale={colors}>
        {resultSet.seriesNames().map((series, i) => (
          <VictoryBar key={i} data={transformResult(series, resultSet)} />
        ))}
      </VictoryStack>
    </VictoryChart>
  </div>
);

Nivo

As well as Recharts and Victory, Nivo is built on top of D3 and is React-specific. But unlike previous libraries it is not composable. It provides one component per chart type and this component is configured via multiple props. Nivo is distributed as a set of packages for specific chart types, for example, @nivo/bar. So, one needs to install a specific package to use a specific chart type.

The project itself is quite active; it has more than 5k stars on Github and almost 300 members in the community chat.

It has interactive documentation, where you can build config for your chart. Although it is nice, It lacks a good old text API reference and search option. It also has a Storybook with examples. It helped me a lot to shortcut the time to build the first chart. Same as Victory, Nivo lets you create your own theme to have a consistent look across all the charts.

We’re going to use the @nivo/bar package for our stack bar chart; you can find a code sample and CodeSandbox demo below.

//https://github.com/plouc/nivo/issues/138#issuecomment-373015114
const ticksFormmater = (ticksCount, value, data, dateFormatter) => {
  const valueIndex = data.map(i => i.x).indexOf(value);
  if (valueIndex % Math.floor(data.length / ticksCount) === 0) {
    return dateFormatter(value);
  }

  return "";
};

export default ({ resultSet, colors, dateFormatter, numberFormatter }) => (
  <div style={{ height: 300 }}>
    <ResponsiveBar
      enableLabel={false}
      colors={colors}
      data={resultSet.chartPivot()}
      keys={resultSet.seriesNames()}
      indexBy="x"
      enableGridY={false}
      padding={0.3}
      margin={{ top: 60, right: 80, bottom: 60, left: 40 }}
      axisLeft={{
        format: numberFormatter
      }}
      axisBottom={{
        format: value =>
          ticksFormmater(8, value, resultSet.chartPivot(), dateFormatter)
      }}
      tooltip={({ id, value, color }) => (
        <strong style={{ color }}>
          {id.split(",")[0]}: {numberFormatter(value)}
        </strong>
      )}
      legends={[
        {
          anchor: "bottom",
          direction: "row",
          translateY: 50,
          itemsSpacing: 2,
          itemWidth: 150,
          itemHeight: 20,
          itemDirection: "left-to-right"
        }
      ]}
    />
  </div>
);

BizCharts

BizCharts is React-specific visualization library based on G2, a visualization grammar. It is backed by Alibaba and plays nicely with Ant Design Framework.

It has almost 4k stars on Github, but the majority of development is in Chinese, same for most of the documentation. I think the team is doing a great job of translating the docs, but it is still a work in progress.

Though, it lacks documentation in English the API is pretty straightforward. The only hard thing is to re-format the data into the specific format for the stacked chart.

const stackedChartData = resultSet => {
  const data = resultSet
    .pivot()
    .map(({ xValues, yValuesArray }) =>
      yValuesArray.map(([yValues, m]) => ({
        x: resultSet.axisValuesString(xValues, ", "),
        color: resultSet.axisValuesString(yValues, ", "),
        measure: m && Number.parseFloat(m)
      }))
    )
    .reduce((a, b) => a.concat(b));

  return data;
};

export default ({ resultSet, dateFormatter, colors, numberFormatter }) => (
      <Chart
        scale={{ x: { tickCount: 10 } }}
        height={400}
        data={stackedChartData(resultSet)}
        forceFit
      >
        <Axis name="x" label={{ formatter: dateFormatter }} />
        <Axis label={{ formatter: numberFormatter }} name="measure" />
        <Tooltip />
        <Geom
          type="intervalStack"
          position={`x*measure`}
          color={["color", colors]}
        />
        <Legend itemFormatter={item => item.split(",")[0]} />
      </Chart>
    )}
  />
);

React-vis

React-vis is being developed by Uber and seems quite active with 5.4k Github stars, 150 open issues, and a lot of recent commits. It is modular, like most of the libraries on the list. It comes with some nice default styles, which should be imported separately as CSS files.

Same as Nivo, it has Storybook with examples. The components API is also well documented. On the customization side you can control the look and feel via custom CSS styles. React-vis also provides a specific component for building custom SVG charts—CustomSVGSeries.

The API is similar to Victory's. You can see I'm using almost the same transformResult from Victory's snippet.

const transformResult = (series, resultSet, dateFormatter) =>
  resultSet
    .chartPivot()
    .map(element => ({ x: Date.parse(element.x), y: element[series] }));

export default ({ resultSet, dateFormatter, colors, numberFormatter }) => (
  <XYPlot xType="time" height={300} width={500} stackBy="y">
    <XAxis tickFormat={dateFormatter} tickSize={8} />
    <YAxis />
    {resultSet.seriesNames().map((series, i) => (
      <VerticalBarSeries
        cluster="stack 1"
        key={i}
        color={colors[i]}
        data={transformResult(series, resultSet, dateFormatter)}
      />
    ))}
    <DiscreteColorLegend
      colors={colors}
      items={resultSet.seriesNames().map(i => i.split(",")[0])}
      orientation="horizontal"
      style={{ position: "absolute", left: 130, bottom: -30 }}
    />
  </XYPlot>
);

If don’t see your favorite library or just want me to add one more—just ping me in this Public Slack Community. I’m happy to add as many libraries as I can to the list.

Top comments (6)

Collapse
 
desi profile image
Desi

This is an awesome collection. I'm working on a personal artsy data project right now, so I love learning about more analytics display tools!

Collapse
 
keydunov profile image
Artyom Keydunov

Thank you!

Collapse
 
karataev profile image
Eugene Karataev

So, what graph library have you selected for your project and why?

Collapse
 
keydunov profile image
Artyom Keydunov

My main project is Cube.js. It's interesting postion to be, because It doesn't need visualization itself, but when implemented in real-world applications it always comes hand in hand with some visualization library. I've been working on multiple deployments of Cube.js and usually, I pick Recharts. I'd say that Recharts' API design and approach when it comes to customization (raw SVG support) are main reasons why I chose it. Also, one should keep in mind that Recharts is SVG based, and may not be a good fit for heavy dashboards. I'd go with canvas-based chart library in that case.

Collapse
 
karataev profile image
Eugene Karataev

Thanks for sharing. I used react-vis for one project and it was nice. Will try Recharts for the next one 🙂

Collapse
 
stereobooster profile image
stereobooster