In this activity, you are going to create a line-chart using D3.
-
Clone this repository to your local machine. E.g., in your terminal / command prompt
CDto where you want this the folder for this activity to be. Then rungit clone <YOUR_REPO_URL> -
CDor open a terminal / command prompt window into the cloned folder. -
Start a simple python webserver. E.g.,
python -m http.server,python3 -m http.server, orpy -m http.server. If you are using python 2 you will need to usepython -m SimpleHTTPServerinstead, but please switch to python 3. -
Wait for the output:
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/). -
Now open your web browser (Firefox or Chrome) and navigate to the URL: http://localhost:8000
- Open
index.html. Just below this HTML comment:
<!-- Load the d3.js library( version 4 minified) -->add this line to load the D3 javascript code (note the version number v5):
<script src="https://d3js.org/d3.v5.min.js"></script>- You also have a file
linechart.js. We want to load this javascript code as well. Inindex.html, just below this HTML comment:
<!-- Load the line.js file -->add this line:
<script src="linechart.js"></script>-
Open the file
data.csvwith a text editor and see what is inside. It is comma-separated. You will see a header row followed by several data rows with a date in the MM/D/YYYY format, e.g.,10/6/2018, and a price, e.g.,33.9. Note that you can open CSV files with Excel or other clever tools but they can make mistakes with parsing the data into their own formats. -
In
linechart.jswe are going to load this CSV file. Add this line to use D3 to load the file and then pass it to a callback function insidethen:
d3.csv("data.csv").then(function(data) {
console.log(data);
});Once the data is loaded from the CSV file it is stored in the data variable. Your entire code for creating the line chart will go here inside the then function which happens after the data is asynchronously loaded.
-
In your browser (Firefox or Chrome), open the browser developer tools by pressing
CTRL+SHIFT+I(Windows/Linux) orCmd+Opt+Iand select theConsoleview. Here is where you see any output fromconsole.logor any otherconsolemessages such as errors. The browser developer tools and theConsoleview are very useful for debugging. Here you can see the that your code logged an array of 50 objects to the console. If you see this, your data has loaded! -
However, if you interact with the object by clicking the triangles you will notice that the date and price are enclosed in double-quotes (") and are thus strings. This is not the format that we want our data to be in for us to interpret it properly. Hence we need to parse the data into the formats we want. To learn about date parsing visit this site: http://learnjsdata.com/time.html
-
To parse our date data to the format we want, we are going to define a variable called
parseDatebefore the step where we loaded our data:
var parseDate = d3.timeParse('%m/%d/%Y');Because our dates use forward slashes / as delimiters, our format string includes them. If our date was instead 02-02-2009, we would parse it using %m-%d-%Y.
- Now we can use
parseDateto parse our dates and we can use the built-in unary+operator to parse our numbers. Modify your call tod3.csvlike so, passing an anonymous row conversion function that does the parsing:
d3.csv('data.csv', function(d) {
return {
date: parseDate(d.date),
price: +d.price
};
}).then(function(data) {
console.log(data);
});- Instead of writing everything inside the
thenfunction ofd3.csv, lets create a new function that creates our line chart given some data:
function lineChart(data){
console.log(data);
}and replace the anonymous function inside then with our new function, like so:
d3.csv("data.csv", function(d) {
return {
date: parseDate(d.date),
price: +d.price
};
}).then(lineChart);- In order to have the proper scales for your line chart, you need to know the max and min of your data. This is easy to do manually for static, small datasets but in general this is cumbersome, error-prone, and can be done instead algorithmically. Add these lines after the
console.loginlineChart:
var maxDate = d3.max(data, function(d){return d.date; });
var minDate = d3.min(data, function(d){return d.date; });
var maxPrice = d3.max(data, function(d){return d.price;});
console.log(maxDate, minDate, maxPrice);-
In your browser
Consoleview check whether those variables have been set. Theconsole.logis for your own assurance that your variable is indeed returning the value that you are asking for. You can remove this later. -
Check to see if you can see those variables in the browser debugger instead (
Debuggerin Firefox,Sourcesin Chrome). Openlinechart.jsin the debugger. Click on the line number beside the closing parenthesis}of thelineChartfunction to create a breakpoint. Refresh the browser page. You should see the variable values at this point inside theScopesview (Firefox) orScopeview (Chrome). Chrome also shows the values in-line. You can click theResumebutton (right-facing triangle, e.g. a play button) to resume execution. Remove the breakpoint by clicking the line number again. -
Define the
widthandheightfor thesvgyou will use:
var width = 600;
var height = 500;
var margin = {
top: 30,
bottom: 30,
left: 30,
right: 30
};For each of the following steps, you can save your file and reload the page in your web browser to see what has changed.
- Now, create your
svginside thebodyin the DOM by using D3 toselectthebodyandappendthesvg, giving it awidth,height, andbackgroundcolor:
var svg = d3.select('body')
.append('svg')
.attr('width' , width)
.attr('height', height)
.style('background', '#efefef');- Then create an SVG group
gfor all the elements that will make up our line chart.
var chartGroup = svg
.append('g')
.attr('transform','translate(' + margin.left +',' + margin.top + ')');- Now we will define two scales for the x (
d3.scaleTime) and y (d3.scaleLinear) axes and set theirdomain(in the data) andrange(on the screen):
var xScale = d3.scaleTime()
.domain([minDate, maxDate])
.range([0, width]);var yScale = d3.scaleLinear()
.domain([0, maxPrice])
.range([height - margin.bottom - margin.top, 0]);- Then we can draw our axes using these scales:
var xAxis = d3.axisBottom(xScale);
chartGroup.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + (height - margin.bottom - margin.top) + ')')
.call(xAxis);var yAxis = d3.axisLeft(yScale);
chartGroup.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(0, 0)')
.call(yAxis);- Finally, we will draw the line:
var line = d3.line()
.x(function(d){return xScale(d.date);})
.y(function(d){return yScale(d.price);})chartGroup.append('path')
.attr('d', line(data));-
At this point, if you save and reload in your browser you will see that your line looks rather bizarre. This is because by default the line is filled with black and it is trying to close the polygon. Let's add CSS to fix this.
-
First, add a CSS class to the lines we want to style (adding to the original code):
chartGroup.append('path')
.attr('d', line(data))
.attr('class', 'dataLine');Then, in linechart.css add these lines:
.dataLine{
stroke: #0000BB;
stroke-width: 1px;
fill: none;
}Congratulations! You should now have a line chart. What else can you do with this by playing with JavaScript, HTML, and CSS?