Simple plot of blood pressure in a heart over a short period of time.
Built with blockbuilder.org
forked from lwthatcher's block: Blood Pressure Waveform
license: mit |
Simple plot of blood pressure in a heart over a short period of time.
Built with blockbuilder.org
forked from lwthatcher's block: Blood Pressure Waveform
value | |
81.885 | |
81.484 | |
81.129 | |
80.822 | |
80.562 | |
80.351 | |
80.189 | |
80.077 | |
80.014 | |
80.014 | |
80.077 | |
80.189 | |
80.351 | |
80.562 | |
80.822 | |
81.129 | |
81.484 | |
81.885 | |
82.331 | |
82.821 | |
83.355 | |
83.930 | |
84.545 | |
85.198 | |
85.889 | |
86.615 | |
87.375 | |
88.166 | |
88.986 | |
89.834 | |
90.708 | |
91.605 | |
92.522 | |
93.459 | |
94.412 | |
95.378 | |
96.357 | |
97.344 | |
98.338 | |
99.336 | |
100.336 | |
101.335 | |
102.331 | |
103.321 | |
104.302 | |
105.273 | |
106.231 | |
107.173 | |
108.097 | |
109.001 | |
109.882 | |
110.739 | |
111.569 | |
112.370 | |
113.140 | |
113.877 | |
114.579 | |
115.245 | |
115.873 | |
116.462 | |
117.009 | |
117.513 | |
117.974 | |
118.390 | |
118.760 | |
119.083 | |
119.358 | |
119.585 | |
119.763 | |
119.892 | |
119.971 | |
120.000 | |
119.991 | |
119.833 | |
119.477 | |
118.926 | |
118.186 | |
117.264 | |
116.170 | |
114.914 | |
113.509 | |
111.969 | |
110.310 | |
108.548 | |
106.700 | |
104.785 | |
102.822 | |
100.000 | |
101 | |
101.9 | |
102.7 | |
103.4 | |
104 | |
104.5 | |
104.9 | |
105.3 | |
105.5 | |
105.399 | |
105.110 | |
104.766 | |
104.370 | |
103.922 | |
103.426 | |
102.882 | |
102.295 | |
101.665 | |
100.997 | |
100.293 | |
99.556 | |
98.790 | |
97.998 | |
97.183 | |
96.349 | |
95.501 | |
94.641 | |
93.774 | |
92.904 | |
92.034 | |
91.168 | |
90.310 | |
89.465 | |
88.635 | |
87.825 | |
87.038 | |
86.278 | |
85.548 | |
84.852 | |
84.192 | |
83.572 | |
82.994 | |
82.460 | |
81.975 | |
81.538 | |
81.153 | |
80.821 | |
80.544 | |
80.323 | |
80.159 | |
80.052 | |
80.003 | |
80.013 | |
80.081 | |
80.207 | |
80.390 | |
80.630 | |
80.925 | |
81.275 | |
81.677 | |
82.130 | |
82.600 |
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
.axis { | |
font: 10px sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.axis--match text{ | |
fill: purple; | |
} | |
.line { | |
fill: none; | |
stroke: red; | |
stroke-width: 1.5px; | |
} | |
.bar { | |
fill: purple; | |
opacity: .5; | |
} | |
.bar:hover { | |
fill: red; | |
opacity: .7; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var margin = {top: 20, right: 50, bottom: 30, left: 50}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var svg = d3.select("body").append("svg") | |
.attr("width", 960) | |
.attr("height", 500) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var x = d3.scaleLinear() | |
.range([0, width]); | |
var y = d3.scaleLinear() | |
.range([height, 0]); | |
var y2 = d3.scaleLinear() | |
.range([height, 0]); | |
var line = d3.line() | |
.x(d => x(d.t)) | |
.y(d => y(d.value)); | |
var matched = d3.area() | |
.curve(d3.curveMonotoneX) | |
.x(d => x(d.t)) | |
.y0(height) | |
.y1(d => y2(d.match)); | |
var notch_idx = 87; | |
var template_size = 3; | |
d3.csv("data.dat", type, (err, data) => { | |
if (err) throw err; | |
let template = rangeAround(data, notch_idx, template_size); | |
console.log("template", template); | |
template = normalize(template); | |
check(template) | |
console.info("normalized template", template); | |
data = convolve(data, template); | |
// console.log('data', data); | |
x.domain(d3.extent(data, d => d.t)); | |
y.domain(d3.extent(data, d => d.value)); | |
y2.domain(d3.extent(data, d => Math.max(d.match, 0))); | |
svg.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate(0," + height + ")") | |
.call(d3.axisBottom(x)); | |
svg.append("g") | |
.attr("class", "axis axis--y") | |
.call(d3.axisLeft(y)); | |
svg.append("g") | |
.attr("class", "axis axis--match") | |
.attr("transform", "translate( " + width + ", 0 )") | |
.call(d3.axisRight(y2)); | |
// Blood Pressure | |
svg.append("path") | |
.datum(data) | |
.attr("class", "line") | |
.attr("d", line); | |
// Match | |
// svg.append("path") | |
// .datum(data) | |
// .attr("class", "match") | |
// .attr("d", matched); | |
var bars = svg.append("g") | |
bars.selectAll(".bar") | |
.data(data) | |
.enter().filter(d => "match" in d).append("rect") | |
.attr("class", "bar") | |
.attr("x", function(d) { return x(d.t) -2.5; }) | |
.attr("y", function(d) { return y2(d.match); }) | |
.attr("width", 5) | |
.attr("height", (d) => {return Math.max(height - y2(d.match), 0);}) | |
.on("mouseover", mouseover) | |
function mouseover(d) { | |
console.log("d", d); | |
} | |
}); | |
function type(d, i) { | |
d.value = +d.value; | |
d.t = i; | |
return d; | |
} | |
function check(template) { | |
sum = 0; | |
template.forEach(t => { | |
sum += t.value; | |
}) | |
console.info("sum", sum); | |
} | |
function rangeAround(data, idx, size) { | |
var side = Math.floor(size/2); | |
var result = []; | |
for (var i = idx-side; i <= idx+side; i++) { | |
result.push(data[i]); | |
} | |
return result; | |
} | |
function normalize(values) { | |
var result = []; | |
var side = Math.floor(values.length/2); | |
var ave = d3.mean(values, d => d.value); | |
console.log("average", ave); | |
var j = -side; | |
values.forEach(d => { | |
var val = d.value - ave | |
result.push({value: val, offset: j}); | |
j++; | |
}) | |
return result; | |
} | |
function convolve(data, template) { | |
var side = Math.floor(template.length/2); | |
for (var i = 0; i < data.length; i++) { | |
if (i + side < data.length && i - side >= 0) | |
{ | |
var sum = 0; | |
template.forEach(t => { | |
var j = i + t.offset; | |
sum += (data[j].value * t.value); | |
}) | |
data[i]["match"] = sum; | |
} | |
} | |
return data; | |
} | |
</script> | |
</body> |