A calendar visualization of the 2012 housing violations dataset. An alternate presentation of this beeswarm visualization. This one takes advantage of the fact that our data is mostly focused on the year 2012. I used emoji's in the selections to draw more attention to different violations in a long list.
Select different sorts of violations from the drop down menu. Hold your mouse over a rectangle to reveal more details.
Original exploded calendar is here. Emoji reference from here.
Drop down inspired from Micah Stubb's guide.
forked from BBischof's block: Calendar Alternate Orientation v4 update
forked from BBischof's block: Violations 2012 calendar view
xxxxxxxxxx
<meta charset="utf-8">
<html>
<head>
<style>
body {
font: 1.1em sans-serif;
}
#chart{
width: 800px;
margin: 0 auto;
}
.background {
fill: #eee;
}
line {
stroke: #fff;
}
text.active {
fill: red;
}
.container1{
padding-top: 10px;
position: relative;
left: 6%;
top: 0%;
}
.container2{
padding-top: 10px;
position: relative;
left: 6%;
top: 0%;
}
.day {
fill: #fff;
stroke: #ccc;
}
.month {
fill: none;
stroke: #fff;
stroke-width: 4px;
}
.year-title {
font-size: 1.5em;
}
/* color ranges */
.RdYlGn .q0-11{fill:rgb(165,0,38)}
.RdYlGn .q1-11{fill:rgb(215,48,39)}
.RdYlGn .q2-11{fill:rgb(244,109,67)}
.RdYlGn .q3-11{fill:rgb(253,174,97)}
.RdYlGn .q4-11{fill:rgb(254,224,139)}
.RdYlGn .q5-11{fill:rgb(255,255,191)}
.RdYlGn .q6-11{fill:rgb(217,239,139)}
.RdYlGn .q7-11{fill:rgb(166,217,106)}
.RdYlGn .q8-11{fill:rgb(102,189,99)}
.RdYlGn .q9-11{fill:rgb(26,152,80)}
.RdYlGn .q10-11{fill:rgb(0,104,55)}
polylinear_color = d3.scale.linear()
.domain([0, 3, 10])
.range(['rgb(255,0,0)','rgb(255,255,255)','rgb(0,255,0)'])
/* hover info */
#tooltip {
background-color: #fff;
border: 2px solid #ccc;
padding: 10px;
}
</style>
</head>
<body>
<div class="container2"></div>
<div class="container1">
</div>
<div id="chart" class="clearfix"></div>
<script src="https://d3js.org/d3.v4.js"></script>
<!-- <script src="https://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script> -->
<script>
var violation_type = "Overgrown Vegetation";
///////////////////////////
function plot(name){
d3.select("svg").remove();
var width = 960,
height = 750,
cellSize = 25; // cell size
var no_months_in_a_row = Math.floor(width / (cellSize * 7 + 50));
var shift_up = cellSize * 3;
var day = d3.timeFormat("%w"), // day of the week
day_of_month = d3.timeFormat("%e") // day of the month
day_of_year = d3.timeFormat("%j")
week = d3.timeFormat("%U"), // week number of the year
month = d3.timeFormat("%m"), // month number
year = d3.timeFormat("%Y"),
percent = d3.format(".1%"),
format = d3.timeFormat("%Y-%m-%d");
var parseDate = d3.timeParse("%Y-%m-%d");
var color = d3.scaleQuantize()
.domain([0, 10])
.range(d3.range(11).map(function(d) { return "q" + d + "-11"; }));
var svg = d3.select("#chart").selectAll("svg")
.data(d3.range(2012, 2013)) //years included in the viz
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "RdYlGn")
.append("g")
var rect = svg.selectAll(".day")
.data(function(d) {
return d3.timeDays(new Date(d, 0, 1), new Date(d + 1, 0, 1));
})
.enter().append("rect")
.attr("class", "day")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) {
var month_padding = 1.2 * cellSize*7 * ((month(d)-1) % (no_months_in_a_row));
return day(d) * cellSize + month_padding;
})
.attr("y", function(d) {
var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
var row_level = Math.ceil(month(d) / (no_months_in_a_row));
return (week_diff*cellSize) + row_level*cellSize*8 - cellSize/2 - shift_up;
})
.datum(format);
var month_titles = svg.selectAll(".month-title") // Jan, Feb, Mar and the whatnot
.data(function(d) {
return d3.timeMonths(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.text(monthTitle)
.attr("x", function(d, i) {
var month_padding = 1.2 * cellSize*7* ((month(d)-1) % (no_months_in_a_row));
return month_padding;
})
.attr("y", function(d, i) {
var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
var row_level = Math.ceil(month(d) / (no_months_in_a_row));
return (week_diff*cellSize) + row_level*cellSize*8 - cellSize - shift_up;
})
.attr("class", "month-title")
.attr("d", monthTitle);
var year_titles = svg.selectAll(".year-title") // Jan, Feb, Mar and the whatnot
.data(function(d) {
return d3.timeYears(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
.enter().append("text")
.text(yearTitle)
.attr("x", function(d, i) { return width/2 - 100; })
.attr("y", function(d, i) { return cellSize*5.5 - shift_up; })
.attr("class", "year-title")
.attr("d", yearTitle);
// Tooltip Object
var tooltip = d3.select("body")
.append("div").attr("id", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
function dayTitle (t0) {
return t0.toString().split(" ")[2];
}
function monthTitle (t0) {
return t0.toLocaleString("en-us", { month: "long" });
}
function yearTitle (t0) {
return t0.toString().split(" ")[3];
}
d3.csv("Violations-2012.csv", function(error, data) {
if (error) throw error;
var vio_by_type = d3.nest().key(function(d) {return d.violation_type}).entries(data);
var new_data = d3.nest()
.key(function(d) {return d.violation_type})
.key(function(d) {return (d.violation_date.split(" ")[0])})
.rollup(function(v) { return v.length; })
.map(data);
var data_length =d3.nest()
.key(function(d) {return d.violation_type})
.rollup(function(v) { return v.length})
.map(data)
d3.select(".container2").html("Number of violations: " + data_length.get(name))
rect.filter(function(d) {
return (new_data.get(name).has(d));
})
.attr("class", function(d) {
return "day " + color(new_data.get(name).get(d));
})
.select("title")
.text(function(d) { return d + ": " + percent(new_data.get(name).get(d)); });
// Tooltip
rect.on("mouseover", mouseover);
rect.on("mouseout", mouseout);
function mouseover(d) {
tooltip.style("visibility", "visible");
var factlet_num = (new_data.get(name).get(d) !== undefined) ? new_data.get(name).get(d) : 0;
var purchase_text = d + ": " + factlet_num + " violations";
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(purchase_text)
.style("left", (d3.event.pageX)+30 + "px")
.style("top", (d3.event.pageY) + "px");
}
function mouseout (d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
var $tooltip = $("#tooltip");
$tooltip.empty();
}
});
}
d3.csv("Violations-2012.csv", function(error, data) {
if (error) throw error;
var vio_by_type = d3.nest().key(function(d) {return d.violation_type}).entries(data);
var names = vio_by_type.map(function(f){return f.key});
var selector = d3.select(".container1")
.append("select")
.attr("id", "vioselector")
.selectAll("option")
.data(names)
.enter().append("option")
.text(function(d) { return d; })
.attr("value", function (d) {
console.log(d); return d;
});
var name = "Refuse Accumulation"; d3.select("#vioselector").property("selectedIndex", name);
d3.select("#vioselector")
.on("change", function(d) {
name = this.value;
// update();
plot(name);
})
});
</script>
</body>
</html>
Modified http://d3js.org/d3.v4.js to a secure url
Modified http://code.jquery.com/jquery-latest.min.js to a secure url
https://d3js.org/d3.v4.js
https://code.jquery.com/jquery-latest.min.js