Skip to content

Instantly share code, notes, and snippets.

@gordlea
Last active Oct 12, 2020
Embed
What would you like to do?
D3 v5 Line Chart
license: mit

D3 v4 Line Chart Example

This is a example for basic line chart using D3. We are using the newest version of D3, version 4. As for all visualizations, we can break down this work into a checklist.

Line Chart Checklist
  1. Add an SVG to draw our line chart on
  2. Use the D3 standard margin convetion
  3. Create an x axis
  4. Create a y axis
  5. Create an x scale
  6. Create a y scale
  7. Create a line generator
  8. Create a random dataset
  9. Create a path object for the line
  10. Bind the data to the path object
  11. Call the line generator on the data-bound path object
  12. Add circles to show each datapoint
  13. Add some basic styling to the chart so its easier on the eyes

Read through the code below to see where each part of the checklist is completed.

forked from pstuffa's block: D3 v4 Line Chart

<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
/* 13. Basic Styling with CSS */
/* Style the lines by removing the fill and applying a stroke */
.line {
fill: none;
stroke: #ffab00;
stroke-width: 3;
}
.overlay {
fill: none;
pointer-events: all;
}
/* Style the dots by assigning a fill and stroke */
.dot {
fill: #ffab00;
stroke: #fff;
}
.focus circle {
fill: none;
stroke: steelblue;
}
</style>
<!-- Body tag is where we will append our SVG and SVG objects-->
<body>
</body>
<!-- Load in the d3 library -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
// 2. Use the margin convention practice
var margin = {top: 50, right: 50, bottom: 50, left: 50}
, width = window.innerWidth - margin.left - margin.right // Use the window's width
, height = window.innerHeight - margin.top - margin.bottom; // Use the window's height
// The number of datapoints
var n = 21;
// 5. X scale will use the index of our data
var xScale = d3.scaleLinear()
.domain([0, n-1]) // input
.range([0, width]); // output
// 6. Y scale will use the randomly generate number
var yScale = d3.scaleLinear()
.domain([0, 1]) // input
.range([height, 0]); // output
// 7. d3's line generator
var line = d3.line()
.x(function(d, i) { return xScale(i); }) // set the x values for the line generator
.y(function(d) { return yScale(d.y); }) // set the y values for the line generator
.curve(d3.curveMonotoneX) // apply smoothing to the line
// 8. An array of objects of length N. Each object has key -> value pair, the key being "y" and the value is a random number
var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)() } })
// 1. Add the SVG to the page and employ #2
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// 3. Call the x axis in a group tag
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom
// 4. Call the y axis in a group tag
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale)); // Create an axis component with d3.axisLeft
// 9. Append the path, bind the data, and call the line generator
svg.append("path")
.datum(dataset) // 10. Binds data to the line
.attr("class", "line") // Assign a class for styling
.attr("d", line); // 11. Calls the line generator
// 12. Appends a circle for each datapoint
svg.selectAll(".dot")
.data(dataset)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d, i) { return xScale(i) })
.attr("cy", function(d) { return yScale(d.y) })
.attr("r", 5)
.on("mouseover", function(a, b, c) {
console.log(a)
this.attr('class', 'focus')
})
.on("mouseout", function() { })
// .on("mousemove", mousemove);
// var focus = svg.append("g")
// .attr("class", "focus")
// .style("display", "none");
// focus.append("circle")
// .attr("r", 4.5);
// focus.append("text")
// .attr("x", 9)
// .attr("dy", ".35em");
// svg.append("rect")
// .attr("class", "overlay")
// .attr("width", width)
// .attr("height", height)
// .on("mouseover", function() { focus.style("display", null); })
// .on("mouseout", function() { focus.style("display", "none"); })
// .on("mousemove", mousemove);
// function mousemove() {
// var x0 = x.invert(d3.mouse(this)[0]),
// i = bisectDate(data, x0, 1),
// d0 = data[i - 1],
// d1 = data[i],
// d = x0 - d0.date > d1.date - x0 ? d1 : d0;
// focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
// focus.select("text").text(d);
// }
</script>
@MorgusLethe
Copy link

MorgusLethe commented Jan 29, 2019

Hi, thanks for this example, it's the best I could find. If you want to make it even better you should remove all references to v4, it was confusing to me. And perhaps include an example on how to get data through a promise. :)

@dbardele
Copy link

dbardele commented Jun 10, 2019

Hi...thank you for a great tutorial. I'm very new to programming and am following along trying to build a custom visual in Power BI. Everything works until ".attr("d", line); // 11. Calls the line generator" at which point my linting package shows an error underneath 'line' and states "Argument of type '{ "y": number; }[]' is not assignable to parameter of type '[number, number][]'."

The pbiviz package I'm using has me writing in Typescript, which then compiles to JS, so I'm wondering if that might be the problem. Any quick suggestions or is this a deeper issue that cannot be described in a quick answer.

Thanks again!

@dbardele
Copy link

dbardele commented Jun 10, 2019

Actually just found an answer that got rid of the error...I added before line so it's now .attr("d", line).

@wbtittle
Copy link

wbtittle commented Nov 12, 2019

Thank you. Another step in understanding d3 happened looking at your code for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment