// console.clear() d3.select('body').selectAppend('div.tooltip.tooltip-hidden') var months = [] years.forEach(year => { year.months .forEach((d, i) => months.push({year: year.year, tmp: d, month: i})) }) byMonth = d3.nestBy(months, d => d.month) byMonth.forEach(month => { month.forEach((d, i) => { d.rolling = d3.mean(month.slice(i - 10, i + 1), d => d.tmp) }) var monthReg = month.map(d => [d.year, d.tmp]) month.l = ss.linearRegressionLine(ss.linearRegression(monthReg)) month.min = d3.min(month, d => d.tmp) if (month.key == 1) month.min += 2 if (month.key == 0) month.min += .6 }) var sel = d3.select('#graph').html('') var c = d3.conventions({sel, margin: {left: 40}}) c.x.domain([0, 12]) c.y.domain(d3.extent(months, d => d.tmp)) c.svg.appendMany('rect', d3.range(12)) .at({ width: c.x(1), x: d => c.x(d), height: c.height, opacity: d => d % 2 ? .04 : .08 }) c.xAxis .tickFormat(i => 'Jan Feb March April May June July Aug Sept Oct Nov Dec'.split(' ')[i]) .tickValues(d3.range(12)) c.yAxis .ticks(6) .tickSize(c.width) .tickFormat(d => d + '° C') d3.drawAxis(c) c.svg.select('.x') .translate(0, 0) .selectAll('.tick') .translate(d => [c.x(d + .5), c.y(byMonth[d].min)]) c.svg.selectAll('.y') .translate(c.width, 0) var pad = innerWidth < 500 ? 3 : 10 var yearScale = d3.scaleLinear() .domain(d3.extent(years, d => d.year)) .range([pad, c.x(1) - pad]) var line = d3.line() .x(d => yearScale(d.year)) .y(d => c.y(d.rolling)) .curve(d3.curveStep) .defined(d => !isNaN(d.rolling)) var monthSel = c.svg.appendMany('g', byMonth) .translate(d => c.x(d.key), 0) monthSel .append('path') .at({ d: line, stroke: '#000', fill: 'none', strokeWidth: .0, }) var y0 = years[0].year var y1 = 2017 monthSel.append('path') .at({ d: d => `M ${yearScale(y0)} ${c.y(d.l(y0))} L ${yearScale(y1)} ${c.y(d.l(y1))}`, stroke: '#f0f', strokeWidth: 3, fill: '#f0f' }) .attr('marker-end', 'url(#arrow)') months.forEach(d => delete d.rolling) var circleSel = monthSel .appendMany('circle', d => d) .at({ r: .7, strokeWidth: 5, stroke: d => d.year == 1881 ? 'steelblue' : d.year == 2017 ? 'orange' : '#f00', strokeOpacity: d => d.year == 1881 || d.year == 2017 ? .5 : .01, stroke: '#f00', strokeOpacity: .01, opacity: innerWidth < 500 ? .7 : 1, cx: d => yearScale(d.year), cy: d => c.y(d.tmp) }) .call(d3.attachTooltip) .on('mouseover', d => { circleSel .classed('active', e => e.year == d.year) }) .on('mouseout', d => { circleSel.classed('active', 0) }) // .classed('active', d => d.year == 1881 || d.year == 2017) var octSel = monthSel.filter(d => d.key == 9) octSel.append('g') .translate(d => [pad - 27, c.y(d[0].tmp) + 2]) .append('text.anno').text(1881) .at({textAnchor: 'end', dy: '-.3em', fontSize: 10, dx: 10, opacity: .6}) .parent() .append('path') .at({ d: 'M 0,0 A 13.09 13.09 0 1 0 26,1', stroke: '#ccc', fill: 'none', }) octSel.append('g') .translate(d => [c.x(1) - pad, c.y(d[136].tmp) - 2]) .append('text.anno').text(2017) .at({textAnchor: 'start', dy: '1em', fontSize: 10, dx: 14, opacity: .6}) .parent() .append('path') .at({ d: 'M 0,0 A 13.09 13.09 0 1 1 26,1', stroke: '#ccc', fill: 'none', }) c.svg.append('marker') .attr('id', 'arrow') .attr('viewBox', '-10 -10 20 20') .attr('markerWidth', 17) .attr('markerHeight', 17) .attr('orient', 'auto') .append('path') .attr('d', 'M4,0 L0,-2 L 0,2Z') .at({ fill: '#f0f' })