Categories
React D3

Adding Graphics to a React App with D3 — Bar Chart

Spread the love

D3 lets us add graphics to a front-end web app easily.

Vue is a popular front end web framework.

They work great together. In this article, we’ll look at how to add graphics to a Vue app with D3.

Create a Bar Chart

We can create a bar chart with D3 in our React app by reading in the data, creating the axes, and adding the bars.

For example, we can write:

public/data.csv

year,population
2006,20
2008,25
2010,38
2012,61
2014,43
2016,26
2017,62

src/App.js

import React, { useEffect } from "react";
import * as d3 from "d3";

const createBarChart = async () => {
  const svg = d3.select("svg"),
    margin = 200,
    width = svg.attr("width") - margin,
    height = svg.attr("height") - margin;

  svg
    .append("text")
    .attr("transform", "translate(100,0)")
    .attr("x", 50)
    .attr("y", 50)
    .attr("font-size", "20px")
    .attr("class", "title")
    .text("Population bar chart");

  const x = d3.scaleBand().range([0, width]).padding(0.4),
    y = d3.scaleLinear().range([height, 0]);
  const g = svg.append("g").attr("transform", "translate(100, 100)");
  const data = await d3.csv("data.csv");

  x.domain(
    data.map(function (d) {
      return d.year;
    })
  );
  y.domain([
    0,
    d3.max(data, function (d) {
      return d.population;
    })
  ]);

  g.append("g")
    .attr("transform", `translate(0, ${height})`)
    .call(d3.axisBottom(x))
    .append("text")
    .attr("y", height - 250)
    .attr("x", width - 100)
    .attr("text-anchor", "end")
    .attr("font-size", "18px")
    .attr("stroke", "blue")
    .text("year");

  g.append("g")
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", "-5.1em")
    .attr("text-anchor", "end")
    .attr("font-size", "18px")
    .attr("stroke", "blue")
    .text("population");

  g.append("g").attr("transform", "translate(0, 0)").call(d3.axisLeft(y));
  g.selectAll(".bar")
    .data(data)
    .enter()
    .append("rect")
    .attr("class", "bar")
    .style("fill", "lightgreen")
    .on("mouseover", onMouseOver)
    .on("mouseout", onMouseOut)
    .attr("x", function (d) {
      return x(d.year);
    })
    .attr("y", function (d) {
      return y(d.population);
    })
    .attr("width", x.bandwidth())
    .transition()
    .ease(d3.easeLinear)
    .duration(200)
    .delay(function (d, i) {
      return i * 25;
    })
    .attr("height", function (d) {
      return height - y(d.population);
    });

  function onMouseOver(d, i) {
    d3.select(this).attr("class", "highlight");

    d3.select(this)
      .transition()
      .duration(200)
      .attr("width", x.bandwidth() + 5)
      .attr("y", function (d) {
        return y(d.population) - 10;
      })
      .attr("height", function (d) {
        return height - y(d.population) + 10;
      });

    g.append("text")
      .attr("class", "val")
      .attr("x", function () {
        return x(d.year);
      })
      .attr("y", function () {
        return y(d.value) - 10;
      });
  }

  function onMouseOut(d, i) {
    d3.select(this).attr("class", "bar");

    d3.select(this)
      .transition()
      .duration(200)
      .attr("width", x.bandwidth())
      .attr("y", function (d) {
        return y(d.population);
      })
      .attr("height", function (d) {
        return height - y(d.population);
      });

     d3.selectAll(".val").remove();
  }
};

export default function App() {
  useEffect(() => {
    createBarChart();
  }, []);

  return (
    <div className="App">
      <svg width="500" height="500"></svg>
    </div>
  );
}

We add the svg element in our template.

Then we create the title by writing:

svg
  .append("text")
  .attr("transform", "translate(100,0)")
  .attr("x", 50)
  .attr("y", 50)
  .attr("font-size", "20px")
  .attr("class", "title")
  .text("Population bar chart");

x and y are the x and y coordinates of the top left corner of the text.

transform transforms the text by translating it.

The font-size has the font size for the title.

Then we create the x and y ranges we use for the axes:

const x = d3.scaleBand().range([0, width]).padding(0.4),
  y = d3.scaleLinear().range([height, 0]);
const g = svg.append("g").attr("transform", "translate(100, 100)");
const data = await d3.csv("data.csv");

x.domain(
  data.map(function(d) {
    return d.year;
  })
);
y.domain([
  0,
  d3.max(data, function(d) {
    return d.population;
  }),
]);

We set the domain of x and y with the domain method.

Then we create the x-axis with the axisBottom method:

g.append("g")
  .attr("transform", `translate(0, ${height})`)
  .call(d3.axisBottom(x))
  .append("text")
  .attr("y", height - 250)
  .attr("x", width - 100)
  .attr("text-anchor", "end")
  .attr("font-size", "18px")
  .attr("stroke", "blue")
  .text("year");

The attr method sets all the CSS styles.

Then we add the label for the y-axis by writing:

g.append("g")
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", "-5.1em")
  .attr("text-anchor", "end")
  .attr("font-size", "18px")
  .attr("stroke", "blue")
  .text("population");

Then we add the y-axis itself by writing:

g.append("g").attr("transform", "translate(0, 0)").call(d3.axisLeft(y));

And we add the bars by writing:

g.selectAll(".bar")
  .data(data)
  .enter()
  .append("rect")
  .attr("class", "bar")
  .style("fill", "lightgreen")
  .on("mouseover", onMouseOver)
  .on("mouseout", onMouseOut)
  .attr("x", function(d) {
    return x(d.year);
  })
  .attr("y", function(d) {
    return y(d.population);
  })
  .attr("width", x.bandwidth())
  .transition()
  .ease(d3.easeLinear)
  .duration(200)
  .delay(function(d, i) {
    return i * 25;
  })
  .attr("height", function(d) {
    return height - y(d.population);
  });

We add a mouseover event listener that expands the bar when we hover our mouse over it.

Also, we add the mouseout event listener to restore the bar to its original size when we move our mouse away from the bar.

We set the x and y attributes so that we can position it on the x-axis.

Then, we add some transition to it when it’s loading with the transition , ease , and duration calls.

And finally, we set the height of the bar to by setting the height attribute in the last attr call.

Conclusion

We can create a bar chart from CSV data with D3.

Leave a Reply

Your email address will not be published. Required fields are marked *