D3 nested objects should be different colors - csv

I'm creating a line graph in which the area under the line is colored based on a variable rank that is not taken into account with plotting with date and close. I'm using d3.nest() to chunk data based on the rank and then looping through dataGroup and plotting each entry with a random color.
Based on this thought process, each of the dataGroups should be a different color, but when it plots, I only get one random color for the whole plot.
Here's a Plunker
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 12px Arial;
}
text.shadow {
stroke: #fff;
stroke-width: 2.5px;
opacity: 0.9;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.grid .tick {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.area {
stroke-width: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 30, right: 20, bottom: 35, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
var color = d3.scale.category20();
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.close); });
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
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 + ")");
// function for the x grid lines
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5)
}
// function for the y grid lines
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
}
// Get the data
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
var dataGroup = d3.nest()
.key(function(d) {
return d.rank;
})
.entries(data);
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
dataGroup.forEach(function(d, i){
svg.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
});
svg.selectAll(".area")
.style("fill",function() {
return "hsl(" + Math.random() * 360 + ",100%,50%)";
})
// Draw the x Grid lines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
// Draw the y Grid lines
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
// Add the valueline path.
svg.append("path")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Add the text label for the X axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height+margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Date");
// Add the white background to the y axis label for legibility
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("x", margin.top - (height / 2))
.attr("dy", ".71em")
.style("text-anchor", "end")
.attr("class", "shadow")
.text("Price ($)");
// Add the text label for the Y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("x", margin.top - (height / 2))
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
// Add the title
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Price vs Date Graph");
});
</script>
</body>

You bind the complete dataset (data) to each area element. As a result, all areas are on top of each other and the fill results in just showing the top most area path.
Instead in your dataGroup.forEach() you need to bind just the data corresponding to the rank:
...svg.append("path").datum(d.values)....

Related

D3 svg chart can't display in IE

I'm building a website which contains d3 svg to display the bar chart. It can display in Chrome, Firefox, Edge, Safari, but it is not working in IE. I have tried to use canvas method, but it is not working. Then I tried set viewbox for svg, but it is not working as well. Could anyone help me solve this problem?
Here's my d3.js and html code
function homeStats() {
var jsonobj = document.getElementById('stats-data').value;
var data = JSON.parse(jsonobj);
var parentDiv = document.getElementById("home-stats");
function drawbar() {
var margin = { top: 40, right: 20, bottom: 100, left: 40 };
var width = parentDiv.clientWidth - margin.left - margin.right;
var height = parentDiv.clientHeight - margin.top - margin.bottom;
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function (d) {
return "<span style='color:white'>" + d.value + "</span>";
})
d3.selectAll('#home-stats-svg').remove()
var svg = d3.select("#home-stats").append("svg").attr("id", "home-stats-svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.call(tip);
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .65);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#f79944", "#20b5e1"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
var columnNames = d3.keys(data[0]).filter(function (key) { return key !== "Year"; });
data.forEach(function (d) {
d.subGroups = columnNames.map(function (name) { return { name: name, value: +d[name] }; });
});
x0.domain(data.map(function (d) { return d.Year; }));
x1.domain(columnNames).rangeRoundBands([0, 30]);
y.domain([0, d3.max(data, function (d) { return d3.max(d.subGroups, function (d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end");
const rx = 5;
const ry = 5;
var Year = svg.selectAll(".Year")
.data(data)
.enter().append("g")
.attr("class", "Year")
.attr("transform", function (d) { return "translate(" + x0(d.Year) + ",0)"; });
Year.selectAll("rect")
.data(function (d) { return d.subGroups; })
.enter().append("path")
.style("fill", function (d) { return color(d.name); })
.attr("d", item => `
M${x1(item.name)},${y(item.value) + ry}
a${rx},${ry} 0 0 1 ${rx},${-ry}
h${10 - 2 * rx}
a${rx},${ry} 0 0 1 ${rx},${ry}
v${height - y(item.value) - ry}
h${-(10)}Z
`)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
var legend = svg.selectAll(".legend")
.data(columnNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 5)
.attr("width", "1vw")
.attr("height", "2vh")
.style("fill", color);
legend.append("text")
.attr("x", width - 7)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function (d) { return d; });
}
drawbar();
}
Html
<div id="home-stats" style="height:50vh; width:45vw">
<input type="hidden" id="stats-data" value=#ViewBag.deaths_json />
<svg id="home-stats-svg" viewBox="0 0 100 100"></svg>
</div>
Since the arrow function expression doesn't support IE browser, we could use babeljs.io to convert this function to ES5 format.

Using Ajax for real time graphical display

I am doing a sample project using d3js sample from bl.ocks.org to plot graph. There is a csv file which is continuously updated. My task is to read it every second and update the plot. I tried to look up ajax example to add into the d3. However bl.ocks.org did not have what I needed. Can anyone please let me know a good ajax example which I can integrate with my application.
--> next task is to get csv off and have a restful service to read data. Then it is to be parsed and graph is to be updated periodically.
Thanks in advance!
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
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 + ")");
// Get the data
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>

The values on x-axis are descending values on grouped bar chart using d3.js

I have transformed the vertical grouped bar chart from horizontal grouped bar chart. I have taken the code from the site https://bl.ocks.org/mbostock/3887051. The problem is when I have transformed horizontal to vertical axis the values on x-axis are not ascending but they are descending i.e., the values are 10M, 8M, 6M, 4M etc....I am not sure where I have made a mistake.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 50, left: 140},
width = 800 - margin.left - margin.right,
height = 900 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0],.1);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(y)
.orient("top").ticks(5);
var yAxis = d3.svg.axis()
.scale(x0)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("height", width + margin.left + margin.right)
.attr("width", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("data.csv", function(error, data) {
if (error) throw error;
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "State"; });
data.forEach(function(d) {
d.ages = ageNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.State; }));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.ages, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0,0)")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "translate(0," + height + ")")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Population");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) { return "translate(0," + x0(d.State) + ")"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("height", x1.rangeBand())
.attr("y", function(d) { return x1(d.name); })
//.attr("x", function(d) { return y(d.value); })
.attr("width", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 10)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 14)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
</script>
You y-scale which is used on your x-axis is defined as:
var y = d3.scale.linear()
.range([height, 0] , 0.1);
This runs it in reverse and should be:
var y = d3.scale.linear()
.range([0, height] , 0.1);

