Skip to content

Instantly share code, notes, and snippets.

@junkwhinger
Created July 18, 2015 17:01
Show Gist options
  • Save junkwhinger/533556afa7e9eec09217 to your computer and use it in GitHub Desktop.
Save junkwhinger/533556afa7e9eec09217 to your computer and use it in GitHub Desktop.
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
<!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