Created
July 18, 2015 17:01
-
-
Save junkwhinger/533556afa7e9eec09217 to your computer and use it in GitHub Desktop.
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
Date | 한겨레 | 경향신문 | YTN | KBS_TV | 조선일보 | JTBC_TV | 국민일보 | YTN_TV | 동아일보 | TV조선 | 한국일보 | MBC_TV | 중앙일보 | SBS_TV | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
20150707 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
20150708 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
20150709 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | |
20150710 | 4 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
20150711 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | |
20150712 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
20150713 | 7 | 1 | 1 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 2 | 0 | 1 | 0 | |
20150714 | 8 | 12 | 11 | 3 | 7 | 11 | 5 | 7 | 2 | 2 | 8 | 3 | 3 | 2 | |
20150715 | 14 | 14 | 12 | 16 | 11 | 9 | 11 | 8 | 17 | 8 | 4 | 2 | 3 | 3 | |
20150716 | 15 | 26 | 15 | 14 | 13 | 8 | 3 | 12 | 6 | 9 | 7 | 5 | 4 | 4 | |
20150717 | 13 | 10 | 11 | 11 | 14 | 8 | 17 | 6 | 6 | 7 | 4 | 4 | 3 | 3 | |
20150718 | 3 | 1 | 3 | 6 | 3 | 3 | 3 | 2 | 3 | 6 | 1 | 1 | 0 | 1 |
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"> | |
<style> | |
body { | |
font: 12px Arial; | |
} | |
.axis path, .axis line { | |
fill: none; | |
stroke: grey; | |
stroke-width: 1; | |
shape-rendering: crispEdges; | |
} | |
.x.axis path { | |
display: none; | |
} | |
.line { | |
fill: none; | |
opacity: .5; | |
stroke-width: 1.5px; | |
} | |
pre { | |
display: none; | |
} | |
.hover-line { | |
fill: black; | |
stroke: black; | |
stroke-width: .5px; | |
left: 10px; | |
shape-rendering: crispEdges; | |
} | |
</style> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<body><body> | |
<script> | |
var margin = { | |
top: 30, | |
right: 120, | |
bottom: 30, | |
left: 50 | |
}, | |
width = 900 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var parseDate = d3.time.format("%Y%m%d").parse; | |
var bisectDate = d3.bisector(function (d) { | |
return d.date; | |
}).left; | |
var x = d3.time.scale() | |
.range([0, width]); | |
var y = d3.scale.linear() | |
.range([height, 0]); | |
var color = d3.scale.category20(); | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.orient("bottom"); | |
var yAxis = d3.svg.axis() | |
.scale(y) | |
.orient("left"); | |
//maxY is for resetting the y axis using legends | |
var maxY; | |
//function for x grid | |
function make_x_axis() { | |
return d3.svg.axis() | |
.scale(x) | |
.orient("bottom") | |
.ticks(20) | |
}; | |
var line = d3.svg.line() | |
.interpolate("linear") | |
.x(function (d) { | |
return x(d.date); | |
}) | |
.y(function (d) { | |
return y(d.articles); | |
}); | |
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.append("rect") | |
.attr("width", width) | |
.attr("height", height) | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("id", "mouse-tracker") | |
.attr("fill", "white") | |
.attr("opacity", 0); | |
d3.csv("data.csv", function(error, data) { | |
color.domain(d3.keys(data[0]).filter(function (key) { | |
return (key !== "Date") & (key !== "Issue"); | |
})); | |
data.forEach(function (d) { | |
d.date = parseDate(d.Date); | |
}); | |
var press = color.domain().map(function (name) { | |
return { | |
name: name, | |
values: data.map(function (d) { | |
return { | |
date: d.date, | |
articles: +d[name], | |
issue: d.Issue, | |
visible: ((name === "조선일보") | (name === "한겨레") ? true : false) | |
}; | |
}), | |
// making 조선일보 and 한겨레 visible when the page is loaded | |
visible: ((name === "조선일보") | (name === "한겨레") ? true : false) | |
}; | |
}); | |
x.domain(d3.extent(data, function (d) { | |
return d.date; | |
})); | |
y.domain([ | |
d3.min(press, function (c) { | |
return d3.min(c.values, function (v) { | |
return v.articles; | |
}); | |
}), | |
d3.max(press, function (c) { | |
return d3.max(c.values, function (v) { | |
return v.articles; | |
}); | |
})]); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
svg.append("g") | |
.attr("class", "y axis") | |
.style("fill", "black") | |
.call(yAxis) | |
.append("text") | |
.attr("x", 205) | |
.attr("y", -5) | |
.attr("dy", "-.5em") | |
.style("text-anchor", "end") | |
.text("# of News Articles on NAVER(국정원, 해킹)"); | |
maxY = findMaxY(press); | |
y.domain([0, maxY]); | |
svg.select(".y.axis") | |
.transition() | |
.call(yAxis); | |
var news = svg.selectAll(".news") | |
.data(press) | |
.enter().append("g") | |
.attr("class", "news"); | |
news.append("path") | |
.attr("class", "line") | |
.attr("d", function (d) { | |
return line(d.values); | |
}) | |
.attr("d", function (d) { | |
return d.visible ? line(d.values) : null; | |
}) | |
.style("stroke", function (d) { | |
return color(d.name); | |
}); | |
news.append("g") | |
.attr("class", "dot") | |
.selectAll("circle") | |
.data(function (d) { | |
return d.values; | |
}) | |
.enter().append("circle") | |
.attr("r", 2) | |
.attr("cx", function (d, i) { | |
return x(d.date); | |
}) | |
.attr("cy", function (d, i) { | |
return y(d.articles); | |
}) | |
.attr("fill", "none"); | |
news.selectAll(".dot") | |
.attr("stroke", function (d) { | |
return d.visible ? color(d.name) : null; | |
}); | |
//drawing grid lines | |
svg.append("g") | |
.attr("class", "grid") | |
.attr("transform", "translate(0," + height + ")") | |
.call(make_x_axis() | |
.tickSize(-height, 0, 0) | |
.tickFormat("")) | |
//drawing legend | |
var legendSpace = height / press.length; | |
news.append("rect") | |
.attr("width", 10) | |
.attr("height", 10) | |
.attr("id", function (d) { | |
return "legend-" + d.name.replace(" ", "").replace("/", ""); | |
}) | |
.attr("x", width + (margin.right / 3) - 15) | |
.attr("y", function (d, i) { | |
return (legendSpace) + i * (legendSpace) - 8; | |
}) | |
.attr("fill", function (d) { | |
return d.visible ? color(d.name) : "#F1F1F2"; | |
}) | |
.attr("class", "legend-box") | |
.on("click", function (d) { | |
d.visible = !d.visible; | |
d.values.visible = !d.values.visible; | |
maxY = findMaxY(press); | |
y.domain([0, maxY]); | |
svg.select(".y.axis") | |
.transition() | |
.call(yAxis); | |
news.select("path") | |
.transition() | |
.attr("d", function (d) { | |
return d.visible ? line(d.values) : null; | |
}) | |
news.selectAll(".dot") | |
.transition() | |
.attr("stroke", function (d) { | |
return d.visible ? color(d.name) : null; | |
}) | |
news.selectAll("circle") | |
.transition() | |
.attr("cy", function (d) { | |
return y(d.articles); | |
}) | |
news.select("rect") | |
.transition() | |
.attr("fill", function (d) { | |
return d.visible ? color(d.name) : "#F1F1F2"; | |
}) | |
}) | |
//adding legend texts | |
news.append("text") | |
.attr("x", width + (margin.right / 3)) | |
.attr("y", function (d, i) { | |
return (legendSpace) + i * (legendSpace); | |
}) | |
.text(function (d) { | |
return d.name; | |
}); | |
//-------------------- Hover line ---------------------// | |
var hoverLineGroup = svg.append("g") | |
.attr("class", "hover-line"); | |
var hoverLine = hoverLineGroup // Create line with basic attributes | |
.append("line") | |
.attr("id", "hover-line") | |
.attr("x1", 10).attr("x2", 10) | |
.attr("y1", 0).attr("y2", height + 10) | |
.style("pointer-events", "none"); // Stop line interferring with cursor | |
var hoverDate = hoverLineGroup.append('text') | |
.attr("class", "hover-text") | |
.attr("y", 10) // hover date text position | |
.attr("x", 30); // hover date text position | |
var columnNames = d3.keys(data[0]) //grab the key values from your first data row | |
//these are the same as your column names | |
.slice(1); //remove the first column name (`date`); | |
var focus = news.select("g") // create group elements to house tooltip text | |
.data(press) // bind each column name date to each g element | |
.enter().append("g") //create one <g> for each columnName | |
.attr("class", "focus"); | |
focus.append("text") // http://stackoverflow.com/questions/22064083/d3-js-multi-series-chart-with-y-value-tracking | |
.attr("class", "tooltip") | |
.attr("x", 30) // position tooltips | |
.attr("y", 30); // (return (11.25/2 =) 5.625) + i * (5.625) // position tooltips | |
// Add mouseover events for hover line. | |
d3.select("#mouse-tracker") // select chart plot background rect #mouse-tracker | |
.on("mousemove", mousemove) // on mousemove activate mousemove function defined below | |
.on("mouseout", function () { | |
hoverDate.text(null) | |
}); | |
function mousemove() { | |
var mouse_x = d3.mouse(this)[0]; | |
var graph_x = x.invert(mouse_x); | |
var format = d3.time.format('%m월 %d일'); | |
hoverDate.text(format(graph_x)); | |
d3.select("#hover-line") | |
.attr("x1", mouse_x) | |
.attr("x2", mouse_x); | |
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.select("text").text(d.Issue) | |
}; | |
function findMaxY(data) { | |
var maxYValues = data.map(function (d) { | |
if (d.visible) { | |
return d3.max(d.values, function (value) { | |
return value.articles; | |
}) | |
} | |
}); | |
return d3.max(maxYValues); | |
} | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment