Categories
Vue and D3

Loading Data into a Vue App with D3

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 load data into a Vue app with D3.

Loading CSV

We can load CSV data into our Vue app with the d3.csv method.

For example, we can write:

public/data.csv

name,age
John,30
Jane,32

App.vue

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
export default {
  name: "App",
  async mounted() {
    const data = await d3.csv("/data.csv");
    for (const { name, age } of data) {
      console.log(name, age);
    }
  },
};
</script>

to load data from public/data.csv into our Vue app.

The public folder is served statically, so we can read data from there.

We just call d3.csv with the path to the CSV file.

Then it’ll parsed automatically into an array of objects.

Therefore, we get:

John 30
Jane 32

logged when we loop through the data array.

Loading JSON

We can load JSON into our app with the d3.json method.

For example, we can write:

public/data.json

[
  {
    "name": "John",
    "age": 30,
    "city": "New York"
  },
  {
    "name": "Jane",
    "age": 20,
    "city": "San Francisco"
  }
]

App.vue

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
export default {
  name: "App",
  async mounted() {
    const data = await d3.json("/data.json");
    for (const { name, age } of data) {
      console.log(name, age);
    }
  },
};
</script>

We call d3.json to get the data.

Then we loop through the data array which has the parsed JSON array.

So we get the same result as we did in the previous example.

Loading XML File

We can load XML files with the d3.xml method.

To use it, we can write:

public/data.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
<row>
    <name>John</name>
    <age>30</age>
</row>
<row>
    <name>Jane</name>
    <age>32</age>
</row>
</root>

App.vue

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
export default {
  name: "App",
  async mounted() {
    const data = await d3.xml("/data.xml");
    for (const n of data.documentElement.getElementsByTagName("name")) {
      console.log(n.textContent);
    }
  },
};
</script>

We call d3.xml to read the data.xml file.

The method returns the parsed XML DOM object.

Therefore, we can use the documentElement.getElementByTagName method to get the name elements by their tag name.

And then we can log the textContent to log the content.

Loading Tab Separated Files

We can read tab-separated files with the d3.tsv method.

For example, we can write:

public/data.tsv

name age city
John 30 New York
Jane 20 San Francisco

App.vue

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
export default {
  name: "App",
  async mounted() {
    const data = await d3.tsv("/data.tsv");
    for (const { name, age, city } of data) {
      console.log(name, age, city);
    }
  },
};
</script>

to call the d3.tsv method to load data.tsv .

It returns a promise with an array of data.

Then we can loop through the data entry and log them.

Conclusion

We can load CSV, TSV, XML, and JSON files with D3 in our Vue app.

Categories
Vue and D3

Adding Graphics to a Vue App with D3 — TSV, Timer, and Bar Chart

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.

tsvFormatRows

We can call the tsvFormatRows method to convert a nested array into a tab-separated string.

For example, we can write:

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
const data = [
  [2011, 10],
  [2012, 20],
  [2013, 30],
];
export default {
  name: "App",
  mounted() {
    const string = d3.tsvFormatRows(data);
    console.log(string);
  },
};
</script>

Then string is:

2011 10
2012 20
2013 30

Timer

We can use timers that come with D3 to add animations to our Vue app.

For example, we can use the d3.timer function to create a timer by writing:

<template>
  <div id="app"></div>
</template>

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

export default {
  name: "App",
  mounted() {
    const timer = d3.timer(function (duration) {
      console.log(duration);
      if (duration > 150) {
        timer.stop();
      }
    }, 100);
  },
};
</script>

We log the duration and stop the timer if the duration is bigger than 150.

duration is in milliseconds.

Create a Bar Chart

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

For example, we can write:

public/data.csv

year,population
2006,30
2008,35
2010,28
2012,31
2014,43
2016,56
2017,62

App.vue

<template>
  <div id="app">
    <svg width="500" height="500"></svg>
  </div>
</template>

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

export default {
  name: "App",
  mounted() {
    Vue.nextTick(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();
      }
    });
  },
};
</script>

We add the svg element in our template.

Then in the nextTick callback, 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 text’s position.

transform transforms the text.

text has the text itself.

font-size sets the font size of the text.

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 methods.

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

We set the styles with attr calls.

The text call adds the label for the x-axis.

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

Then 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 have a mouseout event listener to restore the bar to its original size when we move our mouse away from the bar.

We just set everything into its original size like we did when we load the graph.

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

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

We set the height of the bar to by setting the height attribute in the last attr call.

Conclusion

We can convert arrays to TSVs and create a bar chart with D3.

Categories
Vue and D3

Adding Graphics to a Vue App with D3 — CSV and TSV

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.

csvParseRows

We can use the csvParseRows method to parse CSV strings into rows.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";
const string = `2011,10\n2012,20\n2013,30\n`;
export default {
  name: "App",
  mounted() {
    const data = d3.csvParseRows(string, function ([year, population]) {
      return {
        year: new Date(+year, 0, 1),
        population,
      };
    });
    console.log(data);
  },
};
</script>

We parse the CSV rows into an array with the csvParseRows method into a nested array.

The year and population are destructured from the parameter and we return them after parsing them.

csvFormat

We can use the csvFormat method to format the CSV rows and columns.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

const data = [
  { year: 2011, population: 10 },
  { year: 2012, population: 20 },
  { year: 2013, population: 30 },
];

export default {
  name: "App",
  mounted() {
    const string = d3.csvFormat(data, ["year", "population"]);
    console.log(string);
  },
};
</script>

We pass in an array of objects into the csvFormat method.

The 2nd argument is the column headings.

And then we get back:

year,population
2011,10
2012,20
2013,30

as the value of string .

tsvParse

We can use the tsvParse method to parse tab-separated strings.

For instance, we can write:

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
const string = `yeartpopulation\n2011\t10\n2012\t20\n2013\t30\n`;

export default {
  name: "App",
  mounted() {
    const data = d3.tsvParse(string, function ({ year, population }) {
      return {
        year: new Date(+year, 0, 1),
        population,
      };
    });
    console.log(data);
  },
};
</script>

We have a string that has the columns separated by tabs.

And rows separated by a new line.

Then we call tsvParse to parse the string.

And we get the year and population in the parameter.

tsvParseRows

We can use the tsvParseRows to parse the rows in a tabbed separated string.

For example, we can write:

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
const string = `2011\t10\n2012\t20\n2013\t30\n`;

export default {
  name: "App",
  mounted() {
    const data = d3.tsvParseRows(string, function ([year, population]) {
      return {
        year: new Date(+year, 0, 1),
        population,
      };
    });
    console.log(data);
  },
};
</script>

We parse the string and destructure the year and population from the parameter.

tsvFormat

We can call the tsvFormat method to convert an array of data to a tabbed separated string.

For instance, we can write:

<template>
  <div id="app"></div>
</template>

<script>
import * as d3 from "d3";
const data = [
  { year: 2011, population: 10 },
  { year: 2012, population: 20 },
  { year: 2013, population: 30 },
];
export default {
  name: "App",
  mounted() {
    const string = d3.tsvFormat(data, ["year", "population"]);
    console.log(string);
  },
};
</script>

We pass in the array in the first argument and an array of column names in the 2nd argument.

Then string is:

year population
2011 10
2012 20
2013 30

Conclusion

We can parse and create CSV and TSV files with D3 in a Vue app.

Categories
Vue and D3

Adding Graphics to a Vue App with D3 — Drag and Drop, Zoom, and CSV

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.

Drag and Drop

We can add drag and drop to our Vue app with D3 easily.

For example, we can write:

<template>
  <div id="app">
    <svg>
      <g>
        <rect x="40" y="10" width="50" height="50" fill="teal"></rect>
      </g>
    </svg>
  </div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      d3.select("g")
        .datum({
          x: 0,
          y: 0,
        })
        .call(
          d3.drag().on("drag", function (d) {
            d3.select(this).attr("transform", `translate(${d.x} , ${d.y})`);
          })
        );
    });
  },
};
</script>

We have an SVG with a rectangle inside.

In the nextTick callback, we call d3.select to get the g element.

And then we call datum to set the x and y coordinates of the top left corner.

And then we call the call method by passing in the d3.drag().on method into the call method.

The callback gets the element we’re dragging with this .

And then we set the transform attribute to the drag position.

Zooming

We can add a zoom feature to shapes.

With it, we can use the mouse wheel to zoom in and out of an SVG.

For example, we can write:

<template>
  <div id="app">
    <div id="zoom"></div>
  </div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      const svg = d3
        .select("#zoom")
        .append("svg")
        .attr("width", 460)
        .attr("height", 460)
        .call(
          d3.zoom().on("zoom", function (d) {
            svg.attr("transform", d.transform);
          })
        )
        .append("g");

      svg
        .append("circle")
        .attr("cx", 100)
        .attr("cy", 100)
        .attr("r", 40)
        .style("fill", "#68b2a1");
    });
  },
};
</script>

We have a div with ID zoom .

In the nextTick callback, we get the div and then add the svg element into it.

Then we call the call method with the d3.zoom method so that we can watch for zoom.

The d.transform has the string to change the size according to how much we zoom in or out.

Then we add the circle that we can zoom in and out.

cx and cy has the x and y coordinates of the center.

r has the radius.

style has the fill style.

Read Comma-Separated Values

We can read data from formatted data directly.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";
const string = `year,population\n2011,10\n2012,20\n2013,30\n`;
export default {
  name: "App",
  mounted() {
    const data = d3.csvParse(string, function (d) {
      return {
        year: new Date(+d.year, 0, 1),
        population: d.population,
      };
    });
    console.log(data);
  },
};
</script>

to parse a CSV string with d3.csvParse .

The callback lets us return the transformed data after reading it.

d has the entry read and we return what we want as the new value of the entry.

Conclusion

We can add drag and drop, zooming, and read CSV strings with D3 in our Vue app.

Categories
Vue and D3

Adding Graphics to a Vue App with D3 — Colors and Transitions

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.

Colors

We can create color objects with the d3.color method.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    const color = d3.color("green");
    console.log(color);
  },
};
</script>

to call d3.color .

Then color is:

{r: 0, g: 128, b: 0, opacity: 1}

We get the r, g, and b values and the opacity.

We get the same thing with the color.rgb() method:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    const color = d3.color("green");
    console.log(color.rgb());
  },
};
</script>

The color object also has the toString method:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    const color = d3.color("green");
    console.log(color.toString());
  },
};
</script>

We see:

rgb(0, 128, 0)

logged.

D3 also comes with the d3.rgb method to create an object with the RGB values:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    console.log(d3.rgb("yellow"));
    console.log(d3.rgb(200, 100, 0));
  },
};
</script>

And we get:

{r: 255, g: 255, b: 0, opacity: 1}
{r: 200, g: 100, b: 0, opacity: 1}

The d3.hsl method creates a new HSL color:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    const hsl = d3.hsl("blue");
    console.log((hsl.h += 100));
    console.log((hsl.opacity = 0.5));
  },
};
</script>

d3.lab creates a new lab color:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    const lab = d3.lab("blue");
    console.log(lab);
  },
};
</script>

Then we get:

{l: 29.567572863553245, a: 68.29865326565671, b: -112.02942991288025, opacity: 1}

logged.

The d3.hcl method creates a new HCL color.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    const hcl = d3.hcl("blue");
    console.log(hcl);
  },
};
</script>

d3.cubehelix creates a new Cubehelix color:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";

export default {
  name: "App",
  mounted() {
    const cubehelix = d3.cubehelix("blue");
    console.log(cubehelix);
  },
};
</script>

And we get:

{h: 236.94217167732103, s: 4.614386868039719, l: 0.10999954957200976, opacity: 1}

Transitions

We can add transitions easily with D3 into our Vue app.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      d3.selectAll("body")
        .transition()
        .style("background-color", "yellow")
        .transition()
        .delay(5000)
        .style("background-color", "blue")
        .delay(2000)
        .remove();
    });
  },
};
</script>

We call the transition method to create our transition.

Then we specify the styles to apply with the style method.

And we call delay to set the delay before the next transition is applied.

Conclusion

We can add colors and transitions with D3 into our Vue app.