Skip to content

Instantly share code, notes, and snippets.

@ajfarkas
Last active Aug 29, 2015
Embed
What would you like to do?
Range Area Graph

#Range Area Graph This graph shows temperature ranges for each day in May.

The low temperatures are drawn as a clipping path to hide the bottom of the low temperature area. This allows for the use of gradients or photos or whatever you'd like in the background.
The graphs are also generated by a function, so the code is easily reusable. The low temperature graph is drawn with the opposite domain it would usually have: this makes it overlap with the high temperature graph to create a proper clipping path.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
body {
height: 500px;
background: #f98902;
background-image: linear-gradient(
to bottom,
#f98902,
#0083f7
);
}
text { font-size: 4px; }
.title { font-size: 5px; }
line, .domain {
fill: none;
stroke-width: .2;
stroke: black;
}
.max { fill: white; }
</style>
</head>
<body>
<svg width="960px" height="480px" viewBox="0 0 200 100">
</svg>
</body>
<script>
//config
var s = {
width: 200,
height: 100,
m: {
top: 20,
right: 20,
bottom: 25,
left: 30
}
}
s.plot = { w: s.width - s.m.left - s.m.right, h: s.height - s.m.top - s.m.bottom }
//x-axis is always time, y is linear scale
var x = d3.time.scale().range([0, s.plot.w]),
y = d3.scale.linear().range([s.plot.h, 0]),
xAxis = d3.svg.axis().scale(x).orient('bottom').tickSize(2, 0),
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(2, 0),
formatDate = d3.time.format('%Y-%m-%d')
//select svg
var svg = d3.select('svg')
//add group, with margin
svg.append('g')
.attr('class', 'graph')
.attr('width', s.plot.w)
.attr('height', s.plot.h)
.attr('transform', 'translate('+s.m.left+','+s.m.top+')')
//call data
d3.json('./weather.json', function(err, data) {
if (err) return console.error(err)
x.domain([
new Date(d3.min(data, function(d) { return formatDate.parse(d.date) }) - 86400000),
d3.max(data, function(d) { return formatDate.parse(d.date) })
])
// x.domain(d3.extent(data, function(d) { return formatDate.parse(d.date) }) )
y.domain([d3.min(data, function(d) { return d.min }), d3.max(data, function(d) { return d.max }) ])
//account for step-style line graph (add dupe day to beginning of month)
var dLen = data.length,
last = {
date : x.domain()[0].getFullYear()+'-'+(x.domain()[0].getMonth() + 1)+'-'+x.domain()[0].getDate(),
max: data[dLen - 1].max,
min: data[dLen - 1].min
}
data.push(last)
//create clipping path from d.min data
createGraph(data, 'min', 'clipping')
//create area graph from d.max data, clipped by d.min
createGraph(data, 'max', 'min')
//add title
svg.append('text')
.attr('x', s.width/2)
.attr('y', '3em')
.attr('text-anchor', 'middle')
.attr('class', 'title')
.text('Temperature Range in Farenheit')
})
function createGraph(data, accessor, clip) {
//add clipping path, if appropriate
var group = (clip == 'clipping')
? svg.select('.graph')
.append('clipPath')
.attr('id', accessor)
: svg.select('.graph')
group.append('path')
.datum(data)
.attr('class', accessor)
//clip, if appropriate
.attr('clip-path', (clip && clip != 'clipping')
? 'url(#'+clip+')'
: ''
)
//make area graph
.attr('d', d3.svg.area()
.x(function(d) { return x(formatDate.parse(d.date)) })
.y0( (clip == 'clipping')
? y(y.domain()[1])
: y(y.domain()[0])
)
.y1(function(d) { return y(d[accessor]) })
.interpolate('step-after')
)
//make axes, once
if (clip != 'clipping') {
// y-axis
var thisAxisY = group.append('g')
.attr('class', 'y axis')
.call(yAxis)
thisAxisY.selectAll('text')
.attr('dx', 2)
// x-axis
var thisAxisX = group.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,'+s.plot.h+')')
.call(xAxis)
thisAxisX.selectAll('text')
.attr('transform', 'rotate(-90)')
.attr('style', 'text-anchor: end')
.attr('dy', '-.75em')
.attr('dx', '-.75em')
}
}
</script>
</html>
[{ "date":"2015-05-31",
"min":"50.4",
"max":"69.4"
},
{ "date":"2015-05-30",
"min":"56.8",
"max":"83.1"
},
{ "date":"2015-05-29",
"min":"57.9",
"max":"78.8"
},
{ "date":"2015-05-28",
"min":"60.4",
"max":"83.1"
},
{ "date":"2015-05-27",
"min":"55.4",
"max":"86.4"
},
{ "date":"2015-05-26",
"min":"58.8",
"max":"85.5"
},
{ "date":"2015-05-25",
"min":"50.5",
"max":"77.9"
},
{ "date":"2015-05-24",
"min":"37.9",
"max":"78.6"
},
{ "date":"2015-05-23",
"min":"32.9",
"max":"60.1"
},
{ "date":"2015-05-22",
"min":"42.4",
"max":"67.6"
},
{ "date":"2015-05-21",
"min":"40.8",
"max":"71.4"
},
{ "date":"2015-05-20",
"min":"41.5",
"max":"59.5"
},
{ "date":"2015-05-19",
"min":"50.0",
"max":"71.6"
},
{ "date":"2015-05-18",
"min":"50.2",
"max":"69.1"
},
{ "date":"2015-05-17",
"min":"53.8",
"max":"77.5"
},
{ "date":"2015-05-16",
"min":"41.7",
"max":"71.4"
},
{ "date":"2015-05-15",
"min":"31.6",
"max":"74.3"
},
{ "date":"2015-05-14",
"min":"30.2",
"max":"71.6"
},
{ "date":"2015-05-13",
"min":"40.1",
"max":"62.1"
},
{ "date":"2015-05-12",
"min":"47.8",
"max":"76.6"
},
{ "date":"2015-05-11",
"min":"49.1",
"max":"66.6"
},
{ "date":"2015-05-10",
"min":"46.2",
"max":"84.9"
},
{ "date":"2015-05-09",
"min":"44.6",
"max":"70.0"
},
{ "date":"2015-05-08",
"min":"44.8",
"max":"64.2"
},
{ "date":"2015-05-07",
"min":"39.7",
"max":"84.2"
},
{ "date":"2015-05-06",
"min":"34.2",
"max":"77.4"
},
{ "date":"2015-05-05",
"min":"51.3",
"max":"74.3"
},
{ "date":"2015-05-04",
"min":"34.5",
"max":"84.4"
},
{ "date":"2015-05-03",
"min":"32.7",
"max":"73.6"
},
{ "date":"2015-05-02",
"min":"30.9",
"max":"70.5"
},
{ "date":"2015-05-01",
"min":"40.1",
"max":"63.7"
}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment