In this blog, we will see how to plot a simple line chart using ReactJS and D3JS.
If you are not familiar with ReactJS then please take a look at official ReactJS webpage. You can also look at our Learn ReactJS in steps video series.
What is D3.js
D3.js is a Javascript library used to create interactive, dynamic visualizations.
Let's take a step by step look at how we can integrate ReactJS with D3JS to plot some interactive visualizations.
Step 1 - Get ReactJS example working
We will be using JSFiddle example from ReactJS Docs to begin with. Fork the JSFiddle example and you should be good to go.
Step 2 - Add D3.js as an external resource
We will be using D3.js from Cloudflare CDN. Add D3.js as an external resource as shown in the image given below and type the following URL as an external resource.
1https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.12/d3.js
Step 3 - Build ReactJS components to create visualizations with D3.js
Now let's try to draw a Line Chart using D3.js.
Let's create a Line component that renders line path for the data points provided.
1const Line = React.createClass({ 2 propTypes: { 3 path: React.PropTypes.string.isRequired, 4 stroke: React.PropTypes.string, 5 fill: React.PropTypes.string, 6 strokeWidth: React.PropTypes.number, 7 }, 8 9 getDefaultProps() { 10 return { 11 stroke: "blue", 12 fill: "none", 13 strokeWidth: 3, 14 }; 15 }, 16 17 render() { 18 let { path, stroke, fill, strokeWidth } = this.props; 19 return ( 20 <path d={path} fill={fill} stroke={stroke} strokeWidth={strokeWidth} /> 21 ); 22 }, 23});
Here in above code, Line component renders an SVG path. Path data d is generated using D3 path functions.
Let's create another component DataSeries that will render Line component for each series of data provided. This generates path based on xScale and yScale generated for plotting a line chart.
1const DataSeries = React.createClass({ 2 propTypes: { 3 colors: React.PropTypes.func, 4 data: React.PropTypes.object, 5 interpolationType: React.PropTypes.string, 6 xScale: React.PropTypes.func, 7 yScale: React.PropTypes.func, 8 }, 9 10 getDefaultProps() { 11 return { 12 data: [], 13 interpolationType: "cardinal", 14 colors: d3.scale.category10(), 15 }; 16 }, 17 18 render() { 19 let { data, colors, xScale, yScale, interpolationType } = this.props; 20 21 let line = d3.svg 22 .line() 23 .interpolate(interpolationType) 24 .x((d) => { 25 return xScale(d.x); 26 }) 27 .y((d) => { 28 return yScale(d.y); 29 }); 30 31 let lines = data.points.map((series, id) => { 32 return <Line path={line(series)} stroke={colors(id)} key={id} />; 33 }); 34 35 return ( 36 <g> 37 <g>{lines}</g> 38 </g> 39 ); 40 }, 41});
Here in above code d3.svg.line creates a new line generator which expects input as a two-element array of numbers.
Now we will create LineChart component that will calculate xScale, yScale based on data and will render DataSeries by passing xScale, yScale, data (input x,y values), width, height for the chart.
1const LineChart = React.createClass({ 2 propTypes: { 3 width: React.PropTypes.number, 4 height: React.PropTypes.number, 5 data: React.PropTypes.object.isRequired, 6 }, 7 8 getDefaultProps() { 9 return { 10 width: 600, 11 height: 300, 12 }; 13 }, 14 15 render() { 16 let { width, height, data } = this.props; 17 18 let xScale = d3.scale 19 .ordinal() 20 .domain(data.xValues) 21 .rangePoints([0, width]); 22 23 let yScale = d3.scale 24 .linear() 25 .range([height, 10]) 26 .domain([data.yMin, data.yMax]); 27 28 return ( 29 <svg width={width} height={height}> 30 <DataSeries 31 xScale={xScale} 32 yScale={yScale} 33 data={data} 34 width={width} 35 height={height} 36 /> 37 </svg> 38 ); 39 }, 40});
Here d3.scale.ordinal constructs an ordinal scale that can have discrete domain while d3.scale.linear constructs a linear quantitative scale.
You can learn more about D3 Quantitative scales here.
Now we need to call LineDataSeries component with the data.
1let data = { 2 points: [ 3 [ 4 { x: 0, y: 20 }, 5 { x: 1, y: 30 }, 6 { x: 2, y: 10 }, 7 { x: 3, y: 5 }, 8 { x: 4, y: 8 }, 9 { x: 5, y: 15 }, 10 { x: 6, y: 10 }, 11 ], 12 [ 13 { x: 0, y: 8 }, 14 { x: 1, y: 5 }, 15 { x: 2, y: 20 }, 16 { x: 3, y: 12 }, 17 { x: 4, y: 4 }, 18 { x: 5, y: 6 }, 19 { x: 6, y: 2 }, 20 ], 21 [ 22 { x: 0, y: 0 }, 23 { x: 1, y: 5 }, 24 { x: 2, y: 8 }, 25 { x: 3, y: 2 }, 26 { x: 4, y: 6 }, 27 { x: 5, y: 4 }, 28 { x: 6, y: 2 }, 29 ], 30 ], 31 xValues: [0, 1, 2, 3, 4, 5, 6], 32 yMin: 0, 33 yMax: 30, 34}; 35 36ReactDOM.render( 37 <LineChart data={data} width={600} height={300} />, 38 document.getElementById("container") 39);
An element with id container is replaced with content rendered by LineChart.
If we take a look at the output now, we see how the Line Chart gets plotted.
To build complex visualizations in a modularized fashion, we can use one of the open source libraries mentioned below based on their advantages and disadvantages.
ReactJS + D3.js Open Source Projects
Here are two popular open source ReactJS + D3.JS projects.
react-d3
Pros
- Supports Bar chart, Line chart, Area chart, Pie chart, Candlestick chart, Scattered chart and Treemap.
- Legend support.
- Tooltips support.
Cons
- No support for Animations. You can implement animations using D3 Transitions.
- Only stacked Bar chart support.
react-d3-components
Pros
- Custom scales support.
- Supports Bar chart (Stacked, Grouped), Line chart, Area chart, Pie chart, Scattered chart.
- Tooltips support.
Cons
- No Legend support.
- No support for Animations.
Summary
Below is final working example of JSFiddle built in the post.