summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgebele <gebele@in-silico.ch>2015-09-17 16:46:32 +0200
committergebele <gebele@in-silico.ch>2015-09-17 16:46:32 +0200
commitc20b9fb92b56c7818a4f24b22eead665b1dd1143 (patch)
tree5116e2c41d485349daeae3e426d3bbd1f48e4c86
parent1f3029412ad0a5d94c369b916b23593191b9534f (diff)
save stadium
-rw-r--r--application.rb59
-rw-r--r--views/batch.haml39
-rw-r--r--views/layout.haml1
-rw-r--r--views/predict.haml225
-rw-r--r--views/style.scss240
5 files changed, 286 insertions, 278 deletions
diff --git a/application.rb b/application.rb
index acf3c73..0214db4 100644
--- a/application.rb
+++ b/application.rb
@@ -6,6 +6,10 @@ include OpenTox
# Date: 18/11/2013
set :protection, :except => :path_traversal
+configure :development do
+ $logger = Logger.new(STDOUT)
+end
+
helpers do
class Numeric
def percent_of(n)
@@ -195,24 +199,49 @@ get '/predict/:dataset/?' do
end
post '/predict/?' do
+
+ # process batch prediction
+ if !params[:fileselect].blank?
+ File.open('tmp/' + params[:fileselect][:filename], "w") do |f|
+ f.write(params[:fileselect][:tempfile].read)
+ end
+ input = OpenTox::Dataset.from_csv_file File.join "tmp", params[:fileselect][:filename]
+ dataset = OpenTox::Dataset.find input.id
+ @compounds = dataset.compounds
+ @models = []
+ @predictions = []
+ @compounds.each do |compound|
+ params[:selection].keys.each do |model_id|
+ model = Model::Prediction.find model_id
+ @models << model
+ @predictions << model.predict(compound)
+ end
+ end
+ input.delete
+ return haml :batch
+ end
+
# validate identifier input
# transfered input
- @identifier = params[:identifier]
- begin
- # get compound from SMILES
- @compound = Compound.from_smiles @identifier
- rescue
- @error_report = "Attention, '#{params[:identifier]}' is not a valid SMILES string."
- return haml :error
- end
- @models = []
- @predictions = []
- params[:selection].keys.each do |model_id|
- model = Model::Prediction.find model_id
- @models << model
- @predictions << model.predict(@compound)
+ if !params[:identifier].blank?
+ @identifier = params[:identifier]
+ begin
+ # get compound from SMILES
+ @compound = Compound.from_smiles @identifier
+ rescue
+ @error_report = "Attention, '#{params[:identifier]}' is not a valid SMILES string."
+ return haml :error
+ end
+
+ @models = []
+ @predictions = []
+ params[:selection].keys.each do |model_id|
+ model = Model::Prediction.find model_id
+ @models << model
+ @predictions << model.predict(@compound)
+ end
+ haml :prediction
end
- haml :prediction
end
get '/style.css' do
diff --git a/views/batch.haml b/views/batch.haml
new file mode 100644
index 0000000..5bae411
--- /dev/null
+++ b/views/batch.haml
@@ -0,0 +1,39 @@
+/ displays all prediction result in first table
+%div.table-responsive
+ %table.table.table-bordered{:id=>"batch", :style=>"background-color:white;"}
+ %thead
+ %tr
+ %h3 Batch Prediction Results:
+
+ %tbody
+ - @compounds.each_with_index do |compound,i|
+ %tr
+ %td{:id=>"compound", :style=>"vertical-align:top;"}
+ %p= compound.svg
+ %p= compound.smiles
+ - @predictions.each_with_index do |prediction,i|
+ %td{:style=>"vertical-align:top;"}
+ %b{:class => "title"}
+ = "#{@models[i].endpoint.gsub('_', ' ')} (#{@models[i].species})"
+ %p
+ - if prediction[:confidence] == "measured"
+ %p
+ / TODO fix scientific notation from database
+ %b Measured activity:
+ = prediction[:value].numeric? ? "#{prediction[:value].round(3)} (#{@models[i].unit})" : prediction[:value]
+ %p Compound is part of the training dataset
+ - elsif prediction[:neighbors].size > 0
+ %p
+ / model type (classification|regression)
+ %b Type:
+ = @models[i].model.class.to_s.match("Classification") ? "Classification" : "Regression"
+ %br
+ %b Prediction:
+ / TODO scientific notation
+ = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} #{@models[i].unit}" : prediction[:value]
+ %br
+ / TODO probability
+ %b Confidence:
+ = prediction[:confidence].round(3)
+ %p
+ %p
diff --git a/views/layout.haml b/views/layout.haml
index 974a8ed..60f2bb3 100644
--- a/views/layout.haml
+++ b/views/layout.haml
@@ -9,6 +9,7 @@
%link{:rel=>'stylesheet', :href=>"#{'/css/bootstrap.min.css'}"}
%link{:rel=>'stylesheet', :href=>"#{'/css/theme.default.min.css'}"}
%link{:rel=>'stylesheet', :href=>"#{'/css/theme.bootstrap.min.css'}"}
+ %link{ :href=>"/style.css", :rel=>"stylesheet"}
%link{ :href=>"/stylesheets/jquery-ui.css", :rel=>"stylesheet"}
%script{:src=>"/javascripts/jquery-1.11.2.min.js"}
%script{:src=>"/javascripts/bootstrap.min.js"}
diff --git a/views/predict.haml b/views/predict.haml
index 77f16bc..917a04a 100644
--- a/views/predict.haml
+++ b/views/predict.haml
@@ -1,21 +1,58 @@
%link{ :href=>"/jsme/jsa.css", :rel=>"stylesheet"}
%script{:src=>"/jsme/jsme.nocache.js"}
:javascript
+ function getTab(){
+ t = $('.nav-tabs li.active').text();
+ return t.trim();
+ };
function showcircle() {
- if (checksmiles() && checkboxes()){
+ /*if (checksmiles() && checkboxes()){
button = document.getElementById("submit");
image = document.getElementById("circle");
button.parentNode.replaceChild(image, button);
$("img.circle").show();
return true;
};
+ return false;*/
+ switch (getTab()){
+ case "single":
+ if (checksmiles() && checkboxes()){
+ button = document.getElementById("submit");
+ image = document.getElementById("circle");
+ button.parentNode.replaceChild(image, button);
+ $("img.circle").show();
+ return true;
+ };
+ return false;
+ break;
+ case "batch":
+ if (checkfile() && checkboxes()){
+ button = document.getElementById("submit");
+ image = document.getElementById("circle");
+ button.parentNode.replaceChild(image, button);
+ $("img.circle").show();
+ return true;
+ };
+ return false;
+ break;
+ default: false;
+ };
+ return false;
+ };
+ function checkfile() {
+ var fileinput = document.getElementById("fileselect");
+ if(fileinput.value != "") {
+ //TODO check file type is csv
+ return true;
+ };
+ alert("Please select a file (csv).");
return false;
};
function checksmiles () {
+ getsmiles();
if (document.form.identifier.value == "") {
alert("Please draw or insert a chemical structure.");
document.form.identifier.focus();
- //$('.progress-bar').hide();
$("img.circle").hide();
return false;
};
@@ -48,49 +85,171 @@
};
};
-// init task for progress
-
// whole site content needs to be in one form. Input and checkboxes are proofed by js functions.
%form{:name => "form", :action => to('/predict'), :method => "post", :enctype => "multipart/form-data", :onsubmit => "return !!(showcircle())" }
%fieldset#top.well
- %h2 1. Draw a chemical structure
- :javascript
- $("a#linkInsert").click(function () {
- $("#insert").toggle();
- document.location = document.location + "#" + "insert";
- });
- #insert
- %p
- %label &nbsp;
- #appletContainer
- %br
- %label{:for => 'identifier'}
- or enter the
- %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification", :rel => "external"} SMILES
- string:
- %br
- %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'}
+ // tabs to select single prediction or batch prediction
+ %ul.nav.nav-tabs{:role=>"tablist"}
+ - ["single", "batch"].each do |select|
+ %li{:class => ("active" if select == "single")}
+ %a{:href => "div##{select}", :id => "linkTab#{select}", :data=> {:toggle=>"tab"}}
+ = select
+
+ %div.tab-content
+ #single.tab-pane.fade-in.active
+ %h2 1. Draw a chemical structure
+ #insert
+ %p
+ %label &nbsp;
+ #appletContainer
+ %br
+ %label{:for => 'identifier'}
+ or enter the
+ %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification", :rel => "external"} SMILES
+ string:
+ %br
+ %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'}
+
+ #batch.tab-pane.fade-in
+ %h2 1. Select a file to upload
+ Browse (csv):
+ %span.btn.btn-default.btn-file
+ %input{:type=>"file", :name=> "fileselect", :id=>"fileselect"}
%fieldset#middle.well
%h2 2. Select one or more endpoints
-
- :javascript
- $("a#linkModels").click(function () {
- $("#models").toggle();
- document.location = document.location + "#" + "models";
- });
-
#models
- @endpoints.each do |endpoint|
- %div
- %b= endpoint
+ %div{:id=>endpoint}
+ %h4.head-back=endpoint
- @models.select{|m| m.endpoint == endpoint}.each do |model|
- %div{:id => model.id}
- %input{:type => "checkbox", :name => "selection[#{model.id}]", :id => "selection[#{model.id}]", :value => true, :disabled => false}
+ %div.row{:id => model.id}
+ %span.col-sm-4
+ %input{:type => "checkbox", :name => "selection[#{model.id}]", :id => "selection[#{model.id}]", :value => true, :disabled => false}
%label{:for => "selection[#{model.id}]"}
= model.species
- %p
+ %span.col-sm-8
+ %a.btn.btn-default.btn-xs{:data=>{:toggle=>"collapse"}, :href=>"#details#{model.id}", :id => "link#{model.id}", :style=>"font-size:small;"}
+ Details | Validation
+ %div.panel-collapse.collapse{:id=>"details#{model.id}", :style=>"margin-left:1em;"}
+ %b Model:
+ = model.id
+ %br
+ = "Algorithm:\tLAZAR"
+ %br
+ - model.classification? ? type = "classification" : type = "regression"
+ = "Type:\t"
+ = type
+ %br
+ - training_dataset = OpenTox::Dataset.find model.training_dataset.id
+ = "Training dataset:\t"
+ = training_dataset.source.split("/").last
+ %br
+ = "Training compounds:\t"
+ = training_dataset.compounds.size
+
+
+ %p
+ %b Validation:
+ %br
+ - cv = OpenTox::CrossValidation.find model.crossvalidation.id
+ = "Num folds:\t"
+ = cv.folds
+ %br
+ = "Num instances:\t"
+ = cv.nr_instances
+ %br
+ = "Num unpredicted"
+ = cv.nr_unpredicted
+ - if model.classification?
+ %br
+ = "Accuracy:\t"
+ = cv.accuracy.round(3)
+ %br
+ = "Weighted Accuracy:\t"
+ = cv.weighted_accuracy.round(3)
+ %br
+ = "True positive rate:\t"
+ = cv.true_rate["active"].round(3)
+ %br
+ = "True negative rate:\t"
+ = cv.true_rate["inactive"].round(3)
+ %br
+ = "Positive predictive value:\t"
+ = cv.predictivity["active"].round(3)
+ %br
+ = "Negative predictive value:\t"
+ = cv.predictivity["inactive"].round(3)
+ %p
+ %b Confusion Matrix:
+ %table.table.table-condensed.table-borderless{:style=>"width:20%;"}
+ %tbody
+ %tr
+ %td
+ %td
+ %td
+ %b actual
+ %td
+ %td
+ %tr
+ %td
+ %td
+ %td active
+ %td inactive
+ %td total
+ %tr
+ %td
+ %b predicted
+ %td active
+ %td
+ =cv.confusion_matrix[0][0]
+ %td
+ =cv.confusion_matrix[0][1]
+ %td
+ =cv.confusion_matrix[0][0]+cv.confusion_matrix[0][1]
+ %tr
+ %td
+ %td inactive
+ %td
+ =cv.confusion_matrix[1][0]
+ %td
+ =cv.confusion_matrix[1][1]
+ %td
+ =cv.confusion_matrix[1][0]+cv.confusion_matrix[1][1]
+ %tr
+ %td
+ %td total
+ %td
+ =cv.confusion_matrix[0][0]+cv.confusion_matrix[1][0]
+ %td
+ =cv.confusion_matrix[0][1]+cv.confusion_matrix[1][1]
+ %td
+ -#= "Confusion Matrix:\t"
+ -#= cv.confusion_matrix
+ - if model.regression?
+ %br
+ = "Root mean squared error:\t"
+ = cv.rmse.round(3)
+ %br
+ = "Weighted root mean squared error:\t"
+ = cv.weighted_rmse.round(3)
+ %br
+ = "Mean absolute error:\t"
+ = cv.mae.round(3)
+ %br
+ = "Weighted mean absolute error:\t"
+ = cv.weighted_mae.round(3)
+ %br
+ = "R square:\t"
+ = cv.r_squared.round(3)
+ %br
+ -#= "Correlation plot"
+ -#= cv.correlation_plot
+ %br
+ -#= "Confidence plot:"
+ -#= cv.confidence_plot
+ %hr
%fieldset#bottom.well
diff --git a/views/style.scss b/views/style.scss
index 0802545..fd05c3e 100644
--- a/views/style.scss
+++ b/views/style.scss
@@ -1,230 +1,10 @@
-$ist-color: rgba(200, 194, 200, 0.4);
-$black: #2b2b2b;
-$orange: #f76700;
-
-body {
- background-image: url("/images/gray_jean.png");
- overflow: scroll;
- font-family: sans-serif; }
- body a {
- &:hover {
- color: $orange; }
- text-decoration: none;
- font-weight: bold;
- color: $black; }
- body img {
- border: 0; }
- body h1 {
- color: $black; }
- body h2 {
- padding-top: 12px;
- font-size: x-large;
- color: $orange; }
-
-.logo {
- top: 0;
- position: fixed;
- background-color: #efefef;
- width: 100%;
- z-index: 40; }
- .logo img {
- float: left;
- display: inline;
- margin-right: 1em;
- padding: 1em; }
- .logo h1 {
- width: 80%; }
- .logo img.ote {
- width: 100px;
- height: 50px;
- display: inline;
- float: right; }
-
-.content {
- background-image: url("/images/gray_jean.png");
- margin-top: 6em; }
- .content h1 {
- text-shadow: white 1px 1px 0;
- font-size: x-large;
- display: inline; }
- .content .arrow {
- margin: 8px 0px 5px 20px; }
- .content .back {
- display: inline; }
- .content fieldset#top {
- border: 0;
- padding: 10px;
- background-color: $ist-color; }
- .content fieldset#top a#linkInsert {
- display: block;
- width: 100%;
- height: 2em; }
- .content fieldset#top #appletContainer {
- padding: 10px; }
- .content fieldset#middle {
- border: 0;
- padding: 10px;
- background-color: $ist-color; }
- .content fieldset#middle a#linkModels {
- display: block;
- width: 100%;
- height: 2em; }
- .content fieldset#middle #models {
- padding-left: 1em; }
- .content fieldset#middle #model a {
- display: inline;
- font-weight: normal; }
- .content fieldset#bottom {
- border: 0;
- background-color: $ist-color;
- padding: 10px;
- margin-bottom: 5em; }
- .content fieldset#bottom input#predict {
- margin-left: 1em; }
- .content .predictions {
- background-color: $ist-color;
- padding: 10px;
- text-align: justify; }
- .content .overview {
- padding: 12px;
- margin-top: 1em;
- margin-bottom: 1em;
- text-align: left; }
- .content .overview a:hover {
- color: $orange; }
- .content .overview caption {
- text-align: left; }
- .content .overview #overview tr td {
- background-color: white;
- border: 1px solid #dad9c7;
- padding-left: 1em;
- padding-top: 0.5em; }
- .content .overview #overview tr td#compound {
- width: 250px; }
- .content .overview #overview tr td b.c {
- color: #d42200; }
- .content .overview #overview tr td b.n {
- color: #5c8533; }
- .content .overview #overview tr td .confidence {
- display: inline; }
- .content .error {
- background-color: $ist-color;
- box-shadow: (1px 1px 1px rgba(white, 1) inset, -1px -1px 5px rgba($black, 0.3) inset);
- padding: 15px; }
- .content .error .message {
- margin: 2em;
- padding: 1em;
- border: 2px solid $orange;
- background-color: white;
- color: $black; }
- .content #closebutton {
- color: $orange;
- margin-left: 98%; }
-
-.details {
- width: 98%;
- box-shadow: (1px 1px 1px rgba(white, 1) inset, -1px -1px 5px rgba($black, 0.3) inset);
- background-color: $ist-color; }
- .details a:hover {
- color: $orange; }
- .details img {
- display: inline;
- float: left;
- margin: 0.5em; }
-
-.significant_fragments {
- width: 98%;
- margin-bottom: 2em;
- box-shadow: (1px 1px 1px rgba(white, 1) inset, -1px -1px 5px rgba($black, 0.3) inset);
- background-color: $ist-color; }
- .significant_fragments img {
- display: inline;
- float: left;
- margin: 0.5em; }
- .significant_fragments table#sf1 {
- text-align: left; }
- .significant_fragments table#sf1 td {
- padding: 0.2em; }
-
- img.smarts{
- width: 100px;
- //float: left;
- }
- img.smarts:hover{
- transform: scale(4);
- border: solid 1px black;
- }
-
-.descriptors {
- width: 98%;
- margin-bottom: 2em;
- box-shadow: (1px 1px 1px rgba(white, 1) inset, -1px -1px 5px rgba($black, 0.3) inset);
- background-color: $ist-color; }
- .descriptors img {
- display: inline;
- float: left;
- margin: 0.5em; }
- .descriptors table#sf2 {
- text-align: left; }
- .descriptors table#sf2 td {
- padding: 0.2em; }
-
-.results {
- overflow-x: auto;
- overflow-y: hidden;
- margin-top: 2em;
- margin-bottom: 2em; }
- .results a:hover {
- color: $orange; }
- .results .tablesorter {
- width: 100%;
- text-align: left; }
- .results .tablesorter thead {
- background-color: $ist-color; }
- .results .tablesorter thead tr th.header {
- background-image: url("/images/bg.gif");
- background-repeat: no-repeat;
- background-position: center left;
- cursor: pointer;
- padding-left: 20px;
- border: 1px solid #dad9c7;
- margin-left: -1px; }
- .results .tablesorter thead tr th.headerSortDown {
- background-image: url("/images/desc.gif");
- background-color: $ist-color; }
- table.tablesorter .tablesorter-default thead tr .tablesorter-headerRow th .tablesorter-header .tablesorter-headerAsc {
- background-image: url("/images/asc.gif");
- background-color: $ist-color; }
- .results .tablesorter tbody tr td {
- border-spacing: 1px;
- padding-left: 1em; }
- .results .tablesorter tbody .compound {
- width: 250px;
- padding: 0.2em; }
- .results .tablesorter tbody .n {
- color: #5c8533; }
- .results .tablesorter tbody .c {
- color: #d42200; }
-
-input#predict {
- border: 0px;
- background-color: $ist-color;
- margin: 0;
- padding: 0; }
-
-.tooltip {
- background-color: white;
- border: 2px solid $orange;
- font-size: 0.5em;
- padding: 1em;
- display: none;
- z-index: 50; }
-
-.footer {
- margin: 20px 0 20px 0; }
- .footer a {
- text-decoration: none;
- color: black; }
- .footer a:hover {
- color: $orange; }
-
+table.table-borderless tbody tr td{
+ border-top: none;
+}
+
+h4.head-back, h5.head-back{
+ background-color: #E7E7E7;
+}
+//.btn:focus{
+ //background: #f0ad4e;
+//}