Skip to content

Instantly share code, notes, and snippets.

@i-tu
Last active December 1, 2015 12:55
Show Gist options
  • Save i-tu/7e63593090bf13bd41d4 to your computer and use it in GitHub Desktop.
Save i-tu/7e63593090bf13bd41d4 to your computer and use it in GitHub Desktop.
Ranking line chart
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);
}
}
}
}
}
<!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.
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
.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