Why is my d3.tool tip not working for the two of the lines?

The below is the codes that will be used to create the line charts. But the problem I am facing is that my d3.tool tip for the lines are not working accordingly. Also, I would like to be able to shorten the y-axis so that the lines will look to have a bigger gap in between.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: black ;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
h3 {
margin-left:220px;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
</style>
<div>
<h3>Life Expectancy History</h3>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var margin = { top: 30, right: 40, bottom: 30, left: 50 },
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Male:</strong> <span style='color:white'>" + d.male + "%" + "</span></br><strong>World Rank:</strong> <span style='color:white'>" + d.rankmale;
});
var tip1 = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Female:</strong> <span style='color:white'>" + d.female + "%" + "</span></br><strong>World Rank:</strong> <span style='color:white'>" + d.rankfemale;
});
var tip2 = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Both Gender:</strong> <span style='color:white'>" + d.both + "%" + "</span></br><strong>World Rank:</strong> <span style='color:white'>" + d.rankall;
});
var parseDate = d3.time.format("%Y").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var y1= d3.scale.linear()
.range([height, 0]);
var y2= d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(10);
var line = d3.svg.line()
.x(function (d) { return x(d.year); })
.y(function (d) { return y(d.male); });
var line2 = d3.svg.line()
.x(function (d) { return x(d.year); })
.y(function (d) { return y(d.female); });
var line3 = d3.svg.line()
.x(function (d) { return x(d.year); })
.y(function (d) { return y(d.both); });
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 + ")");
svg.call(tip).call(tip1).call(tip2);
d3.json("lifehistory.json", function (error, data) {
data.forEach(function (d)
{
d.year = parseDate(d.year.toString());
d.male = +d.male;
d.female = +d.female;
d.both = +d.both;
});
x.domain(d3.extent(data, function (d) { return d.year; }));
y.domain([0, d3.max(data, function (d) { return d.male; })]);
y1.domain([0, d3.max(data, function (d) { return d.female; })]);
y2.domain([0, d3.max(data, function (d) { return d.both; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("text") // text label for the x axis
.attr("x", 265)
.attr("y", 240)
.style("text-anchor", "middle")
.text("Years");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Life Expectancy History");
svg.selectAll('.yaxis1')
.data(data)
.enter()
.append('circle')
.attr('class', 'yaxis1')
.attr('cx', function(datum){return x(datum.year)})
.attr('cy', function(datum){return y(datum.male)})
.attr('r', 3)
.attr('fill', 'red')
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
svg.selectAll('.yaxis2')
.data(data)
.enter()
.append('circle')
.attr('class', 'yaxis2')
.attr('cx', function(datum){return x(datum.year)})
.attr('cy', function(datum){return y1(datum.female)})
.attr('r', 3)
.attr('fill', 'blue')
.on('mouseover', tip1.show)
.on('mouseout', tip1.hide);
svg.selectAll('.yaxis3')
.data(data)
.enter()
.append('circle')
.attr('class', 'yaxis3')
.attr('cx', function(datum){return x(datum.year)})
.attr('cy', function(datum){return y2(datum.both)})
.attr('r', 3)
.attr('fill', 'blue')
.on('mouseover', tip2.show)
.on('mouseout', tip2.hide);
svg.append("path")
.datum(data)
.attr("class", "line")
.style("stroke", "red")
.attr("d", line(data));
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line2(data));
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line3(data));
});
</script></div>
This is the line chart that I have created. The d3.tool tip is not working as what I would like as only one the the d3.tool tip is working on one line but the others are not appearing on the other lines. I would like to show the y-axis to have a bigger gap between each of the value and in other words, it means that the gap between lines will be bigger so that people can easily analysis the graph. Is there any method for me to do it that way?
This is the JSON file that I am using.
[{"year":"1960","male":"61.7","female":"65.7","both":"63.7","rankmale":"47","rankfemale":"50","rankall":"45"},
{"year":"1970","male":"65.4","female":"70.2","both":"67.7","rankmale":"45","rankfemale":"45","rankall":"44"},
{"year":"1980","male":"68.9","female":"74.2","both":"71.5","rankmale":"33","rankfemale":"36","rankall":"29"},
{"year":"1990","male":"71.9","female":"76.9","both":"74.3","rankmale":"28","rankfemale":"30","rankall":"30"},
{"year":"2000","male":"76.1","female":"80.1","both":"78.1","rankmale":"11","rankfemale":"24","rankall":"15"},
{"year":"2011","male":"80.1","female":"84.6","both":"82.3","rankmale":"6","rankfemale":"8","rankall":"5"}]
The problem with your code is from using different y scales for tooltips. You used the same y scale for the lines so they appear fine. But when you use different y scales for the circles, they will be plotted differently. So instead of having
var y = d3.scale.linear()
.range([height, 0]);
var y1= d3.scale.linear()
.range([height, 0]);
var y2= d3.scale.linear()
.range([height, 0]);
and
y.domain([0, d3.max(data, function (d) { return d.male; })]);
y1.domain([0, d3.max(data, function (d) { return d.female; })]);
y2.domain([0, d3.max(data, function (d) { return d.both; })]);
you can just use
var y = d3.scale.linear().range([height, 0]);
and
y.domain([50, 90]);
And then just use the same y scale when you add the circles.
Notice that I also replace your domain start value from 0 to 50. This will help shortening the y scale and space out your lines.
You can see a live demo at http://jsfiddle.net/B6cUS/

Blank page using d3 mbostock

I have very new to d3 so please bear with me. The problem I am having is that I cannot get nor figure out why none of the http://bl.ocks.org/mbostock/ demos work after copying a pasting. I keep get blank or white pages. What am I missing?
I even downloaded the gist source file from https://gist.github.com/mbostock/3884955 and still it did not work.
Any ideas will be much appreciated because I also need to implement http://bost.ocks.org/mike/uberdata/ with its data files:
(1) http://bost.ocks.org/mike/uberdata/citites.csv
(2) http://bost.ocks.org/mike/uberdata/matrix.json
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.temperature); });
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 + ")");
d3.tsv("data.tsv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var cities = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, temperature: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.temperature; }); }),
d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Temperature (ºF)");
var city = svg.selectAll(".city")
.data(cities)
.enter().append("g")
.attr("class", "city");
city.append("path")
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.temperature); });
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 + ")");
d3.tsv("data.tsv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var cities = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, temperature: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.temperature; }); }),
d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Temperature (ºF)");
var city = svg.selectAll(".city")
.data(cities)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
city.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.temperature) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
});
</script>
</body>
</html>
You most likely get this message in your console:
XMLHttpRequest cannot load file:///C:/Users/Charles/Desktop/New%20folder/data.tsv. Cross origin requests are only supported for HTTP.
You need to be using a webserver in order to run this script. You might also be able to get around it within your browser settings. This is because an http request is not made by loading this file.
It is explained here how to get around this. It shouldn't take too long to set up and it will make local development much easier for you. Good luck!