Author avatar

Benney Au

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

Benney Au

  • Sep 24, 2020
  • 11 Min read
  • 114 Views
  • Sep 24, 2020
  • 11 Min read
  • 114 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:

1
yarn start

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React from "react";
import BarChart from "./BarChart";
import * as d3 from "d3";
import "./App.css";

function App() {
  const [data, setData] = React.useState([]);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    d3.csv("/chart-data.csv").then((d) => {
      setData(d);
      setLoading(false);
    });
    return () => undefined;
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        {loading && <div>loading</div>}
        {!loading && <BarChart data={data} />}
      </header>
    </div>
  );
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React from "react";
import BarChart from "./BarChart";
import * as d3 from "d3";
import "./App.css";

function App() {
  const [data, setData] = React.useState([]);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    d3.json("/chart-data.json").then((d) => {
      setData(d);
      setLoading(false);
    });
    return () => undefined;
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        {loading && <div>loading</div>}
        {!loading && <BarChart data={data} />}
      </header>
    </div>
  );
}

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

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

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

1