Skip to content

Commit

Permalink
Merge pull request #70 from RhoInc/v2.1.1-dev
Browse files Browse the repository at this point in the history
Safety Shift Plot v2.1.1
  • Loading branch information
jwildfire authored Oct 25, 2018
2 parents e591b12 + cccef15 commit 4665240
Show file tree
Hide file tree
Showing 9 changed files with 425 additions and 927 deletions.
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2016-2017 [Rho Inc.](http://www.rhoworld.com)
Copyright (c) 2016-2018 [Rho Inc.](http://www.rhoworld.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Expand Down
48 changes: 20 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
# Shift Plot for Clinical Trials

![alt tag](https://user-images.githubusercontent.com/31038805/33946258-4d8cc192-dfef-11e7-8049-f63ff351d826.gif)


## Overview

Safety Shift Plot is a JavaScript library, built using Webcharts ([1](https://github.com/RhoInc/Webcharts), [2](https://github.com/RhoInc/webcharts-wrapper-boilerplate)), that allows users to compare lab and vital sign values between two time points. A typical chart created with Saftey Shift Plot looks like the above chart when it is first loaded. It also features a self updating data listing below the chart that shows meta data about the selected points as pictured below.



![alt tag](https://user-images.githubusercontent.com/31038805/33946248-46a9933c-dfef-11e7-8ac3-7f9ed6bcddf6.gif)



The chart uses the AdAM data standards by default, but can be customized to use any data set that is one record per measurement. Full details about chart configuration are [here](https://github.com/RhoInc/safety-shift-plot/wiki/Configuration).

Users can:
Expand All @@ -24,40 +17,39 @@ Users can:
* Click and drag across data points to show a linked listing of the underlying data
* Filter the shift plot for selected criteria, and see an updated chart (optional)


## Typical Usage

In the simplest case, using a dataset matching all default requirements, the chart can be created with a single line of code.

```javascript
safetyShiftPlot('#chartLocation', {}).init(data);
safetyShiftPlot('body', {}).init(data);
```

The code to load a comma-delimited data set and initialize the customized chart, with filters and simple data mappings, looks like this:

```javascript
const settings = {
time_col: 'VISIT'
start_value: 'Potassium'
x_params: {visits: ['Screening'], stat: 'min'}
y_params: {visits: ['End of Study'], stat: 'max'}
filters:[
{value_col: 'SITEID', label: 'Site ID'},
{value_col: 'SEX', label: 'Sex'},
{value_col: 'RACE', label: 'Race'}
]
};

d3.csv('../data/ADBDS.csv', function(data) {
safetyShiftPlot('#chartLocation', settings).init(data);
});
const settings = {
time_col: 'VISIT'
start_value: 'Potassium'
x_params: {visits: ['Screening'], stat: 'min'}
y_params: {visits: ['End of Study'], stat: 'max'}
filters:[
{value_col: 'SITEID', label: 'Site ID'},
{value_col: 'SEX', label: 'Sex'},
{value_col: 'RACE', label: 'Race'}
]
};

d3.csv(
'../data/ADBDS.csv',
function(data) {
safetyShiftPlot('body', settings).init(data);
}
);
```

## Links

- [Interactive Example](https://rhoinc.github.io/safety-shift-plot/build/test-page/)
- [Interactive Example](https://rhoinc.github.io/safety-shift-plot/test-page/)
- [Configuration](https://github.com/RhoInc/safety-shift-plot/wiki/Configuration)
- [API](https://github.com/RhoInc/safety-shift-plot/wiki/API)
- [Technical Documentation](https://github.com/RhoInc/safety-shift-plot/wiki/Technical-Documentation)
- [Data Guidelines](https://github.com/RhoInc/safety-shift-plot/wiki/Data-Guidelines)

154 changes: 16 additions & 138 deletions build/safetyShiftPlot.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) {
// .length of function is 2
'use strict';

if (target == null) {
// TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
Expand Down Expand Up @@ -248,122 +245,6 @@
: typeof obj;
};

var asyncGenerator = (function() {
function AwaitValue(value) {
this.value = value;
}

function AsyncGenerator(gen) {
var front, back;

function send(key, arg) {
return new Promise(function(resolve, reject) {
var request = {
key: key,
arg: arg,
resolve: resolve,
reject: reject,
next: null
};

if (back) {
back = back.next = request;
} else {
front = back = request;
resume(key, arg);
}
});
}

function resume(key, arg) {
try {
var result = gen[key](arg);
var value = result.value;

if (value instanceof AwaitValue) {
Promise.resolve(value.value).then(
function(arg) {
resume('next', arg);
},
function(arg) {
resume('throw', arg);
}
);
} else {
settle(result.done ? 'return' : 'normal', result.value);
}
} catch (err) {
settle('throw', err);
}
}

function settle(type, value) {
switch (type) {
case 'return':
front.resolve({
value: value,
done: true
});
break;

case 'throw':
front.reject(value);
break;

default:
front.resolve({
value: value,
done: false
});
break;
}

front = front.next;

if (front) {
resume(front.key, front.arg);
} else {
back = null;
}
}

this._invoke = send;

if (typeof gen.return !== 'function') {
this.return = undefined;
}
}

if (typeof Symbol === 'function' && Symbol.asyncIterator) {
AsyncGenerator.prototype[Symbol.asyncIterator] = function() {
return this;
};
}

AsyncGenerator.prototype.next = function(arg) {
return this._invoke('next', arg);
};

AsyncGenerator.prototype.throw = function(arg) {
return this._invoke('throw', arg);
};

AsyncGenerator.prototype.return = function(arg) {
return this._invoke('return', arg);
};

return {
wrap: function(fn) {
return function() {
return new AsyncGenerator(fn.apply(this, arguments));
};
},
await: function(value) {
return new AwaitValue(value);
}
};
})();

function clone(obj) {
var copy;

Expand Down Expand Up @@ -1030,15 +911,15 @@
function onDataTransform() {}

/*------------------------------------------------------------------------------------------------\
Annotate number of participants based on current filters, number of participants in all, and
the corresponding percentage.
Annotate number of participants based on current filters, number of participants in all, and
the corresponding percentage.
Inputs:
Inputs:
chart - a webcharts chart object
id_unit - a text string to label the units in the annotation (default = 'participants')
selector - css selector for the annotation
\------------------------------------------------------------------------------------------------*/
chart - a webcharts chart object
id_unit - a text string to label the units in the annotation (default = 'participants')
selector - css selector for the annotation
\------------------------------------------------------------------------------------------------*/

function updateParticipantCount(chart, selector, id_unit) {
//count the number of unique ids in the data set
Expand Down Expand Up @@ -1096,7 +977,7 @@
}

function drawBoxPlot(
svg$$1,
svg,
results,
height,
width,
Expand Down Expand Up @@ -1133,12 +1014,12 @@
probs[i] = d3.quantile(results, probs[i]);
}

var boxplot = svg$$1
var boxplot = svg
.append('g')
.attr('class', 'boxplot')
.datum({ values: results, probs: probs });

//set bar width variable
//draw rectangle from q1 to q3
var box_x = horizontal ? x(0.5 - boxPlotWidth / 2) : x(probs[1]);
var box_width = horizontal
? x(0.5 + boxPlotWidth / 2) - x(0.5 - boxPlotWidth / 2)
Expand Down Expand Up @@ -1314,7 +1195,7 @@
function brushed() {
var _this = this;

var extent$$1 = brush.extent();
var extent = brush.extent();
var points = this.svg.selectAll('g.point').classed('selected', false);

points.select('circle').attr('fill-opacity', 0);
Expand All @@ -1324,10 +1205,10 @@
var cx = _this.x(+d.values.x);
var cy = _this.y(+d.values.y);
return (
extent$$1[0][0] <= cx &&
cx <= extent$$1[1][0] &&
extent$$1[0][1] <= cy &&
cy <= extent$$1[1][1]
extent[0][0] <= cx &&
cx <= extent[1][0] &&
extent[0][1] <= cy &&
cy <= extent[1][1]
);
})
.classed('selected', true)
Expand Down Expand Up @@ -1435,10 +1316,7 @@
}

//polyfills
//settings
//layout and styles
//webcharts
//chart callbacks

function safetyShiftPlot(element, settings) {
//settings
if (settings.time_col && !settings.visit_col) settings.visit_col = settings.time_col; // prevent breaking backwards compatibility
Expand Down
Loading

0 comments on commit 4665240

Please sign in to comment.