Last active
December 1, 2015 12:55
-
-
Save i-tu/7e63593090bf13bd41d4 to your computer and use it in GitHub Desktop.
Ranking line chart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
lineChart("ranking.csv" | |
, ["#0072C5", "#FFA824", '#E21831', '#3E0605'] | |
, "#example"); | |
function lineChart(filePath, colors, selector) { | |
var x_column = "Year"; | |
var constructedData; | |
d3.dsv(";", "text/plain")(filePath, function(error, data) { | |
data.map(function(d){ | |
d[x_column] = +d[x_column]; | |
}); | |
var name_columns = d3.keys(data[0]) | |
.filter(function(key) { | |
return key !== x_column; | |
}); | |
color = d3.scale.ordinal() | |
.domain(name_columns) | |
.range(colors); | |
constructedData = name_columns.map(function(name_column) { | |
return { | |
name: name_column, | |
values: data.map(function(d) { | |
if (d[name_column] === "") | |
return { x: +d[x_column] }; | |
else | |
return { x: +d[x_column], y: +d[name_column] }; | |
}) | |
} | |
}); | |
drawSeries(constructedData); | |
}) | |
function drawSeries() { | |
if (constructedData.length === 0) | |
return; | |
var chart = d3.select(selector); | |
var boundingWidth = chart.node().getBoundingClientRect().width; | |
var margin = { top: 20, right:100, bottom: 30, left: 50 }; | |
var width = boundingWidth - margin.left - margin.right, | |
height = (boundingWidth/2) - margin.top - margin.bottom; | |
var svg = d3.select(selector) | |
.append("div") | |
.classed("svg-container", true) | |
.append("svg") | |
.attr("preserveAspectRatio", "xMinYMin meet") | |
.attr("viewBox", "0 0 " | |
+ (width + margin.left + margin.right) | |
+ " " | |
+ (height + margin.top + margin.bottom) | |
) | |
.classed("svg-content-responsive", true) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var i_scale, y_scale, colors; | |
var range = { y_min: 9999, y_max: -9999, x_min: 9999, x_max: -9999 }; | |
constructedData.map(function(serie){ | |
serie.values.map(function(d, i) { | |
if (range.y_min > d.y) range.y_min = d.y; | |
if (range.y_max < d.y) range.y_max = d.y; | |
if (range.x_min > d.x) range.x_min = d.x; | |
if (range.x_max < d.x) range.x_max = d.x; | |
d.i = i; | |
}); | |
}); | |
var transitionTime = 2000; | |
i_scale = d3.scale.linear() | |
.domain([0, constructedData[0].values.length - 1]) | |
.range([0, width]); | |
x_scale = d3.scale.linear() | |
.domain([range.x_min, range.x_max]) | |
.range([0, width]); | |
y_scale = d3.scale.linear() | |
.domain([range.y_min, range.y_max]) | |
.range([0, height]); | |
var xAxis = d3.svg.axis() | |
.scale(x_scale) | |
.orient("bottom") | |
.tickFormat( function(d) { | |
return d; | |
}) | |
.innerTickSize(-5) | |
.outerTickSize(1) | |
.tickPadding(10); | |
var yAxis = d3.svg.axis() | |
.scale(y_scale) | |
.ticks(8) | |
.orient("left") | |
.tickFormat( function(d) { | |
return d; | |
}) | |
.innerTickSize(-width) | |
.outerTickSize(1) | |
.tickPadding(10); | |
var lineFunction = d3.svg.line() | |
.x(function(d) { | |
return i_scale(d.i); | |
}) | |
.defined(function(d){ | |
return 'y' in d; | |
}) | |
.y(function(d) { | |
return y_scale(d.y); | |
}); | |
var chart = svg.selectAll(".dataset") | |
.data(constructedData) | |
.enter()//.append("g") | |
svg.append("g") | |
.style("font-family", "Open Sans") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.attr("fill", "#000") | |
.call(xAxis) | |
svg.append("g") | |
.style("font-family", "Open Sans") | |
.attr("class", "y axis") | |
.attr("transform", "translate(" + 0 + ",0)") | |
.attr("fill", "#000") | |
.call(yAxis) | |
chart.append('path') | |
.attr('fill', 'none') | |
.attr('stroke', function(d){ | |
return color(d.name); | |
}) | |
.attr('stroke-width', 3) | |
.data(constructedData) | |
.transition() | |
.duration(transitionTime) | |
.attrTween('d', function(d) { | |
return getSmoothInterpolationFromPoint(d.values)(d); | |
}) | |
var point = chart.append("g") | |
.attr("class", "line-point"); | |
point.selectAll('circle') | |
.data(function(d){ return d.values.map(function(e) { | |
e["name"] = d.name; | |
return e; | |
}) | |
.filter(function(e) { | |
return "y" in e; | |
}) | |
}) | |
.enter().append('circle') | |
.attr("cx", function(d) { return i_scale(d.i) }) | |
.attr("cy", function(d) { return y_scale(d.y) }) | |
.attr("fill-opacity", 0) | |
.style("fill", function(d) { return color(d.name); }) | |
.attr("r", 3) | |
.transition() | |
.duration(transitionTime) | |
.attr("fill-opacity", 1) | |
var legend = chart.append("g") | |
.attr("class", "legend") | |
var legend_height = 20; | |
var legend_width = 100; | |
var legend_padding = 10; | |
legend.datum(function(d) { | |
console.log(d); | |
return { | |
name: d.name, | |
y: d.values[d.values.length - 1].y | |
}; | |
}) | |
var fixTextY = { | |
"Shanghai": -5, | |
"Taiwan": 5 | |
}; | |
legend.append('text') | |
.text(function(d) { | |
return d.name; | |
}) | |
.attr("text-anchor", "left") | |
.attr("alignment-baseline", "middle") | |
.style("font-family", "Open Sans") | |
.style("font-weight", "Bold") | |
.attr("x", width + legend_padding ) | |
.attr("y", function(d) { | |
var y = y_scale(d.y); | |
if(d.name in fixTextY) | |
y += fixTextY[d.name]; | |
return y; | |
}) | |
.attr("height", legend_height) | |
.style("fill", function(d){ return color(d.name); }) | |
.style("fill-opacity", 0) | |
.transition() | |
.duration(transitionTime) | |
.style("fill-opacity", 1); | |
function getSmoothInterpolationFromPoint(data) { | |
return function(d, i, a) { | |
var interpolate = d3.scale.linear() | |
.domain([0, 1]) | |
.range([0, data.length]); | |
return function(t) { | |
var flooredX = Math.floor(interpolate(t)); | |
var weight = interpolate(t) - flooredX; | |
var interpolatedLine = data.slice(0, flooredX) | |
.filter(function(d) { | |
return 'y' in d; | |
}); | |
var weightedLineAverage = 0; | |
if (flooredX < data.length) | |
weightedLineAverage += data[flooredX].y * weight; | |
if (flooredX > 0) | |
weightedLineAverage += data[flooredX - 1].y * (1 - weight); | |
if (weightedLineAverage !== null && !isNaN(weightedLineAverage)) { | |
interpolatedLine.push({ | |
"i": interpolate(t) - 1, | |
"y": weightedLineAverage | |
}); | |
} | |
// An empty string means no path in SVG | |
if (interpolatedLine.length === 0) | |
return ""; | |
return lineFunction(interpolatedLine); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<meta charset="utf-8"> | |
<html> | |
<head> | |
<link rel="stylesheet" type="text/css" href="style.css"> | |
</head> | |
<body> | |
<div style="width:100%;height:100px;border-style:dotted;border-color:#CCC;margin-bottom:25px;"> | |
</div> | |
<div style="width: 100%;"> | |
<div style="width: 60%;margin: 0px auto;border-style:dotted;border-color:#CCC;min-width=180px;"> | |
<div id="example"></div> | |
</div> | |
</div> | |
<div style="width:100%;height:100px;border-style:dotted;border-color:#CCC;margin-top:25px;"></div> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="app.js"></script> | |
</body> | |
</html> |
We can make this file beautiful and searchable if this error is corrected: No commas found in this CSV file in line 0.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Year;Shanghai;QS;Times;Taiwan | |
2003;74;;; | |
2004;72;129;; | |
2005;76;62;; | |
2006;74;116;; | |
2007;73;100;;52 | |
2008;68;91;;50 | |
2009;72;108;;48 | |
2010;72;75;102;47 | |
2011;74;89;91;66 | |
2012;73;78;109;56 | |
2013;76;69;100;64 | |
2014;73;67;103;68 | |
2015;67;96;76;69 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.tick > line{ | |
stroke: #ddd; | |
} | |
.svg-container { | |
display: inline-block; | |
position: relative; | |
width: 100%; | |
padding-bottom: 100%; /* aspect ratio */ | |
vertical-align: top; | |
overflow: hidden; | |
} | |
.svg-content-responsive { | |
display: inline-block; | |
position: absolute; | |
top: 10px; | |
left: 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment