Animating patient flow
-
-
Save jtibbutt/dca065935bee334dee5587a940ca355f to your computer and use it in GitHub Desktop.
Animation of patient movements
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<head> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"> | |
</head> | |
<style> /* set the CSS */ | |
body { font: 15px Arial;} | |
.button { | |
fill: lightblue; | |
opacity: 0; | |
text-decoration: underline; | |
} | |
.bed { | |
stroke: white; | |
stroke-width: 1; | |
fill-opacity: 0.5; | |
fill : lightgrey; | |
} | |
div.tooltip { | |
position: absolute; | |
text-align: left; | |
width: 200px; | |
height: 80px; | |
padding: 8px; | |
font: 15px Arial; | |
background: rgba(255,255,255,0.7); | |
# border: solid 1px #aaa; | |
pointer-events: none; | |
font-style: italic; | |
} | |
path { | |
stroke: grey; | |
stroke-width: 1.5; | |
fill: none; | |
} | |
.ward { | |
stroke-width: 1; | |
fill-opacity: 0.1; | |
fill: none; | |
} | |
.wardname{ | |
font: 14px Arial bold; | |
} | |
.slider { | |
position: relative; | |
top: 12px; | |
left: 600px; | |
} | |
.slider-tray { | |
position: absolute; | |
width: 100%; | |
height: 6px; | |
border-top-color: #aaa; | |
border-radius: 4px; | |
background-color: lightgrey; | |
} | |
.slider-handle { | |
position: absolute; | |
top: 3px; | |
} | |
.slider-handle-icon { | |
width: 14px; | |
height: 14px; | |
border: solid 1px #aaa; | |
position: absolute; | |
border-radius: 10px; | |
background-color: #fff; | |
top: -8px; | |
left: -8px; | |
} | |
</style> | |
<body> | |
<!-- load the d3.js library --> | |
<script src="//d3js.org/d3.v3.min.js"></script> | |
<script src="https://momentjs.com/downloads/moment.js"></script> | |
<p id="time"></p> | |
<div class="slider"></div> | |
<script> | |
// load real wards - 0.5 | |
// add real connect patients to beds with middocc data | |
// step through ward moves updating occupancy | |
// add timer and timer buttons to control movement | |
// highlight patients with different attributes - adm type, los, age, pathway etc | |
// charts to tooltip? | |
// | |
// variables for circle and rect sizes | |
var r;// = 6; | |
var h = 96; | |
var w = 96; | |
var now; | |
var starttime; | |
var endtime; | |
var increment; | |
var speed;// = 200; | |
var dur;// = 1000; | |
var timervar; | |
var running = false; | |
var colourCategory = 1; | |
var positionCategory = 1; | |
var slidermax = 500; | |
var slidermin = 100; | |
var tooltopOffsetX = 15; | |
var tooltopOffsetY = 15; | |
var width = 100; | |
var x = d3.scale.linear() | |
.domain([slidermax, slidermin]) | |
.range([0, width]) | |
.clamp(true); | |
var dispatch = d3.dispatch("sliderChange"); | |
var slider = d3.select(".slider").style("width", width + "px"); | |
var sliderTray = slider.append("div").attr("class", "slider-tray"); | |
var sliderHandle = slider.append("rect").attr("class", "slider-handle"); | |
sliderHandle.append("div").attr("class", "slider-handle-icon") | |
slider.call(d3.behavior.drag() | |
.on("dragstart", function() { | |
dispatch.sliderChange(x.invert(d3.mouse(sliderTray.node())[0])); | |
d3.event.sourceEvent.preventDefault(); | |
}) | |
.on("drag", function() { | |
dispatch.sliderChange(x.invert(d3.mouse(sliderTray.node())[0])); | |
}) | |
) | |
// create custom sub-selections by adding methods to d3.selection.prototype | |
// allows me to select last (and first but not needed) patient circle when shuffling | |
// patients to fill gaps | |
// | |
d3.selection.prototype.last = function() { | |
var last = this.size() - 1; | |
return d3.select(this[0][last]); | |
}; | |
d3.selection.prototype.first = function() { | |
return d3.select(this[0][0]); | |
}; | |
// svg layout | |
// | |
var margin = {top: 30, right: 20, bottom: 30, left: 30}, | |
width = 1750 - margin.left - margin.right, | |
height = 1050 - margin.top - margin.bottom; | |
// Adds the svg canvas | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
// initialise lookups | |
// | |
var patientLookup={}; | |
var wardLookup={}; | |
var movesLookup={}; | |
var wardcoloursLookup = {}; | |
// Get the data | |
d3.json("IPdataClean2.json", function(error, data) { | |
if (error) throw error; | |
dispatch.on("sliderChange.slider", function(value) { | |
sliderHandle.style("left", x(value) + "px") | |
console.log(parseInt(value)); | |
if(running){ | |
pause(); | |
speed = parseInt(value); | |
startresume(); | |
} else { | |
speed = parseInt(value); | |
} | |
}) | |
svg.append("text") | |
.attr("x", 450) | |
.attr("y", 20) | |
.text("Speed up/slow down") | |
// define time vars | |
// | |
now = moment(data.starttime, data.timeformat); | |
d3.select('p[id="time"]').text(now.format("DD/MM/YY HH:mm")); | |
starttime = moment(data.starttime, data.timeformat); | |
endtime = moment(data.endtime, data.timeformat); | |
increment = 1; // number of minutes to increment each tick of the timer | |
speed = data.speed; | |
r = data.radius; | |
dur = data.transduration; | |
// ward data lookup indexed by ward name | |
// | |
data.wards.forEach( function(d) { | |
wardLookup[d.name]=d; | |
}) | |
data.wardcolours.forEach (function(d) { | |
wardcoloursLookup[d.division] = d; | |
}) | |
// initialise moves lookup, indexed by time | |
// | |
data.moves.forEach( function(m) { | |
m.time = moment(m.time, data.timeformat); | |
if(!movesLookup[m.time]) | |
movesLookup[m.time]=[]; | |
movesLookup[m.time].push(m); | |
}) | |
// create g elements as placeholders for the wards | |
// and to avoid having to translate all the rects, texts and lines | |
// | |
var gWard = svg.selectAll("g") | |
.data(data.wards) | |
.enter().append("g") | |
.attr("id", function(d){ return d.name}) | |
.attr("class", "wardcontainer") | |
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"}) | |
; | |
// rect to provide outline around entire block | |
// | |
wards = gWard.selectAll() | |
.data(data.wards) | |
.enter().append("rect") | |
.filter( function(d) { return d.name == this.parentNode.id }) | |
.attr("class", "ward") | |
.attr("height", h) | |
.attr("width", w) | |
.attr("stroke", "lightgrey") | |
// .attr("stroke", function(d) { return wardcoloursLookup[d.division].colour; }) | |
// .attr("fill", function(d) { | |
// return wardcoloursLookup[d.division].colour ; | |
// }) | |
; | |
// add bed elements to each ward | |
// | |
data.wards.forEach( function(d) | |
{ | |
var currRow = 0; | |
var currCol = 0; | |
var currward = svg.select("g#" + d.name); | |
// loop through each possible bed as defined by the ward | |
// | |
for( i=0; i < d.maxbeds; i++) | |
{ | |
// limit number of columns in bed grid to 8 | |
// | |
if(currCol>=8) | |
{ | |
currCol=0; | |
currRow++; | |
} | |
// g element to hold the bed | |
// | |
var currg = currward.append("g") | |
.attr("id", function(){return "b" + (i+1);}) | |
.attr("transform", function(){ return "translate(" + (12*currCol) + "," + (h-12 - 12*currRow) + ")"}) | |
// add a rect to the element | |
// | |
currg.append("rect") | |
.attr("id", function(){return "b" + (i+1);}) | |
.attr("class", "bed") | |
.attr("height", "12") | |
.attr("width", "12") | |
; | |
currCol++; | |
} | |
}) | |
// populate beds with midnight patient data | |
// | |
data.midnight.forEach( function(pt) | |
{ | |
patientLookup[pt.ID] = pt; | |
// if not yet admitted patient, populate the wards with the patients at midnight | |
if(pt.currLocn != "Admission") | |
{ | |
addPatient(pt, wardLookup[pt.currLocn]); | |
} | |
}) | |
// Add text label to each ward | |
// | |
gWard.selectAll("text") | |
.data(data.wards) | |
.enter().append("text") | |
.filter( function(d) { return d.name == this.parentNode.id }) | |
.attr("id", function(d){ return d.name}) | |
.attr("class", "wardname") | |
.style("fill", function(d) { return wardcoloursLookup[d.division].colour; }) | |
// .style("fill", "grey") | |
// .style("fill-opacity", 0.7) | |
.text(function(d){return d.name;}) | |
.attr("transform", function(d) { return "translate(2,15)"}) | |
.on("mouseover", function(d) { | |
showtooltip( | |
"Ward: <t>" + d.name + | |
"<br>Division: <t>" + d.division + | |
"<br>Occupancy: " + d.count + "/" + d.maxbeds, | |
(d3.event.pageX + 20) + "px", | |
(d3.event.pageY + 20) + "px"); | |
}) | |
.on("mouseout", function(d) { hidetooltip(); }) | |
; | |
// Play button label | |
svg.append("text") | |
.attr("x", 5) | |
.attr("y", 20) | |
.text("Play") | |
// Play button | |
// | |
svg.append("rect") | |
.attr("class", "button") | |
.attr("id", "button") | |
.attr("height", "32") | |
.attr("width", "52") | |
.attr("x", 0) | |
.attr("y", 0) | |
.on("click", function(){ | |
var buttonText = ""; | |
d3.selectAll("text").filter(function() { | |
return /Play|Pause/.test(d3.select(this).text()); | |
}) | |
.text( function() { | |
if(!running){ | |
buttonText = "Pause"; | |
startresume(); | |
}else{ | |
buttonText=" Play"; | |
pause(); | |
} | |
return buttonText; | |
}); | |
}) | |
.on("mouseover", function(d) { | |
showtooltip("Play - start the timer. Patients will move in and out of beds - use the slider to speed up and slow down.", | |
(d3.event.pageX + tooltopOffsetX) + "px", | |
(d3.event.pageY + tooltopOffsetY) + "px"); | |
}) | |
.on("mouseout", function(d) { hidetooltip(); }) | |
// play function | |
// | |
function startresume(){ | |
if(!running){ | |
d3.select("i[id=playpause]").attr("class", "fa fa-pause fa-lg") | |
timevar = setInterval(function(){ updatePositions() }, speed); | |
running = true; | |
console.log("play"); | |
} | |
} | |
// Pause function | |
// | |
function pause(){ | |
if(running){ | |
d3.select("i[id=playpause]").attr("class", "fa fa-play fa-lg") | |
clearInterval(timevar); | |
d3.select('p[id="time"]').text(now.format("DD/MM/YY HH:mm")); | |
running = false; | |
console.log("pause"); | |
} | |
} | |
function updatePositions(){ | |
// **** add functionality to increase LOS when crossing midnight **** | |
// step through moves list | |
// | |
if( moment(now).isBefore(endtime) ){ | |
// if there is a move for this moment | |
// | |
if(movesLookup[now]){ | |
// pause the simulation | |
// | |
pause(); | |
movesLookup[now].forEach(function (m) | |
{ | |
// if pt is null then add new patient to patientLookup based on movelist | |
// otherwise use the patient that already exists in a bed somewhere | |
// | |
var pt = patientLookup[m.ID]; | |
var to = wardLookup[m.locn]; | |
if(pt){ | |
var from = wardLookup[pt.currLocn]; | |
removePatient(pt, from, patientLookup); | |
} else { | |
var from = data.wards[0]; //Admission position | |
// create new patient | |
var pt = {}; | |
pt.ID = m.ID; | |
pt.LOS = 0; | |
pt.PTN = m.PTN; | |
pt.currLocn = "Admission"; | |
pt.admtype = m.admtype; | |
//add new pt to pt lookup | |
patientLookup[pt.ID] = pt | |
} | |
console.log(m.time.format("DD/MM/YY HH:mm"), pt.PTN, from.name, to.name); | |
moveCircle(from, to, pt); | |
if(m.locn != "Discharged") | |
addPatient(pt, to); | |
}) | |
startresume(); | |
} | |
now.add(increment, "minute"); | |
d3.select('p[id="time"]').text(now.format("DD/MM/YY HH:mm")); | |
} | |
else { | |
pause(); | |
} | |
} | |
}); | |
// adm type colour | |
svg.append("text") | |
.attr("x", 75) | |
.attr("y", 20) | |
.text("Change colours to LOS") | |
// add button to colour circles by adm type | |
// | |
svg.append("rect") | |
.attr("class", "button") | |
.attr("id", "colourAdmtype") | |
.attr("height", "32") | |
.attr("width", "200") | |
.attr("x", "70") | |
.attr("y", "0") | |
.on("click", function(){ | |
var buttonText = ""; | |
d3.selectAll("text").filter(function() { | |
return /Change c*/.test(d3.select(this).text()); | |
}) | |
.text( function() { | |
if(colourCategory == 1){ | |
colourCategory = 2; | |
buttonText = "Change colours to adm type"; | |
}else if(colourCategory == 2){ | |
colourCategory = 1; | |
buttonText="Change colours to LOS"; | |
} | |
return buttonText; | |
}); | |
svg.selectAll(".patient") | |
.attr("fill", function(){ return changeColour(patientLookup[this.id.substring(1)]); }) | |
console.log("colour by admtype"); | |
}) | |
.on("mouseover", function(d) { | |
if(colourCategory == 1){ | |
showtooltip("Colour by admission"+ | |
"<br>- green = elective"+ | |
"<br>- orange = non-elective"+ | |
"<br>- dark pink = maternity"+ | |
"<br>- light pink = birth", | |
(d3.event.pageX + tooltopOffsetX) + "px", | |
(d3.event.pageY + tooltopOffsetY) + "px"); | |
} else if(colourCategory==2){ | |
showtooltip("Colour by LOS<br>- red = LOS 7+<br>- blue = LOS <7", | |
(d3.event.pageX + tooltopOffsetX) + "px", | |
(d3.event.pageY + tooltopOffsetY) + "px"); | |
} | |
}) | |
.on("mouseout", function(d) { hidetooltip(); }) | |
// Position by division | |
// | |
svg.append("text") | |
.attr("x", 295) | |
.attr("y", 20) | |
.text("Position by division") | |
svg.append("rect") | |
.attr("class", "button") | |
.attr("id", "move test") | |
.attr("height", "32") | |
.attr("width", "140") | |
.attr("x", "290") | |
.attr("y", "0") | |
.on("click", function(){ | |
var buttonText = ""; | |
d3.selectAll("text") | |
.filter(function() { | |
return /Position by*/.test(d3.select(this).text()); | |
}) | |
.text( function() { | |
if(positionCategory == 1){ | |
positionCategory = 2; | |
buttonText = "Position by location"; | |
}else if(positionCategory == 2){ | |
positionCategory = 1; | |
buttonText="Position by division"; | |
} | |
return buttonText; | |
}); | |
svg.selectAll(".wardcontainer") | |
.transition().duration(1000) | |
.attr("transform", function() { | |
if(positionCategory==1){ | |
wardLookup[this.id].x = wardLookup[this.id].x1; | |
wardLookup[this.id].y = wardLookup[this.id].y1; | |
return "translate(" + wardLookup[this.id].x + "," + wardLookup[this.id].y + ")" | |
} else if (positionCategory==2){ | |
wardLookup[this.id].x = wardLookup[this.id].x2; | |
wardLookup[this.id].y = wardLookup[this.id].y2; | |
return "translate(" + wardLookup[this.id].x2 + "," + wardLookup[this.id].y2 + ")" | |
} | |
}) | |
}) | |
.on("mouseover", function(d) { | |
if(positionCategory==1){ | |
showtooltip("Wards shown in physical location, click to change to by division", | |
(d3.event.pageX + tooltopOffsetX) + "px", | |
(d3.event.pageY + tooltopOffsetY) + "px"); | |
} else if(positionCategory==2){ | |
showtooltip("Wards shown by division, click to change to physical location", | |
(d3.event.pageX + tooltopOffsetX) + "px", | |
(d3.event.pageY + tooltopOffsetY) + "px"); | |
} | |
}) | |
.on("mouseout", function(d) { hidetooltip(); }) | |
function changeColour(pt) | |
{ | |
var retColour; | |
try{ | |
if(colourCategory==1) | |
{ | |
if(pt.admtype=="Elective"){ | |
retColour = "green";} | |
else if(pt.admtype=="Emergency"){ | |
retColour = "orange";} | |
else if(pt.admtype=="Maternity"){ | |
retColour = "PaleVioletRed";} | |
else if(pt.admtype=="Birth"){ | |
retColour = "pink";} | |
else{ | |
retColour = "dodgerblue";} | |
} | |
else if(colourCategory==2) | |
{ | |
if(pt.LOS>=7) | |
retColour = "orangered"; | |
else | |
retColour = "skyblue"; | |
} | |
} | |
catch(err){ | |
console.log(err); | |
} | |
return retColour; | |
} | |
// tool tip | |
// | |
var div = d3.select("body").append("div") | |
.attr("class", "tooltip") | |
.style("opacity", 0); | |
function showtooltip(t,left,top){ | |
div.html(t).style("left", left) | |
.style("top", top) | |
.style("opacity", 1); | |
} | |
function hidetooltip(){ | |
div.style("opacity", 0); | |
} | |
// remove patient from currward | |
// | |
function removePatient(pt, ward, ptlookup) | |
{ | |
console.log(ward.name + ": Remove " + pt.PTN + " from bed " + pt.currbed) | |
// find ward and remove patient | |
// | |
var thisward = svg.select("g#" + pt.currLocn); | |
var thisbed = thisward.select("g#b" + pt.currbed); | |
var removed = thisbed.select("circle#c" + pt.ID); | |
removed.remove(); | |
if(pt.currbed < ward.count){ | |
// find last patient using occupancy value and move to empty bed | |
// | |
var last = thisward.select("g#b" + ward.count).select("circle"); | |
thisbed.append(function() { | |
return last.node(); | |
}); | |
// update bed location | |
// | |
ptlookup[last.attr("id").substring(1)].currbed = pt.currbed; | |
} | |
// decrease occupancy of ward | |
// | |
ward.count--; | |
// return removed; | |
} | |
// add a patient to a ward - used to initialise positions and for transfers | |
// | |
function addPatient(pt, ward, removed) | |
{ | |
ward.count++; | |
theward = svg.select("g#" + ward.name) | |
thebed = theward.select("g#b" + ward.count) | |
thebed.append("circle") | |
.attr("id", function(){ return "c"+pt.ID }) | |
.attr("class", "patient") | |
.attr("fill", function(){ | |
return changeColour(pt); | |
}) | |
.attr("fill-opacity", 0.5) | |
.on("mouseover", function(d) { | |
showtooltip( | |
"Ward: " + ward.name + | |
"<br>PTN: " + pt.PTN + | |
"<br>Adm type: " + pt.admtype + | |
"<br>LOS: " + pt.LOS, | |
(d3.event.pageX + tooltopOffsetX) + "px", | |
(d3.event.pageY + tooltopOffsetY) + "px"); | |
}) | |
.on("mouseout", function() { hidetooltip(); }) | |
.attr("cx", 6 ) | |
.attr("cy", 6 ) | |
.transition().delay(dur) | |
.attr("r", r) | |
; | |
// add bed to patient so we know where they are | |
// | |
pt.currbed = ward.count; | |
pt.currLocn = ward.name; | |
console.log(ward.name + ": Add " + pt.PTN + " to bed " + pt.currbed) | |
} | |
function moveCircle(from, to, pt) | |
{ | |
// test code to add circle to ward, move it and then remove it. | |
svg.append("circle") | |
.attr("r", 0) | |
.attr("cx", function(){ return from.x } ) | |
.attr("cy", function(){ return from.y } ) | |
.attr("fill", function(){ | |
return changeColour(pt); | |
}) | |
.attr("transform", "translate(50,50)") | |
.transition().duration(0) | |
.attr("r", r) | |
.each("end", function(){ | |
d3.select(this) | |
.transition().duration(dur).ease("linear") | |
.attr("cx", to.x) | |
.attr("cy", to.y) | |
.each("end", function(){ | |
d3.select(this) | |
.transition().duration(dur/2) | |
.attr("r",0) | |
.remove(); | |
}) | |
}) | |
} | |
function wrap(text, width) { | |
text.each(function() { | |
var text = d3.select(this), | |
words = text.text().split(/\s+/).reverse(), | |
word, | |
line = [], | |
lineNumber = 0, | |
lineHeight = 1.1, // ems | |
y = text.attr("y"), | |
dy = parseFloat(text.attr("dy")), | |
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em"); | |
while (word = words.pop()) { | |
line.push(word); | |
tspan.text(line.join(" ")); | |
if (tspan.node().getComputedTextLength() > width) { | |
line.pop(); | |
tspan.text(line.join(" ")); | |
line = [word]; | |
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); | |
} | |
} | |
}); | |
} | |
</script> | |
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "IPtest", | |
"timeformat": "DD/MM/YY HH:mm", | |
"starttime": "01/01/19 07:00", | |
"endtime": "01/01/19 08:00", | |
"width": 500, | |
"height": 300, | |
"radius": 6, | |
"speed": 500, | |
"transduration": 1000, | |
"wardcolours" : [ | |
{"division" : "A", "colour":"crimson"}, | |
{"division" : "B", "colour":"limegreen"}, | |
{"division" : "C", "colour":"purple"}, | |
{"division" : "D", "colour":"mediumblue"}, | |
{"division" : "E", "colour":"orange"}, | |
{"division" : "X", "colour":"grey"} | |
], | |
"wards": [ | |
{"name":"Admission","division":"X","x":100,"y":400,"x1":100,"y1":400,"x2":100,"y2":400,"count":0,"maxbeds":0 }, | |
{"name":"Discharged","division":"X","x":1000,"y":400,"x1":1000,"y1":400,"x2":1000,"y2":400,"count":0,"maxbeds":0 }, | |
{"name":"W1","division":"A","x":400,"y":200,"x1":400,"y1":200,"x2":400,"y2":300,"count":0,"maxbeds":30 }, | |
{"name":"W2","division":"B","x":500,"y":200,"x1":500,"y1":200,"x2":600,"y2":300,"count":0,"maxbeds":32 }, | |
{"name":"W3","division":"A","x":400,"y":100,"x1":400,"y1":100,"x2":400,"y2":200,"count":0,"maxbeds":28 }, | |
{"name":"W4","division":"B","x":500,"y":100,"x1":500,"y1":100,"x2":600,"y2":200,"count":0,"maxbeds":32 }, | |
{"name":"W5","division":"B","x":700,"y":200,"x1":700,"y1":200,"x2":600,"y2":100,"count":0,"maxbeds":29 }, | |
{"name":"W6","division":"A","x":800,"y":200,"x1":800,"y1":200,"x2":400,"y2":100,"count":0,"maxbeds":32 } | |
], | |
"midnight": [ | |
{"ID":"1","PTN":"963", "currLocn":"W1", "admtype":"Elective", "LOS":1}, | |
{"ID":"2","PTN":"964", "currLocn":"W1", "admtype":"Elective", "LOS":9}, | |
{"ID":"3","PTN":"236", "currLocn":"W2", "admtype":"Elective", "LOS":1}, | |
{"ID":"4","PTN":"326", "currLocn":"W2", "admtype":"Emergency", "LOS":8}, | |
{"ID":"5","PTN":"245", "currLocn":"W2", "admtype":"Elective", "LOS":3} | |
], | |
"moves": [ | |
{"time":"01/01/19 07:01", "ID":"1012","PTN":"1010", "locn":"W1", "admtype":"Emergency"}, | |
{"time":"01/01/19 07:05", "ID":"1131","PTN":"1126", "locn":"W2", "admtype":"Emergency"}, | |
{"time":"01/01/19 07:09", "ID":"1331","PTN":"1320", "locn":"W1", "admtype":"Emergency"}, | |
{"time":"01/01/19 07:10", "ID":"1283","PTN":"1274", "locn":"W2", "admtype":"Elective"}, | |
{"time":"01/01/19 07:11", "ID":"1614","PTN":"1586", "locn":"W1", "admtype":"Elective"}, | |
{"time":"01/01/19 07:12", "ID":"1352","PTN":"1340", "locn":"W1", "admtype":"Elective"}, | |
{"time":"01/01/19 07:13", "ID":"979","PTN":"978", "locn":"W2", "admtype":"Elective"}, | |
{"time":"01/01/19 07:14", "ID":"1","PTN":"963", "locn":"Discharged", "admtype":"Elective"}, | |
{"time":"01/01/19 07:15", "ID":"1114","PTN":"1109", "locn":"W1", "admtype":"Elective"}, | |
{"time":"01/01/19 07:18", "ID":"1672","PTN":"1644", "locn":"W1", "admtype":"Elective"}, | |
{"time":"01/01/19 07:19", "ID":"1484","PTN":"1463", "locn":"W1", "admtype":"Elective"}, | |
{"time":"01/01/19 07:21", "ID":"1217","PTN":"1210", "locn":"W2", "admtype":"Elective"}, | |
{"time":"01/01/19 07:30", "ID":"989","PTN":"988", "locn":"W1", "admtype":"Elective"}, | |
{"time":"01/01/19 07:30", "ID":"1331","PTN":"1320", "locn":"Discharged", "admtype":"Emergency"} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment