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.
forked from BBischof's block: Calendar Alternate Orientation v4 update
xxxxxxxxxx
<meta charset="utf-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<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>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
</head>
<body>
<div class="container2"></div>
<div class="container1">
<div class="dropdown">
Violation Type: <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" id="source">Overgrown Vegetation:πΏπΏπΏ
<span class="caret"></span></button>
<ul class="dropdown-menu" id="source">
<li><a href="#">Animals, Prohibited number:ππ#β£</a></li>
<li><a href="#">Animals and Pests, not specified:πππ</a></li>
<li><a href="#">Damaged or defective walls, floors or ceilings:π₯</a></li>
<li><a href="#">Insects, not specified:π</a></li>
<li><a href="#">Rodents, not specified:ππ</a></li>
<li><a href="#">Unsanitary conditions, not specified:π©</a></li>
<li><a href="#">Abandoned Vehicle:π</a></li>
<li><a href="#">Animal Feces:πππ©</a></li>
<li><a href="#">Animal Urine:πππ¦</a></li>
<li><a href="#">Barrier to Emergency Ingress or Egress:π¨β</a></li>
<li><a href="#">Bed Bugs:π€π</a></li>
<li><a href="#">Building Dampness or Water Intrusion:π¦</a></li>
<li><a href="#">Cockroaches:π</a></li>
<li><a href="#">Dogs:π</a></li>
<li><a href="#">Flies:π</a></li>
<li><a href="#">Human Feces:πΆπ©</a></li>
<li><a href="#">Human Urine:πΆπ¦</a></li>
<li><a href="#">Improper Refuse Storage:β¨</a></li>
<li><a href="#">Inadequate Heating:π₯</a></li>
<li><a href="#">Inadequate Lighting:π‘</a></li>
<li><a href="#">Inadequate Pest Exclusion:π</a></li>
<li><a href="#">Inadequate Ventilation:β¨π¨</a></li>
<li><a href="#">Inadequate or Improper Kitchen Facilities:π΄</a></li>
<li><a href="#">Inoperable Windows:πΌβ¬</a></li>
<li><a href="#">Lead Hazard:π©</a></li>
<li><a href="#">Mice:π</a></li>
<li><a href="#">Moderate risk food holding temperature:π²π₯</a></li>
<li><a href="#">Mold or Mildew:π</a></li>
<li><a href="#">Mosquitos:ππ</a></li>
<li><a href="#">No or inadequate hot or cold water:π¦</a></li>
<li><a href="#">Non-functioning Smoke Detector:π¬</a></li>
<li><a href="#">Nuisance Odors:π·β¨</a></li>
<li><a href="#">Overgrown Vegetation:πΏπΏπΏ</a></li>
<li><a href="#">Pidgeons:π¦</a></li>
<li><a href="#">Poison Ivy or Poison Oak:πΏ</a></li>
<li><a href="#">Rats:π</a></li>
<li><a href="#">Refuse Accumulation:β¨β¨β¨</a></li>
<li><a href="#">Refuse Not Properly Stored:β¨</a></li>
<li><a href="#">Sewage Hazard:π©β </a></li>
<li><a href="#">Standing Water:π</a></li>
<li><a href="#">Unsanitary Floors or Walls:π©π </a></li>
<li><a href="#">Unsanitary Public Areas:π©π°</a></li>
<li><a href="#">Unsanitary Toilets or Bathrooms:π©π</a></li>
</ul>
</div>
</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();
}
});
β
β
β
}
$("#source li a").click(function(){
violation_type = $(this).text();
$("#source:first-child").text(violation_type);
plot(violation_type.split(":")[0]);
});
plot("Overgrown Vegetation");
</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://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js
https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js
https://d3js.org/d3.v4.js
https://code.jquery.com/jquery-latest.min.js