Adding Graphics to a React App with D3 — Bar Chart

John Au-Yeung - Oct 17 '20 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

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

Enter fullscreen mode Exit fullscreen mode

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>
  );
}

Enter fullscreen mode Exit fullscreen mode

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");

Enter fullscreen mode Exit fullscreen mode

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;
  }),
]);

Enter fullscreen mode Exit fullscreen mode

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");

Enter fullscreen mode Exit fullscreen mode

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");

Enter fullscreen mode Exit fullscreen mode

Then we add the y-axis itself by writing:

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

Enter fullscreen mode Exit fullscreen mode

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);
  });

Enter fullscreen mode Exit fullscreen mode

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.

The post Adding Graphics to a React App with D3 — Bar Chart appeared first on The Web Dev.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .