Skip to content

Commit

Permalink
Merge pull request #197 from thejonan/feature/ExpandModelsRunning
Browse files Browse the repository at this point in the history
Feature/expand models running
  • Loading branch information
thejonan authored Sep 9, 2017
2 parents fcb166f + 33c051a commit 61fb883
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 97 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -709,10 +709,10 @@ There are few things that can be setup from outside:
- **`algorithms`** (attr. `data-algorithms`): Whether to list available algorithms, rather than available models. Default: _false_.
- **`maxStars`** (attr. `data-max-stars`): How many stars are considered maximum, when building the long version of ratings. Default: _10_.
- **`shortStars`** (attr. `data-short-stars`): Whether to show show star rating notation, i.e. - one star and the number of stars next to it, opposed to the long (default) version - always showing the maximum number of stars, with given number of them - highlighted. Default is _false_.
- **`loadOnInit`** (attr. `data-load-on-init`): Whether to make an initial query even when _modelUri_ or _algorithmNeedle_ are not specified. Default is _false_.
- **`loadOnInit`** (attr. `data-load-on-init`): Whether to make an initial query even when _modelUri_ or _algorithmFilter_ are not specified. Default is _false_.
- **`sDom`** (attr. `data-s-dom`): The redefinition of _sDom_ attribute for the table. Default _"\<Fif\>rt"_.
- **`modelUri`** (attr. `data-model-uri`): The address to query for list of models. If none is passed, the standard `<baseURL>/model` is used.
- **`algorithmNeedle`** (attr. `data-algorithms-needle`): If algorithms listing mode is selected (`algorithms` = _true_) - this is the needle to be used when listing them. Default: _null_.
- **`algorithmFilter`** (attr. `data-algorithm-filter`): If algorithms listing mode is selected (`algorithms` = _true_) - this is the needle to be used when listing them. Default: _null_.
- **`forceCreate`** (attr. `data-force-create`): When creating a model from an algorithm, the kit usually tries to obtain one from the server, and only if that fails it makes a _create model_ query, unless this option is specified, which instructs the kit to directly try to create a new one. Default _false_.


Expand Down
2 changes: 1 addition & 1 deletion scripts/toxcompound.js
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ cls.prototype.init = function () {
var feat = jT.$.extend({}, features[fId]);
feat.value = entry.values[fId];
if (!!feat.title) {
if (ccLib.fireCallback(callback, null, feat, fId) !== false) {
if (ccLib.fireCallback(callback, null, feat, fId, data.length) !== false) {
if (!feat.value)
feat.value = '-';
data.push(feat);
Expand Down
6 changes: 3 additions & 3 deletions scripts/toxmodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var jToxModel = (function () {
sDom: "<Fif>rt", // merged to dataTable's settings, when created
loadOnInit: false, // whether to make a (blank) request upon loading
oLanguage: null, // merged to dataTable's settings, when created
/* algorithmNeedle */
/* algorithmFilter */
/* modelUri */
configuration: {
columns : {
Expand Down Expand Up @@ -64,7 +64,7 @@ var jToxModel = (function () {
}

// finally, wait a bit for everyone to get initialized and make a call, if asked to
if (self.settings.modelUri != null || self.settings.algorithmNeedle != null || self.settings.loadOnInit)
if (self.settings.modelUri != null || self.settings.algorithmFilter != null || self.settings.loadOnInit)
self.query();
};

Expand Down Expand Up @@ -222,7 +222,7 @@ var jToxModel = (function () {

cls.prototype.query = function (uri) {
if (this.settings.algorithms)
this.listAlgorithms(this.settings.algorithmNeedle = (uri || this.settings.algorithmNeedle));
this.listAlgorithms(this.settings.algorithmFilter = (uri || this.settings.algorithmFilter));
else
this.listModels(this.settings.modelUri = (uri || this.settings.modelUri));
};
Expand Down
2 changes: 1 addition & 1 deletion toxmodel.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

</head>
<body>
<div class="jtox-toolkit" data-kit="model" data-algorithm-link="true" data-algorithm-needle="ToxTree" data-algorithms="true" data-load-on-init="true" data-base-url="http://apps.ideaconsult.net:8080/ambit2"></div>
<div class="jtox-toolkit" data-kit="model" data-algorithm-link="true" data-algorithm-filter="ToxTree" data-algorithms="true" data-load-on-init="true" data-base-url="http://apps.ideaconsult.net:8080/ambit2"></div>
<div class="jtox-template">
<!--[[ jT.templates['all-model'] -->
<div id="jtox-model" class="jtox-model">
Expand Down
1 change: 1 addition & 0 deletions uses/ui-toxtree.css → uses/ui-prediction.css
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ body>div.jtox-toolkit {

#tt-models-panel .content .tt-explanation {
margin: 5px;
padding: 5px;
background: #fefefe;
border: 1px solid #aaa;
border-radius: 5px;
Expand Down
19 changes: 8 additions & 11 deletions uses/ui-toxtree.html → uses/ui-prediction.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" >

<title>ToxTree web interface</title>
<title>Model Prediction</title>
<link rel="stylesheet" href="../tests/base.css"/>
<link rel="stylesheet" href="../tests/skeleton-fluid.css"/>
<link rel="stylesheet" href="../tests/layout.css"/>
Expand All @@ -18,7 +18,7 @@

<link rel="stylesheet" href="../www/jtoxkit.css"/>
<link rel="stylesheet" href="../www/ketcher.css"/>
<link rel="stylesheet" href="ui-toxtree.css"/>
<link rel="stylesheet" href="ui-prediction.css"/>

<script src="oecdcategories.js"></script>

Expand All @@ -32,12 +32,12 @@

<script src="../www/jtoxkit.js"></script>
<script src="../www/ketcher.js"></script>
<script src="ui-toxtree.js"></script>
<script src="ui-prediction.js"></script>
</head>
<body>
<div id="logger" class="jtox-toolkit jtox-widget hidden" data-kit="log" data-resend-events="false" data-right-side="true"></div>

<div class="jtox-toolkit" data-kit="query" data-configuration="config_toxtree" data-base-url="https://apps.ideaconsult.net/data">
<div class="jtox-toolkit" data-kit="query" data-configuration="config_model" data-base-url="https://apps.ideaconsult.net/data">
<div class="jtox-toolkit jtox-widget cc-fixed" data-kit="search"></div>
<div id="tt-bigpane" class="cc-flex">
<div>
Expand All @@ -59,9 +59,9 @@
<div class="title jtox-inline"><span class="counter-field">Toxicity prediction modules (0/0)</span></div>
<div class="jtox-inline selections"><a href="#" class="select-unselect" title="(Un)select all algorithms" data-other="unselect">select</a>&nbsp;<a href="#" class="expand-collapse" title="Expand/collapse all algorithm panes" data-other="collapse">expand</a>&nbsp;<a href="#" class="run-selected" title="Run predictions for all selected algorithms">run</a>&nbsp;<a href="#" class="show-hide" data-other="show" title="Hide/show unselected algorithms">hide</a></div>
</div>
<div class="jtox-toolkit jtox-widget cc-flex size-full" data-kit="model" data-algorithms="true" data-no-interface="true" data-on-loaded="onAlgoLoaded" data-algorithm-needle="ToxTree"></div>
<div class="jtox-toolkit jtox-widget cc-flex size-full" data-kit="model" data-algorithms="true" data-no-interface="true" data-on-loaded="onAlgoLoaded"></div>
</div>
<div id="tt-table" class="jtox-toolkit jtox-panel" data-kit="compound" data-configuration="config_toxtree" data-manual-init="true" data-pre-details="onTableDetails" data-show-tabs="false" data-on-loaded="onDataLoaded" data-selection-handler="checked"></div>
<div id="tt-table" class="jtox-toolkit jtox-panel" data-kit="compound" data-configuration="config_model" data-manual-init="true" data-pre-details="onTableDetails" data-show-tabs="false" data-on-loaded="onDataLoaded" data-selection-handler="checked"></div>
</div>
</div>
<div id="sidebar">
Expand All @@ -88,12 +88,9 @@
<button class="jt-toggle jtox-handler model" data-handler="makeModel" title="Prepare the model for this algorithm">M</button>
<button class="jt-toggle jtox-handler auto" data-handler="markAuto" title="Run automatically on new queries">A</button>
</div>
<div class="tt-classification">
</div>
</div>
<div class="content">
<div class="tt-explanation"></div>
<div class="tt-classification"></div>
</div>
<div class="content"></div>
</div>
</div>
</body>
Expand Down
185 changes: 120 additions & 65 deletions uses/ui-toxtree.js → uses/ui-prediction.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var tt = {
]
};

var config_toxtree = {
var config_model = {
"baseFeatures": {}, // to be expanded upon algorithm loading
"handlers": {
"query": function (e, query) {
Expand All @@ -42,7 +42,7 @@ var config_toxtree = {
"http://www.opentox.org/api/1.1#EINECS",
"http://www.opentox.org/api/1.1#IUCLID5_UUID"
],
"ToxTree": [] // to be expanded upon algorithm loading
"Models": [] // to be expanded upon algorithm loading
}
};

Expand Down Expand Up @@ -121,50 +121,36 @@ function runSelected() {
}

function formatAlgoName(val) {
return (val.indexOf('ToxTree: ') == 0) ? val = val.substr(9) : val;
return val.replace(/^\w+:\s+/, "");
}

function buildCategories(features, values) {
var cats = [];
var regex = /\^\^(\S+)Category/i;
var multi = false;

for (var fId in values) {
if (features[fId].title.indexOf('#explanation') > -1 || features[fId].source.type.toLowerCase() != 'model')
continue;
var val = values[fId];
var anot = features[fId].annotation;
if (anot.length > 0) {
if (cats.length > 0)
multi = true;
for (var i = 0;i < anot.length; ++i) {
cats.push({
name: features[fId].title.replace(/\s/g, '&nbsp;'),
title: anot[i].o.replace(/\s/g, '&nbsp;'),
toxicity: anot[i].type.replace(regex, '$1').toLowerCase(),
active: anot[i].o == val
});
}
}
else
cats.push({
name: features[fId].title.replace(/\s/g, '&nbsp;'),
title: val,
toxicity: 'unknown',
active: true
});
};

if (multi) {
var old = cats;
cats = [];
$.map(old, function (o) {
function mergeCategories(features, indices) {
var cats = [];
for (var i = 0; i < indices.length; ++i) {
$.map(features[indices[i]].categories, function (o) {
if (o.active) {
o.title = o.name + ':&nbsp;' + o.title;
cats.push(o);
}
});
});
}

return cats;
}

function buildCategories(feature) {
anot = feature.annotation;
if (!anot || anot.length == 0)
return null;
var cats = [],
regex = /\^\^(\S+)Category/i;
for (var i = 0;i < anot.length; ++i) {
cats.push({
name: feature.title.replace(/\s/g, '&nbsp;'),
title: anot[i].o.replace(/\s/g, '&nbsp;'),
toxicity: anot[i].type.replace(regex, '$1').toLowerCase(),
active: anot[i].o == feature.value
});
}

return cats;
Expand Down Expand Up @@ -204,8 +190,8 @@ function onAlgoLoaded(result) {
};

$(this).data('algoId', data.id);
config_toxtree.groups.ToxTree.push(data.uri);
config_toxtree.baseFeatures[data.uri] = {
config_model.groups.Models.push(data.uri);
config_model.baseFeatures[data.uri] = {
title: formatAlgoName(data.name),
search: false,
data: "index",
Expand Down Expand Up @@ -244,7 +230,7 @@ function addFeatures(data, className) {
enumFn = function () { $(this).addClass(className); };
$('.' + className, tt.featuresList).remove();
}
ccLib.populateData(tt.featuresList, '#tt-feature', data, enumFn);
ccLib.populateData(tt.featuresList, '#tt-feature', data.filter(function (e) { return e.explanation == null; }), enumFn);
var sep = $('#tt-feature')[0].cloneNode(true);
sep.removeAttribute('id');
$(sep).addClass('separator').empty();
Expand Down Expand Up @@ -307,51 +293,120 @@ function showCompound() {
}

function showPrediction(algoId) {
var map = tt.algoMap[algoId];
var mapRes = map.results[tt.compoundIdx];
var map = tt.algoMap[algoId],
mapRes = map.results[tt.compoundIdx];

// check if we have results for this guy at all...
if (mapRes == null || mapRes.data == null)
return;

addFeatures(mapRes.data, algoId);
var aEl = map.dom;
if (mapRes.explanation != null)
$('.tt-explanation', aEl).html(mapRes.explanation.replace(/(Yes|No)/g, '<span class="answer $1">$1</span>'));
var aEl = map.dom,
$expEl = $('.content', aEl).empty();

if (mapRes.submodels && mapRes.submodels.length) {
mapRes.submodels.forEach(function (el, subIdx) {
addFeatures(el.data, algoId + "-" + subIdx);
if (!el.explanation) {
el.explanation = "";
el.data.forEach(function (feature) {
if (!feature.annotation || !feature.annotation.length)
el.explanation += feature.title + "&nbsp;:&nbsp;<strong>" + jT.ui.valueWithUnits(feature.value, feature.units) + "</strong><br/>";
});
}

if (!!el.explanation)
$expEl.append('<div class="tt-explanation">' + el.explanation + '</div>');
});
}
else { // Singe model mode
addFeatures(mapRes.data, algoId);
if (mapRes.explanation != null)
$expEl.append('<div class="tt-explanation">' + mapRes.explanation + '</div>');
}

$('.tt-classification', aEl).empty();


fillClassification($('.tt-classification', aEl)[0], mapRes.categories);
$(aEl).removeClass('folded');
}

function splitFeatures(features) {
var lastURI = features[0].source.URI,
subs = [],
catFeatures = [],
descIndex = null;

for (var e, i = 0;; ++i) {
if (i >= features.length || features[i].source.URI != lastURI) {
e = { data: features.splice(0, i) };
if (catFeatures.length > 1)
e.categories = mergeCategories(e.data, catFeatures);
else if (catFeatures.length == 1)
e.categories = e.data[catFeatures[0]].categories;

if (descIndex != null)
e.explanation = e.data[descIndex].explanation;

subs.push(e);

i = 0;
descIndex = null;
catFeatures = [];
}

if (i >= features.length)
break;
else if (features[i].explanation != null)
descIndex = i;
else if (features[i].categories != null)
catFeatures.push(i);
lastURI = i < features.length ? features[i].source.URI : null;
}

return subs;
}

function parsePrediction(result, algoId, index) {
var map = tt.algoMap[algoId];

var cells = $('#tt-table table td.' + algoId);
for (var i = 0, rl = result.dataEntry.length; i < rl; ++i) {
var idx = i + (index || 0);
var mapRes = map.results[idx];
if (mapRes == null){
var idx = i + (index || 0),
mapRes = map.results[idx],
catFeatures = [];

if (mapRes == null)
map.results[idx] = mapRes = {};
}
mapRes.explanation = '';
mapRes.data = jToxCompound.extractFeatures(result.dataEntry[i], result.feature, function (feature, fId) {
if (feature.title.indexOf("#explanation") > -1) {
mapRes.explanation = feature.value;

mapRes.data = jToxCompound.extractFeatures(result.dataEntry[i], result.feature, function (feature, fId, fIdx) {
if (feature.source.type.toLowerCase() != 'model' || !feature.value)
return false;

if (feature.title.endsWith("#explanation"))
feature.explanation = feature.value.replace(/\W(Yes|No)\W/g, '<span class="answer $1">$&</span>');
else {
feature.categories = buildCategories(feature);
if (feature.categories != null)
catFeatures.push(fIdx)
}
else if (feature.source.type.toLowerCase() == 'model' && !!feature.value)
return true;
else
return false;
return true;
});

mapRes.categories = buildCategories(result.feature, result.dataEntry[i].values);
// Make the combined categories in any case for the table mode
if (catFeatures.length > 1)
mapRes.categories = mergeCategories(mapRes.data, catFeatures);
else if (catFeatures.length == 1)
mapRes.categories = mapRes.data[catFeatures[0]].categories;

if (mapRes.categories.length == 0 && index == null){
runPredict ($('button', cells[idx]), algoId);
if (tt.modelKit.settings.multiModels && mapRes.data.length > 1) {
mapRes.data.sort(function (a, b) { return a.title < b.title ? -1 : (a.title > b.title ? 1 : 0); });
mapRes.submodels = splitFeatures(mapRes.data);
}
else // !multiModels
mapRes.explanation = mapRes.data.find(function (e) { return e.explanation != null; }).explanation;

// Finally, fill the table cell.
if (mapRes.categories.length == 0 && index == null)
runPredict ($('button', cells[idx]), algoId);
else {
$('.tt-class', cells[idx]).remove();
$(cells[idx]).addClass('calculated');
Expand Down
Loading

0 comments on commit 61fb883

Please sign in to comment.