Skip to content

Instantly share code, notes, and snippets.

@zeffii
Last active March 18, 2016 21:15
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 zeffii/1554f5cc59f7b4b3403d to your computer and use it in GitHub Desktop.
Save zeffii/1554f5cc59f7b4b3403d to your computer and use it in GitHub Desktop.
mediseen0.2 18march2016
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width:100%; height: 100% }
</style>
</head>
<body>
<svg></svg>
<script>
/*
MIT license. Dealga McArdle. 2009-2015
Rewrite in Progress.
Specifically written for people who have a difficult time
figuring out their meds. It's easy for family or a healthcare
professional to update and print when changes are made.
It parses a medicine descriptor string used to describe most
forms of medication. (Universal Medicine Descriptor Language).
only caviat is some meds have weird shapes. A solution is to
allow the medication descriptor to include a link to a bitmap.
Milestones
[x] parse csv
[x] draw time, number, medication name, dose
[x] parse UMDL as vector
[ ] parse IMGUR 5 or 7 digit code when no UMDL is present
[ ] write up formalized UMDL
*/
d3.select("body").style("background-color", d3.rgb(255,255,255))
var svg = d3.select("svg");
var defs = svg.append("defs");
var group1 = svg.append("g").classed("group1", true);
var group2 = svg.append("g").classed("group2", true);
var group3 = svg.append("g").classed("group2", true);
var global_transform = "translate(" + [40, 63] + ")";
group1.attr("transform", global_transform)
group2.attr("transform", global_transform)
group3.attr("transform", global_transform)
d3.csv("medilist.csv", generateList);
var data = [];
function generateList(data){
data = data;
var line_height = 23,
padding_y = 13,
padding_x = 130,
type_height = 19,
time_height = 29,
divider_height = 6,
divider_width = 291,
ty = 30,
my = ty,
vert_lines_x_offset = 259,
outline_width = {"stroke-width": 0.7 + "px"},
div_style = {"fill": "#424242", "stroke": "none"},
med_style = {"fill": "#837979", "stroke": "none", "font-family": "sans-serif"},
dose_style = {"fill": "#77A2CA", "stroke": "none", "font-family": "sans-serif"},
text_styles = [med_style, dose_style];
function assemble_med_list(data, med_list, time_list){
data.forEach(function(d){
if (d.time in med_list) med_list[d.time].push(d)
else {
med_list[d.time] = [d]
time_list.push(d.time)
}
})
return [med_list, time_list]
}
var med_and_time_list = assemble_med_list(data, {}, []);
var med_list = med_and_time_list[0];
var time_list = med_and_time_list[1];
function draw_text(text, size, pos, style){
group1.append('text')
.text(text)
.attr(pos)
.style(style)
.style({"font-size": size})
}
function draw_text2(text, size, pos){
group1.append('text')
.text(text.med)
.attr(pos)
.style(med_style)
.style({"font-size": size})
.append('tspan')
.text(" " + text.dose)
.style(dose_style)
}
function draw_divider(pos){
group1.append("rect")
.attr(pos)
.attr({height: divider_height, width: divider_width})
.style(div_style)
}
function _adjust(ty){ return ty-35 }
function buffer_space(n){ return (2 * padding_y) + (n * line_height) }
function parse_umdl(d){
var descr_array,
descr_object,
descr = d.descriptor,
descr_length = descr.length;
// maybe enforcing this leads to unnecessary complexity
// but i like the way it helps keep the description together
// optically at least in the csv
if ((descr[0] != "(") || (descr[descr_length-1] != ")")){
console.error(descr)
console.error("descriptor must be enclosed in parentheses")
return
}
// strip parentheses
descr = descr.slice(1, descr_length-1)
// split into color(s)|shape|[groovetype|]inscription object
descr_array = descr.split("|")
if (descr_array.length === 3){
descr_object = {
color: descr_array[0].split("/"),
shape: descr_array[1],
inscription: descr_array[2],
numparams: 3
}
}
else if (descr_array.length === 4){
descr_object = {
color: descr_array[0].split("/"),
shape: descr_array[1],
groovetype: descr_array[2],
inscription: descr_array[3],
numparams: 4
}
}
else {
var error_message = "descriptor must take form: \n";
error_message += "color(s)|shape|groovetype|inscription\n"
error_message += "or\n"
error_message += "color|shape|inscription"
console.error(error_message)
return
}
return descr_object
}
function console_debug(d, medicine_object){
console.log("______")
console.log(d.descriptor)
console.log("color(s):", medicine_object.color)
console.log("shape:", medicine_object.shape)
if (medicine_object.numparams === 4)
console.log("groove type:", medicine_object.groovetype)
if (medicine_object.inscription != "_")
console.log("inscription:", medicine_object.inscription)
}
function draw_from_umdl(d, pos){
var medicine_object = parse_umdl(d);
// check if this parsed a valid umdl
if (!medicine_object){
console.error(d, "didn't parse correctly")
// draw questionmark?
return
}
var show_debug = [false, true][0];
if (show_debug) console_debug(d, medicine_object)
draw_medicine(medicine_object, pos)
}
c_list = {
"D-pink": "#F171E7"
// add custom colors
};
function color_list_check(c_in){
if (c_in in c_list) return c_list[c_in]
else {
console.error(c_in, "not in color list (c_list), add it!")
return "#fff"
}
}
function draw_liteline(pos){
// function draw_text(text, size, pos, style){
var y_tweak = 4;
var line_start_x = 239;
var line_width_x = 630;
var line_height_y = type_height+4;
group1.append("line")
.attr(pos)
.attr({x1: line_start_x, y1:0+y_tweak, x2: line_start_x + line_width_x, y2: 0+y_tweak})
.style({"stroke-width": "1px", "stroke": "#eee"})
group1.append("line")
.attr(pos)
.attr({x1: line_start_x, y1: -line_height_y + y_tweak, x2: line_start_x + line_width_x, y2: -line_height_y + y_tweak})
.style({"stroke-width": "1px", "stroke": "#eee"})
}
function draw_vertline(x, total_height){
var line_start_y = -4;
group1.append("line")
.attr({"transform": "translate(" + [x, 0] + ")"})
.attr({x1: x, y1:line_start_y, x2: x, y2: line_start_y + total_height})
.style({"stroke-width": "1px", "stroke": "#aaa"})
}
function draw_medicine(mo, pos){
var med = group2.append("g")
var med_r = type_height/2;
var shape = mo.shape.toLowerCase();
var size = shape.indexOf("small") >= 0 ? "small" : "normal";
if (size==="small") med_r *= 0.8
// round & round-small
if (shape.indexOf("round") >= 0){
med.append("circle")
.attr({"cx": pos.x, "cy": pos.y-med_r/2, "r": med_r})
.style({stroke: "#121212", "fill": mo.color[0]})
.style(outline_width)
}
// oval
if (shape.indexOf("oval") >= 0){
var oval_color = color_list_check(mo.color[0]);
med.append("ellipse")
.attr({"cx": pos.x, "cy": pos.y-med_r/2,
"rx": med_r*1.5, "ry": med_r})
.style({stroke: "#121212", "fill": oval_color})
.style(outline_width)
}
if (mo.groovetype){
var groove = mo.groovetype.toLowerCase();
var g_width = 1;
if (groove === "brkthin") g_width = 1
if (groove === "brkwide") g_width = 4
var groove_style = {
"stroke": "#000",
"stroke-width": g_width +"px",
"stroke-opacity": 0.6
};
med.append('line')
.attr({x1: pos.x, y1: pos.y, x2: pos.x, y2: pos.y-(med_r*2)})
.style(groove_style)
.attr("transform", "translate("+ [0, med_r/2] + ")")
if (groove === "brkx"){
med.append('line')
.attr({x1: pos.x-med_r, y1: pos.y-(med_r), x2: pos.x+med_r, y2: pos.y-(med_r)})
.style(groove_style)
.attr("transform", "translate("+ [0, med_r/2] + ")")
}
}
function side_(dir, med_r){
var th = med_r,
two_th = med_r*2,
straight_1 = "M" + [0,0,-th*dir,0].join(" "),
curve = "C" + [-two_th*dir, 0, -two_th*dir, -two_th, -th*dir, -two_th].join(" "),
straight_2 = "L" + [0,-two_th].join(" ");
return straight_1 + curve + straight_2;
}
// capsule
if (shape==="capsule"){
var cap = {x: pos.x, y: pos.y+(med_r/2)};
med.append("path")
.attr("d", side_(1, med_r))
.style({stroke: "#121212", "fill": mo.color[0]})
.style(outline_width)
med.append("path")
.attr("d", side_(-1, med_r))
.style({stroke: "#121212", "fill": mo.color[1]})
.style(outline_width)
med.attr("transform", "translate(" + [cap.x, cap.y] + ")")
}
// inscriptions
if (mo.inscription != "_"){
group3.append('text')
.attr({x: pos.x + 30, y: pos.y})
.text(mo.inscription)
.style(med_style)
}
}
var end_height = 0;
time_list.forEach(function(d){
my = ty;
draw_divider({x: padding_x, y: _adjust(ty)})
var num_items = med_list[d].length;
var extra_space = buffer_space(num_items);
var text_y = ty + (extra_space / 2) - (padding_y * 1.4);
// draw time
draw_text(d, time_height, {x: 37, y: text_y-5}, med_style)
ty += extra_space
// draw details for each
med_list[d].forEach(function(m){
draw_text(m.num, type_height, {x: 152, y: my}, med_style)
draw_text2(m, type_height, {x: 172, y: my})
draw_liteline({"transform": "translate(" + [172, my] + ")"})
draw_from_umdl(m, {x: 389, y: my})
my += line_height
})
end_height = my;
})
draw_divider({x: padding_x, y: _adjust(ty)})
// draw vertical markings
'Za Zo Ma Di Wo Do Vr'.split(' ').forEach(function(d, i){
// draw_vertline(x, total_height)
var twinky = 35;
var line_x = vert_lines_x_offset + 36*i;
draw_vertline(line_x, end_height);
draw_text(d, 14, {x: line_x+287+(twinky*i), y: 0})
console.log(d)
})
console.log("______\nscript finished")
/* EOF */
}
</script>
</body>
time med num dose descriptor
08:00 Nexium 1 40mg (D-pink|oval|AEl 40mg)
08:00 Thyrax 1 0.025mg (#45D0FC|round|brkwide|ZK 5)
08:00 Thyrax 1 0.10mg (white|round|brkwide|ZK 2)
08:00 Hydrocortison 1 10mg (white|round-small|brkthin|fullname)
08:00 Hydrocortison 1 5mg (white|round|brkx|fullname)
08:00 Furosemide 1 20mg (white|round|FUR.20)
08:00 BREAKFAST - -- (--)
08:00 Spironolacton 1 100mg (white|round|AF)
08:00 Metformine 1 500mg (white|round|_)
08:00 Ursofalk 2 250mg (white/white|capsule|_)
08:00 Lyrica 1 150mg (white/white|capsule|PGN 150)
10:00 Desmopressin 1 0.1mg (white|round|brkthin|0.1)
18:00 Furosemide 1 20mg (white|round|FUR.20)
18:00 DINNER - -- (--)
18:00 Metformine 1 500mg (white|round|_)
18:00 Ursofalk 2 250mg (white/white|capsule|_)
22:00 Hydrocortison 1 5mg (white|round|brkx|fullname)
22:00 Desmopressin 1 0.1mg (white|round|brkthin|0.1)
22:00 SLEEP - -- (--)
Universal Medicine Descriptor Language | Revision B, Draft
Consider describing any medication using a set of rules:
color(s)|shape|groovetype|inscription
color|shape|inscription
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment