Skip to content

Instantly share code, notes, and snippets.

@mohdali
Last active June 16, 2017 10:04
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 mohdali/122828904e71aba94e95f8053435666f to your computer and use it in GitHub Desktop.
Save mohdali/122828904e71aba94e95f8053435666f to your computer and use it in GitHub Desktop.
Distributed Temperature Sensor
license: mit
height: 400

Distributed Temperature Sensors can provide continous temperature readings over a long distance using fiber optic technologies. They have many industrial applications such as leak detection, fire detection, and down-hole monitoring of wells in oil & gas industry.

A common visualization for DTS is the temperature profile along the cable distance. By observing unexpected rise or drop in temperatures, users can find issues such as leaks in pipelines or fires.

Note: Visualization is conceptual only and is using randomized values.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>DTS</title>
<script src="https://d3js.org/d3.v4.min.js" type="text/javascript"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" type="text/javascript"></script>
<style type="text/css">
body {
color: #444;
font: 10px sans-serif;
}
svg {
font: 10px sans-serif;
}
text {
fill: #444;
}
.points circle {
stroke: #000;
stroke-width: 1px;
}
.boundary {
stroke: none;
fill: rgba(0, 0, 0, 0);
}
.point:hover circle {
stroke: red;
stroke-width: 3px;
}
rect.key {
stroke-width: 0px;
opacity: 0.4;
}
path.line {
fill: none;
stroke: black;
stroke-width: 3px;
}
line.grid {
fill: none;
shape-rendering: crispEdges;
stroke: white;
stroke-width: 1px;
}
line.threshold {
fill: none;
shape-rendering: crispEdges;
stroke: darkred;
stroke-width: 2px;
}
line.cursor {
stroke: grey;
stroke-width: 1px;
stroke-dasharray: 2, 2;
}
.clabel rect {
stroke: red;
fill: white;
}
.clabel text {
text-anchor: middle;
font-size: 9px;
}
.caption {
text-anchor: middle;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.points text {
margin-left: -5px;
}
</style>
</head>
<body>
<div class="container">
<div id="plot"></div>
</div>
<script type="text/javascript">
var margin = { top: 10, right: 10, bottom: 40, left: 40 },
width = 880,
height = 300,
distance = 100,
min = -40,
max = 100,
threshold = 65;
var voronoi = d3.voronoi()
.extent([[-1, -1], [width + 1, height + 1]]);
var color = d3.scaleLinear()
.domain([min, 15, max])
.range(["#4575b4", "#ffffbf", "#a50026"])
.interpolate(d3.interpolateHcl);
var x = d3.scaleLinear().domain([0, distance]).range([0, width]),
y = d3.scaleLinear().domain([min, max]).range([height, 0]);
var xAxis = d3.axisBottom().scale(x),
yAxis = d3.axisLeft().scale(y);
var val = d3.randomNormal(30, 10),
delta = d3.randomNormal(0, 0.5),
data = d3.range(distance).map(function (x) { return [x, val()]; }),
xValue = function (d) { return x(d[0]); },
yValue = function (d) { return y(d[1]); },
textValue = function (d) { return d[1].toFixed(2); };
var line = line = d3.line()
.x(xValue)
.y(yValue);
var svg = d3.select("#plot").append("svg")
.attrs({
"width": width + margin.left + margin.right,
"height": height + margin.top + margin.bottom
});
var plot = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
plot.selectAll(".key")
.data(pair(y.ticks(40)))
.enter().append("rect")
.attrs({
"class": "key",
"width": width,
"x": 0,
"y": function (d) { return y(d[1]); },
"height": function (d) { return y(d[0]) - y(d[1]); },
"fill": function (d) { return color((d[0] + d[1]) / 2); }
});
plot.selectAll("line.hgrid")
.data(y.ticks(10))
.enter().append("line")
.attrs({
"class": "hgrid grid",
"x1": 0,
"x2": width,
"y1": function (d) { return y(d); },
"y2": function (d) { return y(d); }
});
plot.selectAll("line.vgrid")
.data(x.ticks(20))
.enter().append("line")
.attrs({
"class": "vgrid grid",
"y1": 0,
"y2": height,
"x1": function (d) { return x(d); },
"x2": function (d) { return x(d); }
});
plot.append("line")
.attrs({
"class": "threshold",
"x1": 0,
"x2": width,
"y1": y(threshold),
"y2": y(threshold)
});
plot.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis)
.append("text")
.text("Distance (Km)")
.attrs({
"class": "caption",
"x": width / 2,
"y": 35
});
plot.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.text("Temperature \u00B0C")
.attrs({
"transform": "rotate(90)",
"class": "caption",
"x": height / 2,
"y": 35
});
var graph = plot.append("path")
.attr("class", "line")
.datum(data)
.attr("d", line);
var vlabel = svg.append("g")
.attrs({
"class": "clabel vlable",
"transform": "translate(10," + height / 2 + ")"
})
.style("display", "none");
vlabel.append("rect")
.attrs({
"rx": 5,
"ry": 5,
"width": 30,
"height": 20
});
vlabel.append("text")
.attrs({
"x": 15,
"y": 15
});
var hlabel = svg.append("g")
.attrs({
"class": "clabel hlable",
"transform": "translate(" + width / 2 + "," + (height + margin.top) + ")"
})
.style("display", "none");
hlabel.append("rect")
.attrs({
"rx": 5,
"ry": 5,
"width": 30,
"height": 20
});
hlabel.append("text")
.attrs({
"x": 15,
"y": 15
});
plot.append("line")
.attrs({
"class": "cursor vcursor",
"y1": 0,
"y2": height,
})
.style("display", "none");
plot.append("line")
.attrs({
"class": "cursor hcursor",
"x1": 0,
"x2": width,
})
.style("display", "none");
var points = plot.append("g")
.attr("class", "points");
update();
setInterval(update, 1000);
plot.on("mousemove", function () {
selectPoint();
});
plot.on("mouseleave", function () {
plot.selectAll(".cursor")
.style("display", "none");
svg.selectAll(".clabel")
.style("display", "none");
});
function pair(array) {
return array.slice(1).map(function (b, i) {
return [array[i], b];
});
}
function update() {
var deltaT = d3.range(distance).map(function (x) { return [x, delta()]; });
data = data.map(function (x, i) { return [x[0], Math.min(max, Math.max(min, x[1] + deltaT[i][1]))]; });
var p = data.map(function (d) { return [x(d[0]), y(d[1])] });
var cells = voronoi.polygons(p);
graph.datum(data)
.transition().duration(500)
.attr("d", line);
var circles = points.selectAll("g.point")
.data(data);
var point = circles.enter()
.append("g")
.attr("class", "point");
point.append("circle")
.attr("r", 5);
point.append("path")
.attr("class", "boundary");
circles.select("circle")
.transition().duration(500)
.attr("cx", xValue)
.attr("cy", yValue)
.attr("fill", function (d) { return color(d[1]) });
circles.select("path")
.attr("d", function (d, i) { return "M" + cells[i].join("L") + "Z"; });
circles.exit().remove();
selectPoint();
}
function selectPoint() {
var k = points.select(".point:hover circle");
if (k.size() > 0) {
var h = points.select(".point:hover").data()[0];
var t = [k.attr("cx"), k.attr("cy")];
hlabel.attr("transform", "translate(" + (t[0] + 25) + "," + (height + margin.top) + ")")
.style("display", t[0] > 0 ? null : "none")
.select("text")
.text(h[0].toFixed(2));
plot.select(".vcursor")
.attrs({
"x1": t[0],
"x2": t[0]
})
.style("display", t[0] > 0 ? null : "none");
vlabel.attr("transform", "translate(10," + t[1] + ")")
.style("display", t[1] > 0 ? null : "none")
.select("text")
.text(h[1].toFixed(2));
plot.select(".hcursor")
.attrs({
"y1": t[1],
"y2": t[1]
})
.style("display", t[1] > 0 ? null : "none");
}
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment