Skip to content

Instantly share code, notes, and snippets.

@carlvlewis
Created March 21, 2017 07:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carlvlewis/a757f41c86a9b83f273f37a547e0f788 to your computer and use it in GitHub Desktop.
Save carlvlewis/a757f41c86a9b83f273f37a547e0f788 to your computer and use it in GitHub Desktop.
Georgia's budget in $1
license: mit
{
"name":"chart",
"children":[
{
"name":"Department of Community Health",
"longname":"Department of Community Health",
"cents":0.315925410017422,
"total":13387306434,
"note":" ",
"children":[
{
"name":"State",
"value":2958621234
},
{
"name":"Other",
"value":3669823351
},
{
"name":"Federal",
"value":6648893592
},
{
"name":"Tobacco settlement",
"value":109968257
}
]
},
{
"name":"Department of Education",
"longname":"Department of Education",
"cents":0.227443679782949,
"total":9637902306,
"note":" ",
"children":[
{
"name":"State",
"value":7944481675
},
{
"name":"Other",
"value":5395610
},
{
"name":"Federal",
"value":1688025021
}
]
},
{
"name":"University System",
"longname":"University System",
"cents":0.156031419189134,
"total":6611815181,
"note":" ",
"children":[
{
"name":"State",
"value":1939087764
},
{
"name":"Other",
"value":4672727417
}
]
},
{
"name":"Department of Transportation",
"longname":"Department of Transportation",
"cents":0.0491113482535659,
"total":2081088281,
"note":" ",
"children":[
{
"name":"State",
"value":15028477
},
{
"name":"Other",
"value":6490891
},
{
"name":"Federal",
"value":1210491192
},
{
"name":"Gas tax",
"value":849077721
}
]
},
{
"name":"Human Services",
"longname":"Department of Human Services",
"cents":0.0382931673994004,
"total":1622668991,
"note":" ",
"children":[
{
"name":"State",
"value":517681501
},
{
"name":"Other",
"value":78197645
},
{
"name":"Federal",
"value":1020598039
},
{
"name":"Tobacco settlement",
"value":6191806
}
]
},
{
"name":"DBHDD",
"longname":"Department of Behavioral Health & Developmental Disabilities",
"cents":0.0275709457421051,
"total":1168315962,
"note":" ",
"children":[
{
"name":"State",
"value":958578287
},
{
"name":"Other",
"value":50945009
},
{
"name":"Federal",
"value":148537528
},
{
"name":"Tobacco settlement",
"value":10255138
}
]
},
{
"name":"Corrections",
"longname":"Department of Corrections",
"cents":0.0274355836167907,
"total":1162580006,
"note":" ",
"children":[
{
"name":"State",
"value":1148527802
},
{
"name":"Other",
"value":13581649
},
{
"name":"Federal",
"value":470555
}
]
},
{
"name":"Debt payments",
"longname":"General Obligation debt payments",
"cents":0.0267763310981543,
"total":1134644249,
"note":" ",
"children":[
{
"name":"State",
"value":960280975
},
{
"name":"Federal",
"value":17683461
},
{
"name":"Gas tax",
"value":156679813
}
]
},
{
"name":"Technical College System",
"longname":"Technical College System of Georgia",
"cents":0.017296594917159,
"total":732941413,
"note":" ",
"children":[
{
"name":"State",
"value":331854904
},
{
"name":"Other",
"value":335970717
},
{
"name":"Federal",
"value":65115792
}
]
},
{
"name":"Early Care and Learning",
"longname":"Department of Early Care and Learning",
"cents":0.016345706356221,
"total":692647609,
"note":" ",
"children":[
{
"name":"State",
"value":55493488
},
{
"name":"Other",
"value":140000
},
{
"name":"Federal",
"value":322714089
},
{
"name":"Lottery",
"value":314300032
}
]
},
{
"name":"HOPE",
"longname":"Student Finance Commission (HOPE)",
"cents":0.0161232282651526,
"total":683220123,
"note":" ",
"children":[
{
"name":"State",
"value":48858430
},
{
"name":"Other",
"value":713673
},
{
"name":"Lottery",
"value":633648020
}
]
},
{
"name":"Public Health",
"longname":"Department of Public Health",
"cents":0.0156274488551915,
"total":662211522,
"note":" ",
"children":[
{
"name":"State",
"value":216758954
},
{
"name":"Other",
"value":2864821
},
{
"name":"Federal",
"value":427085823
},
{
"name":"Tobacco settlement",
"value":13717860
},
{
"name":"Brain & Spinal Injury Trust Fund",
"value":1784064
}
]
},
{
"name":"Juvenile Justice",
"longname":"Department of Juvenile Justice",
"cents":0.00740096962232721,
"total":313615319,
"note":" ",
"children":[
{
"name":"State",
"value":306918411
},
{
"name":"Other",
"value":432243
},
{
"name":"Federal",
"value":6264665
}
]
},
{
"name":"Community Affairs",
"longname":"Department of Community Affairs",
"cents":0.00591157286232412,
"total":250502286,
"note":" ",
"children":[
{
"name":"State",
"value":64428953
},
{
"name":"Other",
"value":13180869
},
{
"name":"Federal",
"value":172892464
}
]
},
{
"name":"Natural Resources",
"longname":"Department of Natural Resources",
"cents":0.00586669702370942,
"total":248600677,
"note":" ",
"children":[
{
"name":"State",
"value":101016923
},
{
"name":"Other",
"value":97290448
},
{
"name":"Federal",
"value":50293306
}
]
},
{
"name":"Judiciary",
"longname": "Judiciary",
"cents":0.0054006959050309,
"total":228853928,
"note":" Court of Appeals, Judicial Council, Juvenile Courts, Superior Courts, Supreme Court, Public Defender Standards Council",
"children":[
{
"name":"State",
"value":220556589
},
{
"name":"Other",
"value":5296948
},
{
"name":"Federal",
"value":3000391
}
]
},
{
"name":"State Patrol",
"longname":"Department of Public Safety",
"cents":0.00484807392505691,
"total":205436629,
"note":" ",
"children":[
{
"name":"State",
"value":130656876
},
{
"name":"Other",
"value":42406001
},
{
"name":"Federal",
"value":32373752
}
]
},
{
"name":"Admin",
"longname":"Department of Administrative Services",
"cents":0.00471497162829069,
"total":199796433,
"note":" ",
"children":[
{
"name":"State",
"value":4878113
},
{
"name":"Other",
"value":194918320
}
]
},
{
"name":"Revenuer",
"longname":"Department of Revenue",
"cents":0.00421363822241453,
"total":178552482,
"note":" ",
"children":[
{
"name":"State",
"value":177299612
},
{
"name":"Federal",
"value":819087
},
{
"name":"Tobacco settlement",
"value":433783
}
]
},
{
"name":"GBI",
"longname": "GBI",
"cents":0.00362514781233577,
"total":153615262,
"note":" ",
"children":[
{
"name":"State",
"value":99943154
},
{
"name":"Other",
"value":23088236
},
{
"name":"Federal",
"value":30583872
}
]
},
{
"name":"Labor",
"longname":"Department of Labor",
"cents":0.00322895439279579,
"total":136826607,
"note":" ",
"children":[
{
"name":"State",
"value":12692804
},
{
"name":"Other",
"value":1209939
},
{
"name":"Federal",
"value":122923864
}
]
},
{
"name":"EcD",
"longname":"Department of Economic Development",
"cents":0.00258494058997909,
"total":109536589,
"note":" ",
"children":[
{
"name":"State",
"value":33620285
},
{
"name":"Federal",
"value":74021318
},
{
"name":"Tobacco settlement",
"value":1894986
}
]
},
{
"name":"Defense",
"longname":"Department of Defense",
"cents":0.00216271602698469,
"total":91644867,
"note":" ",
"children":[
{
"name":"State",
"value":9496994
},
{
"name":"Other",
"value":7641586
},
{
"name":"Federal",
"value":74506287
}
]
},
{
"name":"Gov",
"longname":"Office of the Governor",
"cents":0.00198485142580537,
"total":84107873,
"note":" ",
"children":[
{
"name":"State",
"value":52347978
},
{
"name":"Other",
"value":1576045
},
{
"name":"Federal",
"value":30183850
}
]
},
{
"name":"Legis",
"longname":"Georgia General Assembly & state Auditor",
"cents":0.00173275287274982,
"total":73425223,
"note":" Senate, House, Joint Offices, Dept of Audits & Accounts",
"children":[
{
"name":"State",
"value":72785223
},
{
"name":"Other",
"value":640000
}]},
{
"name":"DMV",
"longname":"Department of Driver Services",
"cents":0.00155478811793266,
"total":65883985,
"note":" ",
"children":[
{
"name":"State",
"value":63039864
},
{
"name":"Other",
"value":2844121
}
]
},
{
"name":"Everything else",
"longname": "Everything else",
"cents":0.0107883682029167,
"total":457155982,
"note":" ",
"children":[
{
"name":"State",
"value":293857870
},
{
"name":"Other",
"value":125791649
},
{
"name":"Federal",
"value":37506463
}
]
}
]
}
<html class="ocks-org do-not-copy">
<meta charset="utf-8">
<title>If Georgia's budget were $1 instead of $42 billion</title>
<style>
body {
/*font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;*/
font-family: "Arial", Arial;
font-size: 11.5px;
/* position: relative;*/
width: 1628px;
}
#chart {
width: 1728px;
height: 608px;
background: #ddd
opacity: 0;
}
text {
pointer-events: none;
}
.grandparent text {
font-weight: bold;
font-size: 16px;
}
rect {
fill: none;
stroke: #fff;
}
rect.parent,
.grandparent rect {
stroke-width: 2px;
}
.grandparent rect {
fill: orange;
}
.grandparent:hover rect {
fill: #ee9700;
}
.children rect.parent,
.grandparent rect {
cursor: pointer;
}
.children rect.parent {
fill: #bbb;
fill-opacity: .5;
}
.children:hover rect.child {
fill: #bbb;
}
div.tooltip {
position: absolute;
text-align: left;
width: 250px;
height: 168px;
padding: 2px;
font: 12px sans-serif;
background: beige;
border: 0px;
border-radius: 8px;
pointer-events: none;
opacity: 0;
}
.subtitle {
position: absolute;
text-align: left;
width: 1050px;
height: 160px;
padding: 2px;
font: 24px sans-serif;
background: none;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
.explainer {
font: 14px sans-serif;
}
</style>
<p id="lede">
<font size='6'><b>If Georgia's budget were $1</b></font><br>
<font size='3'>(Instead of $42,374,896,219)<br></font>
<br>
<font size = '2'>by Maggie Lee<br>
Sept. 4, 2014<br>
<br>
<!-- Note, lots of the values are less than one penny, like "0.7¢" means 7/10 of a penny. -->
Georgia's total budget is <b>$42,374,896,219</b> for the year ending in June, 2015.<br><br> <b>$18,738,793,140</b> of that is <font color="green">state </font> money: the taxes on purchases and income me and you and companies make to the Georgia taxman. <br><br><b>$12,184,984,411</b> is <font color="green">federal</font> money passed through Georgia's budget. A lot of that is matching funds they send when we pony up some cash as well. <br><br><b>$11,451,118,668</b> comes from <font color="green">'other</font>' sources. That includes fees for service, like tuition payments to colleges and universities<br>
<br>
<br>
<aside><b>Click any cell to zoom in, or the top orange label to zoom out.</b></aside>
</p>
<p id="chart">
<!-- ******* this here is what Mike Bostock wrote on the original: -->
<!-- <header>
<aside>June 8, 2012</aside>
<a href="../" rel="author">Mike Bostock</a>
</header> -->
<!-- <p>Treemaps are a form of <a href="http://mbostock.github.com/d3/ex/treemap.html">space</a><a href="http://mbostock.github.com/d3/ex/pack.html">-filling</a> <a href="http://mbostock.github.com/d3/ex/sunburst.html">layout</a> where the area of each rectangle is proportional to its value. This example shows the size of files in a source tree.
<p>Treemaps visualize hierarchical data, but since often only the leaf nodes (files rather than folders) are drawn, it can be difficult to see the hierarchy. <a href="http://en.wikipedia.org/wiki/File:Tree_Map.png">Padding</a> is sometimes used to show the hierarchy via containment, though this introduces area distortion. <a href="http://www.win.tue.nl/~vanwijk/ctm.pdf">Cushion gradients</a> also indicate hierarchy, but are somewhat unintuitive (or perhaps just ugly).
<p>The treemap above uses interaction to reveal the hierarchy incrementally: clicking on a node zooms in. Only two levels of the hierarchy are visible at a time. This allows the layout’s aspect ratio (ideally φ) to be optimized for the current view, rather than computing a global layout. It also allows the exploration of arbitrarily-large datasets: data can be lazily-loaded and positioned on zoom!
<p>This visualization is implemented in <a href="http://d3js.org">D3.js</a>, based on an <a href="http://mbostock.github.com/d3/talk/20111018/treemap.html">earlier version</a> from my talk at SVG Open. Also see Nicolas Garcia Belmonte’s zoomable treemap of <a href="http://thejit.org/static/v20/Jit/Examples/Treemap/example1.html">music albums</a>, and The New York Times’ free-form zooming for <a href="http://www.nytimes.com/packages/html/newsgraphics/2011/0119-budget/">Obama’s 2012 budget proposal</a>. Note the subtle differences in behavior! -->
<!-- *********** -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<!-- <script src="tooltip.js"></script> -->
<script>document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1"></' + 'script>')</script>
<script type="text/javascript"></script>
<script>
everything_else_string = "Attorney General's office, Board of Pardons and Paroles, Employees' Retirement System, Department of Agriculture, Forestry Commission, Department of Veterans Service, Teachers Retirement System, Workers' Compensation Board, Secretary of State's office, State Accounting Office, Insurance Commissioner's office, Department of Banking and Finance, Public Service Commission, Soil and Water Conservation Commission, State Properties Commission<br>";
var factor = 8;
var margin = {top: 30, right: 50, bottom: 30, left: 0},
width = (factor * 166),
height = (factor * 68) -margin.top ,
formatNumber = d3.format(",d"),
transitioning;
console.log(width)
console.log(height)
var color = d3.scale.category10();
var big_cents = d3.format(".2n");
var little_cents = d3.format(".1n");
var reg_cents = d3.format(".1n");
var big_total = 42374896219; // let's hardcode total spending
var x = d3.scale.linear()
.domain([0, width])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, height])
.range([0, height]);
var treemap = d3.layout.treemap()
.children(function(d, depth) { return depth ? null : d._children; })
.sort(function(a, b) { return a.value - b.value; })
.ratio(height / width * 0.5 * (1 + Math.sqrt(10))) // ohh this changest the layont
.round(false);
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.bottom + margin.top)
.style("margin-left", -margin.left + "px")
.style("margin.right", -margin.right + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.style("shape-rendering", "crispEdges");
var grandparent = svg.append("g")
.attr("class", "grandparent");
grandparent.append("rect")
.attr("y", -margin.top)
.attr("width", width)
.attr("height", margin.top);
grandparent.append("text")
.attr("x", 6)
.attr("y", 6 - margin.top)
.attr("dy", ".65em");
var div = d3.select("body").append("div") // put the tooltip in a separate div
.attr("class", "tooltip"); //see d3noob website for all tooltip
var div2 = d3.select("body").append("div")
.attr("class", "subtitle");
d3.json("dollar.json", function(root) {
initialize(root);
accumulate(root);
layout(root);
display(root);
function initialize(root) {
root.x = root.y = 0;
root.dx = width;
root.dy = height;
root.depth = 0;
}
// Aggregate the values for internal nodes. This is normally done by the
// treemap layout, but not here because of our custom implementation.
// We also take a snapshot of the original children (_children) to avoid
// the children being overwritten when when layout is computed.
function accumulate(d) {
return (d._children = d.children)
? d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0)
: d.value;
}
// Compute the treemap layout recursively such that each group of siblings
// uses the same size (1×1) rather than the dimensions of the parent cell.
// This optimizes the layout for the current zoom state. Note that a wrapper
// object is created for the parent node for each group of siblings so that
// the parent’s dimensions are not discarded as we recurse. Since each group
// of sibling was laid out in 1×1, we must rescale to fit using absolute
// coordinates. This lets us use a viewport to zoom.
function layout(d) {
if (d._children) {
treemap.nodes({_children: d._children});
d._children.forEach(function(c) {
c.x = d.x + c.x * d.dx;
c.y = d.y + c.y * d.dy;
c.dx *= d.dx;
c.dy *= d.dy;
c.parent = d;
layout(c);
});
}
}
console.log("ok")
function display(d) { // this is the orange bar
grandparent
.datum(d.parent)
.on("click", transition)
.select("text")
.text("Georgia budget June 2014 through July 2015 -- includes state and federal funds");
var g1 = svg.insert("g", ".grandparent")
.datum(d)
.attr("class", "depth");
var g = g1.selectAll("g")
.data(d._children)
.enter().append("g");
g.filter(function(d) { return d._children; })
.classed("children", true)
.on("click", transition);
g.selectAll(".child")
.data(function(d) { return d._children || [d]; })
.enter().append("rect")
.attr("class", "child")
.style("fill", function (d) {return color(d.parent.name); })
.style("stroke-width", "0px")
.call(rect);
dollar_formatter = d3.format("0,000");
g.append("rect")
.attr("class", "parent")
.call(rect);
d3.selectAll(".parent")
.on("mouseover", function (d) {
div.transition()
.duration(200)
.style("opacity", 0.9);
div.html( d.longname + "<p><b><u>Total: $" + dollar_formatter(d.total) + "</u></b>" + footnoter(d))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px"); })
.on("mouseout", function (d) {
div.transition()
.duration(300)
.style("opacity", 0)
});
d3.selectAll(".depth").append("text") // this appends the subtitle
div2.style("opacity", 0.5)
div2.html(d.name != "Everything else" ?
d.longname + " " + big_cents(d.cents*100) + "¢"
:
d.longname + " " + big_cents(d.cents*100) + "¢" + "<br><font size = '2'>" + everything_else_string + "</font>")
.style("opacity", isNaN(d.cents) ? 0 : 1 ) // erase out the ones that are NaN
.style("left", width*0.01)
.style("top", height *1.64);
g.append("text") // this appends text to parent node
.attr("dy", "0.75em")
.text(function(d) { return d.name; })
.call(text);
g.append("text") // this appends cents figure to parent node
.attr("class", "cents")
.attr("dy", function(d) {
if (d.cents > 0.0019) {return "1.75em"; }
else if (d.cents < 0.0019) {return "0.75em" ;}
else if (isNaN(d.cents)) {return "1.75em"; }
;})
.attr("dx", function(d) {return d.cents < 0.0019 ? "2.75em" : 0 ;})
.call(text)
.text(function(d) {
if (d.cents > 0.1) { return (big_cents(100*d.cents)) + "¢"; }
else if (d.cents < 0.1) { return (little_cents(100*d.cents)) + "¢"; }
else if ( isNaN(d.cents)) {
if (d.value/big_total > 0.1) {return (big_cents(100*(d.value/big_total))) + "¢";}
else {return (little_cents(100*(d.value/big_total))) + "¢"; }}
;})
function transition(d) {
if (transitioning || !d) return;
transitioning = true;
var g2 = display(d),
t1 = g1.transition().duration(750),
t2 = g2.transition().duration(750);
// Update the domain only after entering new elements.
x.domain([d.x, d.x + d.dx]);
y.domain([d.y, d.y + d.dy]);
// Enable anti-aliasing during the transition.
svg.style("shape-rendering", null);
// Draw child nodes on top of parent nodes.
svg.selectAll(".depth").sort(function(a, b) { return a.depth - b.depth; });
// Fade-in entering text.
g2.selectAll("text").style("fill-opacity", 0);
// Transition to the new view.
t1.selectAll("text").call(text).style("fill-opacity", 0);
t2.selectAll("text").call(text).style("fill-opacity", 1);
t1.selectAll("rect").call(rect);
t2.selectAll("rect").call(rect);
// Remove the old node when the transition is finished.
t1.remove().each("end", function() {
svg.style("shape-rendering", "crispEdges");
transitioning = false;
});
}
return g;
}
function text(text) {
text.attr("x", function(d) { return x(d.x) + 2 ; }) //moves text left/right
.attr("y", function(d) { return y(d.y) + 2; }); // moves text up/down
}
function rect(rect) {
rect.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.attr("width", function(d) { return x(d.x + d.dx) - x(d.x); })
.attr("height", function(d) { return y(d.y + d.dy) - y(d.y); });
}
function footnoter(footnote) {
var my_string = ""
for (i = footnote._children.length-1; i > -1 ; i--) {
//console.log(i);
//console.log(footnote._children[i].name + " " + dollar_formatter(footnote._children[i].value));
my_string = my_string.concat("<p>", footnote._children[i].name, ": $", (dollar_formatter(footnote._children[i].value)))
}
return my_string;
}
function name(d) {
return d.parent
? name(d.parent) + "." + d.name
: d.name;
}
});
</script>
<p id="explainer">
<a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank"><img src="http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png"></a><br><hr>
Check out how boring <a href="https://opb.georgia.gov/sites/opb.georgia.gov/files/related_files/site_page/Budget%20In%20Brief%20AFY%202014%20and%20FY%202015.pdf" target="_blank">the original data presentation was, pages 34 and 35.</a><br><br><br><br><br>
This treemap was made with D3.js and mostly lifted from Mike Bostock's <a href="http://bost.ocks.org/mike/treemap/" target="_blank">canonical example</a>.<br>
My remixed code <a href="http://bl.ocks.org/greencracker/fd56f1a279c0e3d5a5d0" target="_blank">is here.</a>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment