Skip to content

Instantly share code, notes, and snippets.

@antont
Forked from jonmitten/Time Series Multi-Line.md
Created September 10, 2018 10:58
Show Gist options
  • Save antont/e36b60cee14ccc3efc8383b1c40fe79f to your computer and use it in GitHub Desktop.
Save antont/e36b60cee14ccc3efc8383b1c40fe79f to your computer and use it in GitHub Desktop.
Temperature Graph with threshold lines
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
.temperature {
fill: none;
stroke-width: 2px;
}
.temp-probe {
stroke: blue;
}
.ambient {
stroke: #C790E3;
}
.high-threshold {
fill: none;
stroke: red;
stroke-width: 1px;
}
.high-threshold {
fill: none;
stroke: red;
stroke-width: 1px;
}
.low-threshold {
fill: none;
stroke: #67A9FF;
stroke-width: 1px;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<!DOCTYPE html>
<html>
<head>
<title>D3 Sandbox</title>
<link rel="icon" href="data:;base64,iVBORwOKGO=" />
<link rel="stylesheet" href="index.css" />
<script src="http://d3js.org/d3.v4.js"></script>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// parse the date / time
var parseDate = d3.utcParse("%Y-%m-%dT%H:%M:%S.%LZ");
//var parseDate = d3.timeParse("%Y-%m-%d %H:%M:%S");
var formatTime = d3.timeFormat("%e %B");
console.log(parseDate("2018-09-05T05:27:54.212Z")); //2017-09-11 18:35:10"))
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var tempprobe_line = d3.line()
.x( function(d) { return x(d.timestamp); })
.y( function(d) { return y(d.tempprobe); });
var high_threshold_line = d3.line()
.x(function(d){ return x(d.timestamp); })
.y(function(d){ return y(d.threshold_high); });
var low_threshold_line = d3.line()
.x(function(d){
return x(d.timestamp);
})
.y(function(d){
return y(d.threshold_low);
})
var ambient_line = d3.line()
.x(function(d)
{ return x(d.timestamp);}
)
.y( function(d) {
return y(d.ambient);
});
var svg = d3.select("body").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 + ")");
function draw(data, tempdata) {
var data = data[tempdata];
data.forEach(function(d, i) {
d.timestamp = parseDate(d.recvTime);
d.tempprobe = +d.attrValue;
d.ambient = +1 //d.ambient;
});
console.log(data);
data.sort(function(a, b){
return a["timestamp"]-b["timestamp"];
});
// scale the range of data
x.domain(d3.extent(data, function(d){
return d.timestamp;
}));
y.domain([0, d3.max(data, function(d){
return Math.max(d.tempprobe, d.ambient);
})]);
// Add the tempprobe path.
svg.append("path")
.data([data])
.attr("class", "line temp-probe temperature")
.attr("d", tempprobe_line);
// Add the ambient path
svg.append("path")
.data([data])
.attr("class", "line ambient temperature")
.attr("d", ambient_line);
/*svg.append("path")
.data([data])
.attr("class", "line high-threshold")
.attr("d", high_threshold_line)
svg.append("path")
.data([data])
.attr("class", "line low-threshold")
.attr("d", low_threshold_line)*/
// add the X Axis
svg.append("g")
.attr("transform", "translate(0,"+ height + ")")
.call(d3.axisBottom(x));
// add the Y Axis
svg.append("g")
.call(d3.axisLeft(y));
}
d3.json("weather_sth.json",
function(error, data){
if (error){
console.log("an error has occurred in d3 JSON");
throw error;
}
draw(data["contextResponses"][0]["contextElement"]["attributes"][0], "values");
});
[{
"tempdata": [{
"tempprobe": 6.5,
"ambient": 12,
"timestamp": "2017-09-01 18:35:10",
"threshold_high": 8,
"threshold_low": 2
},
{
"tempprobe": 6.4,
"ambient": 24,
"timestamp": "2017-09-01 24:38:01",
"threshold_high": 8,
"threshold_low": 2
},
{
"tempprobe": 6.3,
"ambient": 23,
"timestamp": "2017-09-02 18:40:10",
"threshold_high": 8,
"threshold_low": 2
},
{
"tempprobe": 6.0,
"ambient": 20,
"timestamp": "2017-09-03 18:42:10",
"threshold_high": 8,
"threshold_low": 2
},
{
"tempprobe": 4.9,
"ambient": 15,
"timestamp": "2017-09-03 18:44:10",
"threshold_high": 8,
"threshold_low": 2
},
{
"tempprobe": 6.3,
"ambient": 22.1,
"timestamp": "2017-09-04 18:46:10",
"threshold_high": 8,
"threshold_low": 2
},
{
"tempprobe": 5.8,
"ambient": 21.1,
"timestamp": "2017-09-06 18:48:10",
"threshold_high": 8,
"threshold_low": 2
}
]
}]

A graph that interprets IoT temperature device through time, tracking internal to a refrigerator and external to a refrigerator.

Written in D3, and visible here

Gist available here

{
"contextResponses": [
{
"contextElement": {
"attributes": [
{
"name": "temperature:ae68",
"values": [
{
"recvTime": "2018-09-05T05:27:54.212Z",
"attrType": "Number",
"attrValue": "13"
},
{
"recvTime": "2018-09-05T05:32:54.817Z",
"attrType": "Number",
"attrValue": "10"
},
{
"recvTime": "2018-09-05T05:38:00.840Z",
"attrType": "Number",
"attrValue": "11"
},
{
"recvTime": "2018-09-05T05:43:01.278Z",
"attrType": "Number",
"attrValue": "12"
},
{
"recvTime": "2018-09-05T05:48:01.856Z",
"attrType": "Number",
"attrValue": "13"
},
{
"recvTime": "2018-09-05T05:53:02.172Z",
"attrType": "Number",
"attrValue": "13"
},
{
"recvTime": "2018-09-05T05:58:04.234Z",
"attrType": "Number",
"attrValue": "10"
},
{
"recvTime": "2018-09-05T06:03:04.743Z",
"attrType": "Number",
"attrValue": "13"
},
{
"recvTime": "2018-09-05T06:08:05.291Z",
"attrType": "Number",
"attrValue": "12"
},
{
"recvTime": "2018-09-05T06:13:05.597Z",
"attrType": "Number",
"attrValue": "8"
}
]
}
],
"id": "0e72",
"isPattern": false,
"type": "WeatherObserved"
},
"statusCode": {
"code": "200",
"reasonPhrase": "OK"
}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment