Created
March 12, 2014 21:11
-
-
Save cmpolis/9516434 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(document).on 'page:load', () -> | |
return unless $('#ca-vis').length | |
# | |
margin = { top: 0, right: 60, left: 50, bottom: 100 } | |
width = $('.container').width() - margin.right - margin.left | |
height = 540 - margin.top - margin.bottom | |
colors = ['#8dd3c7', '#E1C368', '#bebada', '#fb8072', '#80b1d3', '#fdb462', | |
'#b3de69', '#fccde5', '#d9d9d9', '#bc80bd', '#ccebc5', '#ffed6f'] | |
months = ['Oct', 'Nov', 'Dec', 'Jan', 'Feb', 'Mar', | |
'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'] | |
# | |
svg = d3.select('#ca-vis') | |
.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})") | |
# | |
d3.csv '/fresno_tpcp.csv', (error, raw) -> | |
waterYears = [] | |
# | |
for ndx in [0...raw.length] by 12 | |
waterYear = { | |
year: parseInt(raw[ndx]['YYYYMM'].substring(0, 4)) | |
months: raw.slice(ndx, ndx+12).map (d) -> parseInt(d['TPCP']) | |
} | |
y0 = 0 | |
waterYear.bars = waterYear.months.map (d, ndx) -> | |
y0prev = y0 | |
{ | |
y0: y0prev, | |
y: (y0 += d), | |
color: colors[ndx], | |
year: waterYear.year | |
mon: ndx | |
} | |
# Calculate totals and averages | |
y0 = 0 | |
waterYear.total = d3.sum(waterYear.months) | |
avgMonths = [0...12].map (d, ndx) -> | |
y0prev = y0 | |
val = d3.mean(waterYears, (d) -> d.months[ndx]) | |
{ val: val, y0: y0prev, y: (y0 += val), color: colors[ndx], mon: ndx } | |
# Moving averages | |
if waterYears.length > 2 | |
waterYear.ma_3 = (waterYear.total + | |
waterYears[waterYears.length-1].total + | |
waterYears[waterYears.length-2].total)/3 | |
if waterYears.length > 4 | |
waterYear.ma_5 = (waterYear.total + | |
waterYears[waterYears.length-1].total + | |
waterYears[waterYears.length-2].total + | |
waterYears[waterYears.length-3].total + | |
waterYears[waterYears.length-4].total)/5 | |
waterYears.push waterYear | |
# | |
maxTotal = d3.max(waterYears, (d) -> d.total) | |
meanTotal = d3.mean(waterYears, (d) -> d.total) | |
# | |
y = d3.scale.linear().range( [height, 0] ) | |
.domain( [0, maxTotal] ) | |
x = d3.scale.linear().range( [0, width] ) | |
.domain( [1931, 2014] ) | |
barWidth = (width / (2015 - 1932)) - 1 | |
# | |
xAxis = d3.svg.axis().scale(x) | |
.orient('bottom') | |
.tickValues([1941, 1951, 1961, 1971, 1981, 1991, 2001, 2011]) | |
.tickFormat((d) -> d-1) | |
yAxis = d3.svg.axis().scale(y) | |
.ticks(10) | |
.tickFormat((d) -> (d/100)) | |
.orient('left') | |
# | |
ma_3 = d3.svg.line().x((d) -> x(d.year)) | |
.y((d) -> y(d.ma_3)) | |
ma_5 = d3.svg.line().x((d) -> x(d.year)) | |
.y((d) -> y(d.ma_5)) | |
# | |
svg.append('g') | |
.attr('class', 'x axis') | |
.attr('transform', "translate(0, #{height})") | |
.call(xAxis) | |
svg.append('g') | |
.attr('class', 'y axis') | |
.call(yAxis) | |
# Year groups, month bars | |
year = svg.selectAll('g.yearBars').data(waterYears) | |
.enter().append('g') | |
.attr('class', (d) -> "yearBars #{d.year}") | |
.attr('opacity', 0.6) | |
.attr('transform', (d) -> "translate(#{x(d.year) + barWidth/2},0)") | |
.on('mouseover', (d) -> | |
d3.select(@).attr('opacity', 1) | |
d3.select('.typical') | |
.attr("d", "M 0 #{y(d.bars[4].y)} H #{width + barWidth + 10}") | |
d3.select('.year-label').text("#{d.year}:") | |
d3.select('.total-value').text("#{d3.round((d.total/100), 2)}") | |
d3.selectAll('text.month-value').data(d.months) | |
.text((d) -> d3.round((d/100), 2)) | |
).on('mouseout', (d) -> | |
d3.select(@).attr('opacity', 0.6) | |
) | |
year.selectAll('rect').data((d) -> d.bars) | |
.enter().append('rect') | |
.attr('opacity', (d) -> | |
return 0.5 if d.year == 2013 and d.mon > 4 | |
1 ) | |
.attr('width', barWidth) | |
.attr('y', (d) -> y(d.y)) | |
.attr('height', (d) -> y(d.y0) - y(d.y)) | |
.attr('fill', (d) -> d.color) | |
# Average months | |
meanGroup = svg.append('g') | |
.attr('class', 'mean-group') | |
.attr('opacity', 0.6) | |
.on('mouseover', (d) -> | |
d3.select(@).attr('opacity', 1) | |
d3.select('.typical') | |
.attr("d", "M 0 #{y(721)} H #{width + barWidth + 10}") | |
d3.select('.year-label').text("Mean:") | |
d3.select('.total-value').text("#{d3.round((meanTotal/100), 2)}") | |
d3.selectAll('text.month-value').data(avgMonths) | |
.text((d) -> d3.round((d.val/100), 2)) | |
).on('mouseout', (d) -> | |
d3.select(@).attr('opacity', 0.6) | |
) | |
.selectAll('rect.avg-month').data(avgMonths) | |
.enter().append('rect') | |
.attr('class', (d) -> "avg-month #{d}") | |
.attr('width', barWidth) | |
.attr('x', (d) -> width + 10) | |
.attr('y', (d) -> y(d.y)) | |
.attr('height', (d) -> y(d.y0) - y(d.y)) | |
.attr('fill', (d) -> d.color) | |
# Moving averages, mean line | |
svg.append("path").attr("class", "mean") | |
.attr("d", "M 0 #{y(meanTotal)} H #{width + barWidth + 10}") | |
svg.append("path").attr("class", "current") | |
.attr("d", "M 0 #{y(283)} H #{width + barWidth + 10}") | |
svg.append("path").attr("class", "typical") | |
.attr("d", "M 0 #{y(721)} H #{width + barWidth + 10}") | |
svg.append("path").datum(waterYears.slice(5, waterYears.length)) | |
.attr("class", "ma ma-five") | |
.attr("d", ma_5) | |
.attr("transform", "translate(#{barWidth},0)") | |
.on('mouseover', (d) -> | |
d3.select(@).attr('opacity', 1) | |
).on('mouseout', (d) -> | |
d3.select(@).attr('opacity', 0.8) | |
) | |
svg.append("path").datum(waterYears.slice(3, waterYears.length)) | |
.attr("class", "ma ma-three") | |
.attr("d", ma_3) | |
.attr("transform", "translate(#{barWidth},0)") | |
.on('mouseover', (d) -> | |
d3.select(@).attr('opacity', 1) | |
).on('mouseout', (d) -> | |
d3.select(@).attr('opacity', 0.9) | |
) | |
# Axis, mean labels | |
svg.append("text") | |
.attr('class', 'x-label') | |
.attr('text-anchor', 'middle') | |
.attr('transform', "translate(#{width/2}, #{height + 40})") | |
.text('Water Year (Oct. 1 of given year to Sept. 31 of next year)') | |
svg.append("text") | |
.attr('class', 'y-label') | |
.attr('text-anchor', 'middle') | |
.attr('transform', "translate(-30, #{height/2}) rotate(270)") | |
.text('Precipitation in Inches') | |
svg.append("text") | |
.attr('class', 'mean-label') | |
.attr('text-anchor', 'middle') | |
.attr('transform', "translate(#{width + 20}, 150) rotate(270)") | |
.text('Mean values (1931 to 2013)') | |
# Month/color labels | |
svg.selectAll('rect.month-rect').data(months) | |
.enter().append('rect') | |
.attr('class', (d) -> "month-rect #{d}") | |
.attr('opacity', 0.6) | |
.attr('width', width/12) | |
.attr('x', (d, ndx) -> ndx * width / 12) | |
.attr('y', (d) -> height + 60) | |
.attr('height', 20) | |
.attr('fill', (d, ndx) -> colors[ndx]) | |
svg.selectAll('text.month-label').data(months) | |
.enter().append('text') | |
.attr('class', (d) -> "month-label #{d}") | |
.attr('text-anchor', 'middle') | |
.attr('x', (d, ndx) -> (ndx+.5) * width / 12) | |
.attr('y', (d) -> height + 74) | |
.text((d) -> d) | |
if width > 440 | |
svg.selectAll('text.month-value').data(avgMonths) | |
.enter().append('text') | |
.attr('class', (d) -> "month-value #{d}") | |
.attr('text-anchor', 'middle') | |
.attr('x', (d, ndx) -> (ndx+.5) * width / 12) | |
.attr('y', (d) -> height + 94) | |
.text((d) -> d3.round((d.val/100), 2)) | |
svg.append('text') | |
.attr('class', 'total-label') | |
.attr('text-anchor', 'middle') | |
.attr('x', (d) -> width + 28) | |
.attr('y', (d) -> height + 74) | |
.text('Total') | |
svg.append('text') | |
.attr('class', 'year-label') | |
.attr('text-anchor', 'middle') | |
.attr('x', (d) -> -30) | |
.attr('y', (d) -> height + 94) | |
.text('Mean:') | |
svg.append('text') | |
.attr('class', 'total-value') | |
.attr('text-anchor', 'middle') | |
.attr('x', (d) -> width + 28) | |
.attr('y', (d) -> height + 94) | |
.text((d) -> d3.round((meanTotal/100), 2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment