DEV Community

Cover image for Visualizing CO2 Emission with React, World Bank Data and CanvasJS
Manoj Mohan
Manoj Mohan

Posted on

Visualizing CO2 Emission with React, World Bank Data and CanvasJS

Climate change is a critical global issue, with carbon dioxide (CO₂) emissions playing a significant role in driving global warming. To better understand CO₂ emission trends, we can utilize data from the World Bank Data API and visualize it for clearer insights. This article will walk you through building a CO₂ emission chart using React and CanvasJS. This chart will pull data from the World Bank API based on the year selected in a dropdown menu, showcasing the top countries that contribute to CO₂ emissions.

Prerequisites

Before we begin, ensure you have the following installed:

  • Node.js and npm
  • Basic understanding of React

Setting Up the React Project

To get started, we’ll set up a basic React app using create-react-app. Run the following commands to scaffold a new project:

npx create-react-app co2-emission-chart
cd co2-emission-chart
Enter fullscreen mode Exit fullscreen mode

After the project is set up, install CanvasJS React Charts, a JavaScript library that simplifies the creation of interactive and responsive charts for data visualization.

npm install @canvasjs/react-charts
Enter fullscreen mode Exit fullscreen mode

Next, we'll install react-loader-spinner to show a loading indicator while the data is being fetched.

npm install react-loader-spinner
Enter fullscreen mode Exit fullscreen mode

Now that everything is installed, you're prepared to start creating the chart

Fetching CO₂ Emission Data from the World Bank API

The World Bank Data API provides access to a wide range of global data, including CO₂ emissions. For this article, we'll be focusing on carbon dioxide (CO2) emissions measured in kilotons for all countries.
The API endpoint we’ll be using looks like this:

https://api.worldbank.org/v2/country/all/indicator/EN.ATM.CO2E.KT?date=2020&format=json
Enter fullscreen mode Exit fullscreen mode

This API endpoint retrieves data on carbon dioxide (CO2) emissions measured in kilotons for all countries for the year 2020. The indicator EN.ATM.CO2E.KT represents the total amount of CO2 emissions produced by a country.

Creating the React Component for fetching CO₂ Emissions & displaying in chart

Let’s now create a component EmissionChart.js that fetches the data and displays it using CanvasJS. Inside your src folder, create a new file EmissionChart.js and add the following code:

import { useState, useEffect } from 'react';
import CanvasJSReact from '@canvasjs/react-charts';
let CanvasJS = CanvasJSReact.CanvasJS;
let CanvasJSChart = CanvasJSReact.CanvasJSChart;

function EmissionChart() {
  const [emissionDps, setEmissionDps] = useState([]);
  const [yearSelected, setYearSelected] = useState(2020);
  const years = [];
  for (let i = 0; i < 15; i++) {
    years.push(2020 - i);
  }

  let countriesCount = 10;

  let options = {
    title: {
      text: `Top ${countriesCount} CO₂ Emitting Countries`,
    },
    subtitles: [{
      text: `World Bank Data for ${yearSelected}`
    }],
    animationEnabled: true,
    theme: 'light2',
    axisY: {
      title: 'CO₂ emissions (kt)',
      labelFormatter: (e) => addSymbols(e.value),
      suffix: 'kt'
    },
    data: [{
      type: 'bar',
      yValueFormatString: '#,###kt',
      dataPoints: emissionDps,
    }],
  };

  function addSymbols(value) {
    var suffixes = ['', 'K', 'M', 'B'];
    var order = Math.max(Math.floor(Math.log(value) / Math.log(1000)), 0);

    if (order > suffixes.length - 1) order = suffixes.length - 1;

    var suffix = suffixes[order];
    return CanvasJS.formatNumber(value / Math.pow(1000, order)) + suffix;
  }


  async function fetchCountries() {
    const response = await fetch(
      'https://api.worldbank.org/v2/country?format=json&per_page=300'
    );
    const data = await response.json();

    // Filter out non-countries (regions, aggregates) by checking if country code is not 'XD' or similar
    const validCountries = data[1].filter(
      (country) => country.region.id !== 'NA' && country.incomeLevel.id !== 'XD'
    );

    // Create a set of country codes for quick lookup
    const countryCodes = new Set(validCountries.map((country) => country.id));
    return countryCodes;
  }

  async function fetchEmissionData(baseUrl) {
    let emissionRecords = [];
    let page = 1;
    let morePagesAvailable = true;

      // Looping around pages if exist more
    while (morePagesAvailable) {
      // Construct URL for the current page
      const url = `${baseUrl}&page=${page}`;

      try {
        const response = await fetch(url);
        const data = await response.json();

        // World Bank API returns metadata in the first element, data in the second
        const [metadata, records] = data;

        // Append the current page's data to allData
        emissionRecords = emissionRecords.concat(records);

        // Check if there are more pages based on metadata
        const totalPages = metadata.pages;
        if (page >= totalPages) {
          morePagesAvailable = false;
        } else {
          page++;
        }
      } catch (error) {
        console.error('Error fetching data:', error);
        break;
      }
    }

    // Filtering the record as the world bank API contains data for World, regions, etc.
    var countryCodes = await fetchCountries();
    emissionRecords = emissionRecords.filter((record) => {
      return record.value !== null && countryCodes.has(record.countryiso3code);
    });

    emissionRecords.sort((a, b) => b.value - a.value);
    // Parse the emission record data in CanvasJS datapoint format
    let dps = [];
    for (let i = 0; i < countriesCount; i++) {
      dps.push({
        label: emissionRecords[i].country.value,
        y: emissionRecords[i].value,
      });
    }

    setEmissionDps(dps);
  }

  useEffect(() => {
    fetchEmissionData(  
      `https://api.worldbank.org/v2/country/all/indicator/EN.ATM.CO2E.KT?date=${yearSelected}&format=json`
    );
  }, [yearSelected]);

  return (
    <>
      <div className="year-selection">
        <label>
          Select Year:
          <select
            onChangeCapture={(e) => setYearSelected(e.target.value)}
            defaultValue={yearSelected}
          >
            {years.map((year, index) => (
              <option value={year}>{year}</option>
            ))}
          </select>
        </label>
      </div>
      <div className="container">
        <CanvasJSChart
          options={options}
          containerProps={{ width: '100%', height: '360px' }}
        />
      </div>
    </>
  );
}

export default EmissionChart;

Enter fullscreen mode Exit fullscreen mode

Creating the Component for displaying loader while fetching data

Let’s build a Loader component that will be shown while data is being fetched. Additionally, we will introduce a state variable isLoading in the EmissionChart component, which will serve as a flag to determine whether to display the chart or the loader.

/*Loader.js*/
import { Bars } from 'react-loader-spinner';

function Loader({ yearSelected }) {
  return (
    <>
      <Bars
        height="80"
        width="80"
        color="#6f76ab"
        ariaLabel="Loading Data from World Bank API"
        animationDuration="0.75"
        wrapperStyle={{}}
        visible={true}
      />
      <div style={{ textAlign: 'center', marginTop: '16px' }}>
        Hang on for a moment! <br />
        We're pulling CO₂ emissions data for {yearSelected} from the World Bank
      </div>
    </>
  );
}

export default Loader;
Enter fullscreen mode Exit fullscreen mode
/*EmissionChart.js*/
import Loader from './Loader';
.
.

const [isLoading, setIsLoading] = useState(true);

async function fetchEmissionData(baseUrl) {
    setIsLoading(true);
    .
    .
    setEmissionDps(dps);
    setIsLoading(false);
}
.
.
.
return (
  <>
    <div className="year-selection">
      <label>
        Select Year:
        <select
          onChangeCapture={(e) => setYearSelected(e.target.value)}
          defaultValue={yearSelected}
        >
          {years.map((year, index) => (
              <option value={year}>{year}</option>
          ))}
        </select>
      </label>
    </div>
    <div className="container">
      {isLoading ? (
          // Display the loader spinner while fetching data from World Bank API
          <Loader yearSelected={yearSelected} />
      ) : (
          // Display the chart when the data is loaded
          <>
          <CanvasJSChart
              options={options}
              containerProps={{ width: '100%', height: '360px', maxWidth: '920px', margin: 'auto' }}
          />
          </>
      )}
    </div>
  </>
);
.
.
Enter fullscreen mode Exit fullscreen mode

Using the Component in App.js

With the EmissionChart component complete, it's time to integrate it into the main application. Open src/App.js and update it as follows:

/*App.js*/
import EmissionChart from './EmissionChart';
import './App.css';

function App() {
  return (
    <EmissionChart />
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Adding styles to our Component

To improve the appearance of our component, you can add some CSS styles. You can include the following lines in src/App.css

#root {
  height: 100vh;
  width: 100%;
  background: #fff;
  color: #000;
}
body {
  background: #fff;
  color: #000;
}
.year-selection {
  text-align: center;
  margin-bottom: 16px;
  margin-top: 16px;
  display: flex;
  justify-content: center;
  width: auto;
}
.year-selection select {
  margin-left: 8px;
  background: #fff;
  color: #000;
  border-radius: 4px;
  font-size: 16px;
}
.container {
  height: 360px;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.credit-data {
  display: block;
  font-size: 10px;
  color: #8a8484;
  max-width: 920px;
  width: 100%;
  text-align: right;
}
.credit-data a {
  margin-left: 2px;
  margin-right: 2px;
}
Enter fullscreen mode Exit fullscreen mode

Running the Application

All set! You can now run the application by simply using:

npm start
Enter fullscreen mode Exit fullscreen mode

This will start the React app, and when you visit http://localhost:3000, you should see the loading spinner while the data is being fetched, followed by the chart displaying global CO₂ emissions from 2006 to 2020.

Conclusion

In this article, we illustrated how to create a chart displaying the top countries contributing to CO₂ emissions using data from the World Bank API. We’ve established a solid foundation for building a comprehensive dashboard. This dashboard can be utilized to present various environmental statistics, track trends, and support informed decision-making. Happy coding, and let’s keep making a positive impact together!

Top comments (0)