A visualization of Indian state finances (revenues and expenditures) for 2010-2011
created for India60
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| body { position: relative; } | |
| .chart { height: 500px; overflow: auto; } | |
| .tooltip { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 956px; | |
| height: 121px; | |
| padding: 0 0 16px 0; | |
| background: #f5f5f5; | |
| box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15); | |
| border: 1px solid #F7F7F7; | |
| } | |
| .tooltip.stick { | |
| position: fixed; | |
| top: 0; | |
| z-index: 1000; | |
| } | |
| .tooltip hgroup { | |
| margin-top: 0; | |
| padding: 6px 16px; | |
| background: #eee; | |
| text-shadow: 1px 1px 1px #fff; | |
| border-bottom: 1px solid #ddd; | |
| border-right: 1px solid #ddd; | |
| border-radius: 3px 3px 0 0; | |
| float: left; | |
| width: 200px; | |
| } | |
| .tooltip h1 { | |
| margin: 0; | |
| font-size: 18px; | |
| text-transform: uppercase; | |
| } | |
| .tooltip h6 { | |
| margin: 0; | |
| line-height: 10px; | |
| } | |
| .tooltip-content { | |
| padding: 0 16px 16px 16px; | |
| } | |
| .tooltip h2 { | |
| font-size: 14px; | |
| } | |
| .revenue, .expenditure { | |
| float: left; | |
| margin-left: 60px; | |
| } | |
| </style> | |
| <body> | |
| <div class="chart"></div> | |
| <p style="font-size: 12px; margin: 0;"><em>Source: <a href="http://saiindia.gov.in/english/home/Our_Products/Accounts/Combined_Finance/2010_11/2010_11.html">Comptroller and Auditor General of India</a></em></p> | |
| <div class="tooltip"> | |
| <hgroup> | |
| <h1>Legend</h1> | |
| <h6>in billions of rupees</h6> | |
| </hgroup> | |
| <div class="tooltip-content"> | |
| <section class="revenue"> | |
| <h2>Revenue <span></span></h2> | |
| <div class="chart-revenue"></div> | |
| </section> | |
| <section class="expenditure"> | |
| <h2>Expenditure <span></span></h2> | |
| <div class="chart-expenditure"></div> | |
| </section> | |
| </div> | |
| </div> | |
| <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script> | |
| d3.json("/d/4132655/india-state-finances-2011.json", function(error, data) { | |
| data.shift(); //remove union data for now. | |
| var formatter = d3.format(',d'); | |
| var rupee = formatter//function(v) { return '₹' + formatter(v); }; | |
| var midX = 480; | |
| var contentPadding = 36; | |
| var barHeight = 10; | |
| var barPadding = 3; | |
| var statePadding = 20; | |
| var maxRevenue = d3.max(data, function(d) { return d3.sum(d.revenue, function(d) { return d.value; }); }); | |
| var maxExpenditure = d3.max(data, function(d) { return d3.sum(d.expenditure, function(d) { return d.value; }); }); | |
| var tooltip = d3.select('.tooltip'); | |
| var xRevenue = d3.scale.linear() | |
| .domain([0, maxRevenue]) | |
| .rangeRound([0, 400]); | |
| var xExpenditure = d3.scale.linear() | |
| .domain([0, maxExpenditure]) | |
| .rangeRound([0, 400]); | |
| var colorRevenue = d3.scale.ordinal() | |
| .domain([0,1,2]) | |
| .range(['#8C510A', '#F6E8C3', '#5AB4AC']); | |
| var colorExpenditure = d3.scale.ordinal() | |
| .domain([0, 1, 2, 3]) | |
| .range(['#D73027', '#FC8D59', '#FEE08B', '#91CF60']); | |
| var svg = d3.select('.chart').append('svg') | |
| .attr('width', '960') | |
| .attr('height', '1024') | |
| .style('margin', '160px 0 0 0'); | |
| var state = svg.selectAll('g.state') | |
| .data(data) | |
| .enter().append('g') | |
| .attr('class', 'state') | |
| .on('mouseover', function(d) { | |
| tooltip.select('h1').html(d.name); | |
| var rmax = d3.max(d.revenue, function(r) { return r.value; }); | |
| var emax = d3.max(d.expenditure, function(r) { return r.value; }); | |
| var w = 268; | |
| var x = d3.scale.linear() | |
| .domain([0, d3.max([rmax, emax])]) | |
| .range([0, w - 100]); | |
| var y = function(d1, i) { return (barHeight + barPadding) * i; }; | |
| tooltip.select('.revenue h2 span') | |
| .html(' – ₹' + Math.round(d3.sum(d.revenue, function(d) { return d.value; })/100) + ' billion'); | |
| d3.select('.chart-revenue').html(''); | |
| var svgRevenue = d3.select('.chart-revenue').append('svg') | |
| .attr('width', w) | |
| .attr('height', (barHeight + barPadding) * d.revenue.length); | |
| svgRevenue.selectAll('.label-name') | |
| .data(d.revenue) | |
| .enter().append('text') | |
| .attr('class', 'label-name') | |
| .attr('x', 0) | |
| .attr('y', function(d2,i) { return y(d2, i) + 5; }) | |
| .attr("dy", ".35em") | |
| .style("fill", '#6b6b6b') | |
| .style("font-size", '12px') | |
| .style("text-transform", 'capitalize') | |
| .text(function(d) { return d.name; }); | |
| svgRevenue.selectAll('label-value') | |
| .data(d.revenue) | |
| .enter().append('text') | |
| .attr('class', 'label-value') | |
| .attr('x', 95) | |
| .attr('y', function(d2,i) { return y(d2, i) + 5; }) | |
| .attr("dy", ".35em") | |
| .attr("text-anchor", "end") | |
| .style("fill", '#43403f') | |
| .style("font-size", '12px') | |
| .style("font-weight", 'bold') | |
| .text(function(d) { return rupee(Math.round(d.value/100)); }); | |
| svgRevenue.selectAll('rect') | |
| .data(d.revenue) | |
| .enter().append('rect') | |
| .attr('x', 100) | |
| .attr('y', function(d2, i) { return y(d2, i); }) | |
| .attr('height', barHeight) | |
| .attr('width', function(d1) { return x(d1.value); }) | |
| .style('fill', function(d1, i) { return colorRevenue(i); }); | |
| x = d3.scale.linear() | |
| .domain([0, d3.max([rmax, emax])]) | |
| .range([0, w-100]); | |
| tooltip.select('.expenditure h2 span') | |
| .html(' – ₹' + Math.round(d3.sum(d.expenditure, function(d) { return d.value; })/100) + ' billion'); | |
| d3.select('.chart-expenditure').html(''); | |
| var svgExpenditure = d3.select('.chart-expenditure').append('svg') | |
| .attr('width', w) | |
| .attr('height', (barHeight + barPadding) * d.expenditure.length); | |
| svgExpenditure.selectAll('text') | |
| .data(d.expenditure) | |
| .enter().append('text') | |
| .attr('x', 0) | |
| .attr('y', function(d2,i) { return y(d2, i) + 5; }) | |
| .attr("dy", ".35em") | |
| .style("fill", '#6b6b6b') | |
| .style("font-size", '12px') | |
| .text(function(d) { return d.name.replace(/services|payments/gi, ''); }); | |
| svgExpenditure.selectAll('label-value') | |
| .data(d.expenditure) | |
| .enter().append('text') | |
| .attr('class', 'label-value') | |
| .attr('x', 95) | |
| .attr('y', function(d2,i) { return y(d2, i) + 5; }) | |
| .attr("dy", ".35em") | |
| .attr("text-anchor", "end") | |
| .style("fill", '#43403f') | |
| .style("font-size", '12px') | |
| .style("font-weight", 'bold') | |
| .text(function(d) { return rupee(Math.round(d.value/100)); }); | |
| svgExpenditure.selectAll('rect') | |
| .data(d.expenditure) | |
| .enter().append('rect') | |
| .attr('x', 100) | |
| .attr('y', function(d2, i) { return y(d2, i); }) | |
| .attr('height', barHeight) | |
| .attr('width', function(d1) { return x(d1.value); }) | |
| .style('fill', function(d1, i) { return colorExpenditure(i); }); | |
| d3.event.stopPropagation(); | |
| }); | |
| var revenue = state.selectAll('rect.revenue') | |
| .data(function(d, i) { | |
| d.bottomX = 0; | |
| d.bottomY = (barHeight * 2 + barPadding + statePadding/2) * (i + 1) + contentPadding; | |
| var total = d3.sum(d.revenue, function(d1) { return d1.value; }); | |
| d.revenue.forEach(function(r, j) { | |
| r.i = i; | |
| r.total = total; | |
| r.x0 = j === 0 ? midX - xRevenue(total)/2 : d.revenue[j-1].x0 + xRevenue(d.revenue[j-1].value); | |
| d.bottomX = d.bottomX === 0 ? r.x0 : d3.min([d.bottomX, r.x0]); | |
| }); | |
| return d.revenue; | |
| }) | |
| .enter().append('rect') | |
| .attr('class', 'revenue') | |
| .attr('x', (function(d) { | |
| return d.x0; | |
| })) | |
| .attr('y', function(d, i) { | |
| return (barHeight + barPadding + statePadding) * d.i; | |
| }) | |
| .attr('width', function(d) { | |
| return xRevenue(d.value); | |
| }) | |
| .attr('height', barHeight) | |
| .style('fill', function(d, i) { return colorRevenue(i); }); | |
| state.append('text') | |
| .attr('class', '.state-name') | |
| .attr('x', function(d) { return d.revenue[0].x0 - 5; }) | |
| .attr('y', function(d,i) { | |
| return (barHeight + barPadding + statePadding) * i + 5; | |
| }) | |
| .attr("dy", ".35em") | |
| .attr("text-anchor", "end") | |
| .style('fill', '#6b6b6b') | |
| .style("font-size", '10px') | |
| .style("text-transform", 'uppercase') | |
| .style("letter-spacing", "1px") | |
| .text(function(d) { return d.name; }); | |
| var expenditure = state.selectAll('rect.expenditure') | |
| .data(function(d, i) { | |
| var total = d3.sum(d.expenditure, function(d1) { return d1.value; }); | |
| d.expenditure.forEach(function(r, j) { | |
| r.i = i; | |
| r.total = total; | |
| r.x0 = j === 0 ? midX - xExpenditure(total)/2 : d.expenditure[j-1].x0 + xExpenditure(d.expenditure[j-1].value); | |
| d.bottomX = d.bottomX === 0 ? r.x0 : d3.min([d.bottomX, r.x0]); | |
| }); | |
| return d.expenditure; | |
| }) | |
| .enter().append('rect') | |
| .attr('class', 'expenditure') | |
| .attr('x', (function(d) { | |
| return d.x0; | |
| })) | |
| .attr('y', function(d, i) { | |
| return (barHeight + barPadding + statePadding) * d.i + (barHeight + barPadding); | |
| }) | |
| .attr('width', function(d) { | |
| return xExpenditure(d.value); | |
| }) | |
| .attr('height', barHeight) | |
| .style('fill', function(d, i) { return colorExpenditure(i); }); | |
| }); | |
| var tooltip_relocate = function() { | |
| var window_top = $(window).scrollTop(); | |
| var div_top = $('.chart').offset().top; | |
| if (window_top > div_top) | |
| $('.tooltip').addClass('stick') | |
| else | |
| $('.tooltip').removeClass('stick'); | |
| } | |
| $(function() { | |
| $(window).scroll(tooltip_relocate); | |
| }) | |
| </script> |