Author avatar

Benney Au

Loading Remote Chart Data for D3.js in a React App

Benney Au

  • Sep 24, 2020
  • 11 Min read
  • 3,593 Views
  • Sep 24, 2020
  • 11 Min read
  • 3,593 Views
Web Development
Front End Web Development
Client-side Frameworks
React

Introduction

At the heart of D3.js is joining data to visualizations in order to easily understand and interpret large datasets. Usually, these datasets are dynamic and come in different formats.

In this guide, you will learn how to process different data formats using D3-fetch in a React app. D3-fetch is a simple wrapper around the standard fetch API built into modern browsers; it makes it more convenient to interact with different file formats.

This guide builds on a previous guide, Using D3.js Inside a React App, where you learn how to set up a simple bar chart in D3.js using static in-memory data. Here, you will learn about accessing JSON, CSV, and XML remote data formats and bind them to your chart. The data is sourced from the Bureau of Transportation Statistics.

Fetch CSV Data

Comma-separated values (CSV) is a common format for sharing data as it is simple and easy to understand. To start fetching remote CSV data, start a React app and place a CSV file in the /public folder to serve it locally. To do this run:

1yarn start

Then create a the file public/chart-data.csv and paste the following contents.

1year,efficiency,sales
21980,24.3,8949000
31985,27.6,10979000
41990,28,9303000
51991,28.4,8185000
61992,27.9,8213000
71993,28.4,8518000
81994,28.3,8991000
91995,28.6,8620000
101996,28.5,8479000
111997,28.7,8217000
121998,28.8,8085000
131999,28.3,8638000
142000,28.5,8778000
152001,28.8,8352000
162002,29,8042000
172003,29.5,7556000
182004,29.5,7483000
192005,30.3,7660000
202006,30.1,7762000
212007,31.2,7562000
222008,31.5,6769000
232009,32.9,5402000
242010,33.9,5636000
252011,33.1,6093000
262012,35.3,7245000
272013,36.4,7586000
282014,36.5,7708000
292015,37.2,7517000
302016,37.7,6873000
312017,39.4,6081000
csv

You can now navigate to http://localhost:3000/chart-data.csv to see your data being served locally.

With a CSV file being served, you can modify your React code and display its data in a chart.

Update src/App.js to the below code to fetch CSV data.

1import React from "react";
2import BarChart from "./BarChart";
3import * as d3 from "d3";
4import "./App.css";
5
6function App() {
7  const [data, setData] = React.useState([]);
8  const [loading, setLoading] = React.useState(true);
9
10  React.useEffect(() => {
11    d3.csv("/chart-data.csv").then((d) => {
12      setData(d);
13      setLoading(false);
14    });
15    return () => undefined;
16  }, []);
17
18  return (
19    <div className="App">
20      <header className="App-header">
21        {loading && <div>loading</div>}
22        {!loading && <BarChart data={data} />}
23      </header>
24    </div>
25  );
26}
27
28export default App;
javascript

The code snippet above demonstrates fetching CSV data when the App component is loaded. When the component is loaded, the default state is loading=true and a request is made to localhost:3000/chart-data.csv to fetch the data. When the fetch request is complete, it will update the state of the application to loading=false and display the BarChart component passing down the retrieved data.

Retrieve JSON Data

JSON is another popular format for sharing data. Compared to CSV, it allows hierarchical data types but is more verbose. To start serving JSON, create the file public/chart-data.json and add the following contents.

1[
2  {"year": 1980, "efficiency": 24.3, "sales": 8949000},
3  {"year": 1985, "efficiency": 27.6, "sales": 10979000},
4  {"year": 1990, "efficiency": 28, "sales": 9303000},
5  {"year": 1991, "efficiency": 28.4, "sales": 8185000},
6  {"year": 1992, "efficiency": 27.9, "sales": 8213000},
7  {"year": 1993, "efficiency": 28.4, "sales": 8518000},
8  {"year": 1994, "efficiency": 28.3, "sales": 8991000},
9  {"year": 1995, "efficiency": 28.6, "sales": 8620000},
10  {"year": 1996, "efficiency": 28.5, "sales": 8479000},
11  {"year": 1997, "efficiency": 28.7, "sales": 8217000},
12  {"year": 1998, "efficiency": 28.8, "sales": 8085000},
13  {"year": 1999, "efficiency": 28.3, "sales": 8638000},
14  {"year": 2000, "efficiency": 28.5, "sales": 8778000},
15  {"year": 2001, "efficiency": 28.8, "sales": 8352000},
16  {"year": 2002, "efficiency": 29, "sales": 8042000},
17  {"year": 2003, "efficiency": 29.5, "sales": 7556000},
18  {"year": 2004, "efficiency": 29.5, "sales": 7483000},
19  {"year": 2005, "efficiency": 30.3, "sales": 7660000},
20  {"year": 2006, "efficiency": 30.1, "sales": 7762000},
21  {"year": 2007, "efficiency": 31.2, "sales": 7562000},
22  {"year": 2008, "efficiency": 31.5, "sales": 6769000},
23  {"year": 2009, "efficiency": 32.9, "sales": 5402000},
24  {"year": 2010, "efficiency": 33.9, "sales": 5636000},
25  {"year": 2011, "efficiency": 33.1, "sales": 6093000},
26  {"year": 2012, "efficiency": 35.3, "sales": 7245000},
27  {"year": 2013, "efficiency": 36.4, "sales": 7586000},
28  {"year": 2014, "efficiency": 36.5, "sales": 7708000},
29  {"year": 2015, "efficiency": 37.2, "sales": 7517000},
30  {"year": 2016, "efficiency": 37.7, "sales": 6873000},
31  {"year": 2017, "efficiency": 39.4, "sales": 6081000}
32]
json

You have created a JSON file, and it is served at http://localhost:3000/chart-data.json, similar to the CSV sample. To start fetching this data, you only need to make minor modifications to App.js. It will look like the code snippet below:

1import React from "react";
2import BarChart from "./BarChart";
3import * as d3 from "d3";
4import "./App.css";
5
6function App() {
7  const [data, setData] = React.useState([]);
8  const [loading, setLoading] = React.useState(true);
9
10  React.useEffect(() => {
11    d3.json("/chart-data.json").then((d) => {
12      setData(d);
13      setLoading(false);
14    });
15    return () => undefined;
16  }, []);
17
18  return (
19    <div className="App">
20      <header className="App-header">
21        {loading && <div>loading</div>}
22        {!loading && <BarChart data={data} />}
23      </header>
24    </div>
25  );
26}
27
28export default App;
javascript

Note that you have only changed the URL to /chart-data.json and the function call from d3.csv to d3.json.

Fetch XML Data

Another common data format is XML. This can be more verbose, therefore it is not preferred for new development and is more commonly used in older legacy systems. To serve this format, create the file public/chart-data.xml and add the following contents.

1<?xml version="1.0" encoding="UTF-8"?>
2<root>
3   <element>
4      <efficiency>24.3</efficiency>
5      <sales>8949000</sales>
6      <year>1980</year>
7   </element>
8   <element>
9      <efficiency>27.6</efficiency>
10      <sales>10979000</sales>
11      <year>1985</year>
12   </element>
13   <element>
14      <efficiency>28</efficiency>
15      <sales>9303000</sales>
16      <year>1990</year>
17   </element>
18   <element>
19      <efficiency>28.4</efficiency>
20      <sales>8185000</sales>
21      <year>1991</year>
22   </element>
23   <element>
24      <efficiency>27.9</efficiency>
25      <sales>8213000</sales>
26      <year>1992</year>
27   </element>
28   <element>
29      <efficiency>28.4</efficiency>
30      <sales>8518000</sales>
31      <year>1993</year>
32   </element>
33   <element>
34      <efficiency>28.3</efficiency>
35      <sales>8991000</sales>
36      <year>1994</year>
37   </element>
38   <element>
39      <efficiency>28.6</efficiency>
40      <sales>8620000</sales>
41      <year>1995</year>
42   </element>
43   <element>
44      <efficiency>28.5</efficiency>
45      <sales>8479000</sales>
46      <year>1996</year>
47   </element>
48   <element>
49      <efficiency>28.7</efficiency>
50      <sales>8217000</sales>
51      <year>1997</year>
52   </element>
53   <element>
54      <efficiency>28.8</efficiency>
55      <sales>8085000</sales>
56      <year>1998</year>
57   </element>
58   <element>
59      <efficiency>28.3</efficiency>
60      <sales>8638000</sales>
61      <year>1999</year>
62   </element>
63   <element>
64      <efficiency>28.5</efficiency>
65      <sales>8778000</sales>
66      <year>2000</year>
67   </element>
68   <element>
69      <efficiency>28.8</efficiency>
70      <sales>8352000</sales>
71      <year>2001</year>
72   </element>
73   <element>
74      <efficiency>29</efficiency>
75      <sales>8042000</sales>
76      <year>2002</year>
77   </element>
78   <element>
79      <efficiency>29.5</efficiency>
80      <sales>7556000</sales>
81      <year>2003</year>
82   </element>
83   <element>
84      <efficiency>29.5</efficiency>
85      <sales>7483000</sales>
86      <year>2004</year>
87   </element>
88   <element>
89      <efficiency>30.3</efficiency>
90      <sales>7660000</sales>
91      <year>2005</year>
92   </element>
93   <element>
94      <efficiency>30.1</efficiency>
95      <sales>7762000</sales>
96      <year>2006</year>
97   </element>
98   <element>
99      <efficiency>31.2</efficiency>
100      <sales>7562000</sales>
101      <year>2007</year>
102   </element>
103   <element>
104      <efficiency>31.5</efficiency>
105      <sales>6769000</sales>
106      <year>2008</year>
107   </element>
108   <element>
109      <efficiency>32.9</efficiency>
110      <sales>5402000</sales>
111      <year>2009</year>
112   </element>
113   <element>
114      <efficiency>33.9</efficiency>
115      <sales>5636000</sales>
116      <year>2010</year>
117   </element>
118   <element>
119      <efficiency>33.1</efficiency>
120      <sales>6093000</sales>
121      <year>2011</year>
122   </element>
123   <element>
124      <efficiency>35.3</efficiency>
125      <sales>7245000</sales>
126      <year>2012</year>
127   </element>
128   <element>
129      <efficiency>36.4</efficiency>
130      <sales>7586000</sales>
131      <year>2013</year>
132   </element>
133   <element>
134      <efficiency>36.5</efficiency>
135      <sales>7708000</sales>
136      <year>2014</year>
137   </element>
138   <element>
139      <efficiency>37.2</efficiency>
140      <sales>7517000</sales>
141      <year>2015</year>
142   </element>
143   <element>
144      <efficiency>37.7</efficiency>
145      <sales>6873000</sales>
146      <year>2016</year>
147   </element>
148   <element>
149      <efficiency>39.4</efficiency>
150      <sales>6081000</sales>
151      <year>2017</year>
152   </element>
153</root>
xml

To query this data, update App.js and change the useEffect hook to the following:

1React.useEffect(() => {
2    d3.xml("/chart-data.xml").then((d) => {
3      const chartData = [];
4      for (const element of d.children[0].children) {
5        chartData.push({
6          efficiency: element.children[0].textContent,
7          sales: element.children[1].textContent,
8          year: element.children[2].textContent
9        })
10      }
11      setData(chartData);
12      setLoading(false);
13    });
14    return () => undefined;
15  }, []);
javascript

Notice that we have changed the URL to /chart-data.xml and the function call to d3.xml. Further, there is some extra code required to parse the XML data. This style of parsing code is error prone and requires some trial and error to get it right. It is better to retrieve your data in JSON or CSV format, since it is easier to work with from JavaScript.

Conclusion

Binding a chart from a remote data source is important for making your website visually appealing and dynamic. You have learned how to work with JSON, CSV, and XML formats. As a next step, you may want to learn more about the Fetch API to perform more advanced interactions, such as passing custom headers and error handling.