Data Visualization with Vue and D3

Shajia Abidi

Whether we’re working in a coffee shop or exercising in a gym, we are surrounded by data. In this article, we’re going to use that data and convert it into data visualization using Vue.js and D3.js. Why data visualization? It’s easier to read and reason about as compared to plain numbers.

We’re going to build an Arc representing the top five countries in the year 2018 with the highest Gross Domestic Product (GDP). The example is taken from the Practical D3.js book, with a Vue twist added.


Note: This article assumes that you have a working knowledge of Vue and D3. Nonetheless, I will be adding links to resources.

For this tutorial, we’ll be utilizing the following tools:

  • D3.js - a JavaScript library for producing dynamic, interactive data visualizations in web browsers
  • Vue.js - an Open Source Model–view–view model JavaScript framework for building user interfaces and single-page applications (SPAs)
  • Vuetify - a Material Design component framework for Vue.js

I’m going to assume that you have the Vue CLI installed, and if not, you can get the installation directions from here. Let’s navigate to the directory we want to work with and create a new Vue project, change into the newly created directory, and open it into your favorite editor.

$ vue create viz-with-vue
$ cd viz-with-vue
$ code .

Before we can begin writing code for our data visualization, let’s install some dependencies we will need. We have to install D3 and Vuetify. I’ve decided to use npm, but you can use yarn as well.

$ npm install vuetify d3

Now that we have everything installed let’s start coding. Head over to our App.vue, firstly, let’s remove all the content in the <template> tag. Second, let’s remove the HelloWorld component and imports.

A Vue file is divided into three parts: HTML which is inside our <template> tag, JavaScript which is in our <script> tags and lastly, styles which are in our <style> tags.

For this article, we’ll focus on the first two parts. Using Vuetify’s 12 point grid system, we’ll layout our app.

HTML Template

<template>
  <v-app>
    <v-container>
      <v-row>
        <v-col cols="4" class="d-flex justify-center align-center">
          <div class="pa-2">
            <h3 class="pb-2">Countries in 2018 with the highest GDP</h3>
            <p>
              Gross domestic product by country allows you to compare the economies of the nations.
              It measures everything produced by everyone in the country whether they are citizens or foreigners.
              The data has been taken from
              <a
                href="https://www.thebalance.com/gdp-by-country-3-ways-to-compare-3306012"
              >The Balance</a>.
            </p>
          </div>
        </v-col>
        <v-col id="arc" />
      </v-row>
    </v-container>
  </v-app>
</template>

In the above code snippet, we created two columns: one for text and the other for visual. We are using a lot of Vuetify’s classes and attributes. It makes it super easy to focus on our logic and worry less about the layout. Let’s break it down.

At the top, we have a v-container, which provides the ability to center and horizontally pad our site’s contents. Next, we have v-row, which is a wrapper component for v-col. Lastly, we have v-col, which holds our content.

The <v-col> tags have a few different classes. The classes are adding flex properties. Vuetify is a 12 point grid system that is built using flexbox. The added properties control the alignment and justification of the <v-col>, and it’s children.

You will also see some classes named pa-2 and pb-2. These are some helper Vuetify classes that assist with spacing.

The D3 magic happens on this line: <v-col id="arc" />

There is nothing fancy going on here. It’s just a <v-col> tag with an id of arc. We will use this id in our <script> tag to append our SVG.

Enter D3.js

<script>
import * as d3 from "d3";

export default {
  name: "App",
  data() {
    return {
      gdp: [
        {country: "USA", value: 20.5 },
        {country: "China", value: 13.4 },
        {country: "Germany", value: 4.0 },
        {country: "Japan", value: 4.9 },
        {country: "France", value: 2.8 }
      ]
    };
  },
  // ...
</script>

We’ve already installed D3, and now we import it. Then we return our data object from the data function. For this example, we have one element in the data object called gdp.

  // ...
  mounted() {
    this.generateArc();
  },
  methods: {
    generateArc() {
      const w = 500;
      const h = 500;

      const svg = d3
        .select("#arc")
        .append("svg")
        .attr("width", w)
        .attr("height", h);

      const sortedGDP = this.gdp.sort((a, b) => (a.value > b.value ? 1 : -1));
      const color = d3.scaleOrdinal(d3.schemeDark2);

      const max_gdp = d3.max(sortedGDP, o => o.value);

      const angleScale = d3
        .scaleLinear()
        .domain([0, max_gdp])
        .range([0, 1.5 * Math.PI]);

      const arc = d3
        .arc()
        .innerRadius((d, i) => (i + 1) * 25)
        .outerRadius((d, i) => (i + 2) * 25)
        .startAngle(angleScale(0))
        .endAngle(d => angleScale(d.value));

      const g = svg.append("g");

      g.selectAll("path")
        .data(sortedGDP)
        .enter()
        .append("path")
        .attr("d", arc)
        .attr("fill", (d, i) => color(i))
        .attr("stroke", "#FFF")
        .attr("stroke-width", "1px")
        .on("mouseenter", function() {
          d3.select(this)
            .transition()
            .duration(200)
            .attr("opacity", 0.5);
        })
        .on("mouseout", function() {
          d3.select(this)
            .transition()
            .duration(200)
            .attr("opacity", 1);
        });

      g.selectAll("text")
        .data(this.gdp)
        .enter()
        .append("text")
        .text(d => `${d.country} -  ${d.value} Trillion`)
        .attr("x", -150)
        .attr("dy", -8)
        .attr("y", (d, i) => -(i + 1) * 25);

      g.attr("transform", "translate(200,300)");
  }
}
};
</script>

In our mounted function, we call our method generateArc. This is where we create our visual.

We’ve defined the width and the height of the SVG with w and h, respectively. Then we select the div with the id arc, using d3.select() and passing in the id. We then append the SVG to the selected element and add a width and the height.

At this point, if we open our console, we will see an SVG tag with a width and height of 500 in our div element.

In the following line, we sort our data. This will help with the visualization of the arc. If we sort the data ascendingly, the innermost arc will have the smallest value.

Next, we use D3’s color module to generate different colors.

We then find out the maximum value in our data. This helps us in calculating the domain. We can either manually calculate the scaling or let scales in D3 figure it for us.

In domain, we pass in the minimum and the maximum of our data set. We tell D3 the values can go anywhere from minimum to maximum. The minimum and maximum passed in the range tell D3 how you want to represent the domain.

Then comes the arc generator. It generates an arc with the given arguments. It takes in four arguments: innerRadius, outerRadius, startAngle, and endAngle. The startAngle of all the values is going to be 0, but the endAngle will depend on the gdp value.

We then append the g element. We do this to group our arcs and text together.

We then select all the path, knowing well that no path exists in the g element. You can check in the console, and you will find that g doesn’t have any path. D3 is smart, and it knows that. After you pass in the data set in the data() function, you will execute enter(). The enter function identifies any DOM elements that need to be added. If the path doesn’t exist, enter() will append the path.

We then set the value, fill, stroke, and stroke-width attributes to the path element. We also add a simple transition, that changes the opacity of the arc on mouseenter and mouseout.

Similarly, we select all the text tags, set the value, x, dx and, dy coordinates, and voilà, we have the gdp value next to the arc.

In the end, we move the entire group using transformation.


And there you have it, data visualization in Vue.js generated with the help of D3.js! ✨

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#