Skip to content

Instantly share code, notes, and snippets.

@AdamMescher
Last active May 11, 2019 21:54
Show Gist options
  • Save AdamMescher/62f2efbbc35aa2b2c27cbd419366ea6b to your computer and use it in GitHub Desktop.
Save AdamMescher/62f2efbbc35aa2b2c27cbd419366ea6b to your computer and use it in GitHub Desktop.
Introduction to Data Visualization with d3.js v4

Introduction to Data Visualization with d3.js

Course Resources

D3 Ecosystem

API Reference

Selection & Data

<svg>
    <rect />
    <rect />
    <rect />
    <rect />
    <rect />
</svg>
<script>
    var data = [100, 250, 175, 200, 120];
    d3.selectAll('rect')
        .data(data)
        .attr('x', (d, i) => i * rectWidth)
        .attr('y', d => height - d)
        .attr('width', rectWidth)
        .attr('height', d => d)
        .attr('fill', 'blue')
        .attr('stroke', '#fff');
</script>

There are 5 <rect /> elements in the svg tag

Select all <rect /> elements that exist

d3.selectAll('rect)

Bind data to the selections

.data(data)

Loop through each rectangle selection and pass in x, y, width, and height properties

.attr('x', (d, i) => i * rectWidth)
.attr('y', d => height - d)
.attr('width', rectWidth)
.attr('height', d => d)

Enter - Append

<svg></svg>
<script>
    var rectWidth = 100;
    var height = 300;
    var data = [100, 250, 175, 200, 120];
    var svg = d3.select('svg');
    svg.selectAll('rect')
    	.data(data)
    	.enter().append('rect')
    	.attr('x', (d, i) => i * rectWidth)
    	.attr('y', d => height - d)
    	.attr('width', rectWidth)
    	.attr('height', d => d)
    	.attr('fill', 'blue')
    	.attr('stroke', '#fff');
</script>

No created <rect /> elements

<svg></svg>

What is being selected?

svg.selectAll('rect');

Answer: an empty selection

How are the bars appearing then?

.data(data)
.enter()
.append('rect')
  1. .data(data) needs 5 places to put the data
  2. .enter() creates 5 placeholders
  3. .append() creates a <rect> element for every placeholder

Scales & Axes

d3.scaleLinear()
  .domain([min, max])
  .range([min, max])

scale: mapping from data attributes (domain) to display (range)

  • date --> x-value
  • value --> y-value
  • value --> opacity
  • etc.
// D3 min & max
const min = d3.min(data, d => d[city]);
const max = d3.max(data, d => d[city]);

// D3 extent
const extent = d3.extent(data, d => d[city]);

// yScale creation example with extent
const yScale = d3.scaleLinear().domain(extent).range([height, 0])

Frequently used scales

  • Continuous
    • d3.scaleLinear()
    • d3.scaleLog()
    • d3.scaleTime()
  • Ordinal
    • d3.scaleBand()
const yAxis = d3.axisLeft().scale(yScale) // pass in a scale
d3.select('svg')
  .append('g') // Create a group element we can translate so that the axis will be visible in SVG
  .attr('transform', 'translate(40, 20)') // selection.call(yAxis) is the same as yAxis(selection) and an axis will be created within the selection
  .call(yAxis)
const city = "New York";
const width = 1000;
const height = 500;
const margin = { top: 20, bottom: 20, left: 20, right: 20 };

// dataset of city temperatures across time

// dataset of city temperatures
const data = d3.tsv("./data.tsv").then(data => {
  //clean the data
  data.forEach(d => {
    d.date = d3.timeParse("%Y%m%d")(d.date);
    d.date = new Date(d.date); // x
    d[city] = ++d[city]; // y
  });

  // Create Scales
  const xExtent = d3.extent(data, d => d.date);
  const xScale = d3
    .scaleTime()
    .domain(xExtent)
    .range([margin.left, width - margin.right]);
  const yExtent = d3.extent(data, d => d[city]);
  const yMax = d3.max(data, d => d[city]);
  const yScale = d3
    .scaleLinear()
    .domain([0, yMax])
    .range([height - margin.bottom, margin.top]);
  // Create the rectangles
  const svg = d3.select("svg");
  const rect = svg
    .selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x", d => xScale(d.date))
    .attr("y", d => yScale(d[city]))
    .attr("width", 2)
    .attr("height", d => height - yScale(d[city]))
    .attr("fill", "blue")
    .attr("stroke", "white");

  // Create Axes
  const xAxis = d3
    .axisBottom()
    .scale(xScale)
    .tickFormat(d3.timeFormat("%b %Y"));
  const yAxis = d3.axisLeft().scale(yScale);

  svg
    .append("g")
    .attr("transform", `translate(0 ${height})`)
    .call(xAxis);
  svg
    .append("g")
    .attr("transform", `translate(${margin.left}, ${margin.bottom})`)
    .call(yAxis);
});

Shapes

d3-shape calculates the path attribute so we don't have to

d3.line()

Input: array of objects

Output: path that connects each point (object) with lines or curves

const data = [
 {date: new Date(2007, 3, 24), value: 93.24},
 {date: new Date(2007, 3, 25), value: 95.35},
 {date: new Date(2007, 3, 26), value: 93.24},
 {date: new Date(2007, 3, 27), value: 93.24},
 {date: new Date(2007, 3, 28), value: 93.24},
 {date: new Date(2007, 3, 29), value: 93.24},
 ...
];

const line = d3.line()
 .x(d => xScale(d.date))
 .y(d => yScale(d.value))
 
 d3.select('svg')
  .append('path')
  .attr('d', line(data))

Pie Chart

var colors = d3.scaleOrdinal(d3.schemeCategory10);
var data = [1, 1, 2, 3, 5, 8, 13, 21];
var pies = d3.pie()(data);
var arc = d3.arc()
    .innerRadius(0)
    .outerRadius(150)
    .startAngle(d => d.startAngle)
    .endAngle(d => d.endAngle);

var svg = d3.select('svg')
  	.append('g')
  	.attr('transform', 'translate(200,200)');
svg.selectAll('path')
  	.data(pies).enter().append('path')
  	.attr('d', arc)
  	.attr('fill', (d, i) => colors(d.value))
  	.attr('stroke', '#fff');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment