Skip to content

Instantly share code, notes, and snippets.

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 cmpolis/9516434 to your computer and use it in GitHub Desktop.
Save cmpolis/9516434 to your computer and use it in GitHub Desktop.
$(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