From ddbe5c5478c7dd71d9c851008340e28a61d5ba33 Mon Sep 17 00:00:00 2001 From: gebele Date: Tue, 27 Oct 2015 12:24:58 +0000 Subject: enabled batch --- views/predict.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/views/predict.haml b/views/predict.haml index 9863cd9..0dc767b 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -125,12 +125,11 @@ %br %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'} %p - // disable for public version %label{:for=>"fileselect"} or upload a CSV file for batch predictions (disabled in public version) %br %span.btn.btn-default.btn-file - %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv", :disabled=>"disabled"} + %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv"} %fieldset#middle.well %h2 2. Select one or more endpoints -- cgit v1.2.3 From 41f948d58ba99a635ae7e04573bd368d9ab34d99 Mon Sep 17 00:00:00 2001 From: gebele Date: Tue, 27 Oct 2015 12:26:14 +0000 Subject: enabled batch --- views/predict.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/predict.haml b/views/predict.haml index 0dc767b..a4fa080 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -126,7 +126,7 @@ %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'} %p %label{:for=>"fileselect"} - or upload a CSV file for batch predictions (disabled in public version) + or upload a CSV file for batch predictions %br %span.btn.btn-default.btn-file %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv"} -- cgit v1.2.3 From d2d8db1e59e830b1a24e9b8d270a3b393d746b6c Mon Sep 17 00:00:00 2001 From: gebele Date: Wed, 28 Oct 2015 13:58:45 +0000 Subject: consisten use of brackets for units; collect measured activity for equal neighbors --- views/batch.haml | 3 +-- views/neighbors.haml | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/views/batch.haml b/views/batch.haml index 8389651..ec987c4 100644 --- a/views/batch.haml +++ b/views/batch.haml @@ -44,7 +44,7 @@ %br %b Prediction: / TODO scientific notation - = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} #{model.unit}" : prediction[:value] + = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit})" : prediction[:value] %br / TODO probability %b Confidence: @@ -53,4 +53,3 @@ - else %p = "Not enough similar compounds
in training dataset." - %p diff --git a/views/neighbors.haml b/views/neighbors.haml index 21b4b35..a741b45 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -58,7 +58,7 @@ / %td %tbody - type = @model_types[j] - - prediction[:neighbors].each_with_index do |neighbor,count| + - prediction[:neighbors].uniq.each_with_index do |neighbor,count| %tr / Compound %td{:style =>"vertical-align:middle;padding-left:1em;width:50%;"} @@ -67,7 +67,7 @@ %p= Compound.find(neighbor[0]).smiles / Measured Activity %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;"} - = (type == "Regression") ? neighbor[2].collect{|n| '%.2e' % n + " (#{@models[j].unit})"}.join(", ") : neighbor[2].join(", ") + = (type == "Regression") ? neighbor[2].collect{|n| '%.2e' % n + " (#{@models[j].unit})"}.join("
") : neighbor[2].join(", ") / Similarity %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;"} / TODO differentiate between no neighbors found and compound found in dataset, display neighbors for compounds in dataset? -- cgit v1.2.3 From b452a81e9c0a470bf9aa51f0192378f5fba5177a Mon Sep 17 00:00:00 2001 From: gebele Date: Thu, 29 Oct 2015 09:54:15 +0000 Subject: trim and log SMILES input --- application.rb | 14 ++++++++------ views/predict.haml | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/application.rb b/application.rb index 9c9cabb..d77842d 100644 --- a/application.rb +++ b/application.rb @@ -259,12 +259,14 @@ post '/predict/?' do # validate identifier input # transfered input 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." + # remove whitespaces they terminate a SMILES string + # can result in wrong conversion for compound object + @identifier = params[:identifier].gsub(/\s+/, "") + $logger.debug "input:#{@identifier}" + # get compound from SMILES + @compound = Compound.from_smiles @identifier + if @compound.blank? + @error_report = "Attention, '#{@identifier}' is not a valid SMILES string." return haml :error end diff --git a/views/predict.haml b/views/predict.haml index a4fa080..7f19071 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -24,7 +24,7 @@ }); function getInput(){ - identifier = document.getElementById("identifier").value; + identifier = document.getElementById("identifier").value.trim(); fileselect = document.getElementById("fileselect").value; if (fileselect != ""){ return 1; -- cgit v1.2.3 From 95236e48e8a1da009e6b5ab1789f0de37dde36f5 Mon Sep 17 00:00:00 2001 From: gebele Date: Thu, 29 Oct 2015 12:55:57 +0000 Subject: patch merge --- application.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/application.rb b/application.rb index d77842d..229f3a1 100644 --- a/application.rb +++ b/application.rb @@ -259,9 +259,7 @@ post '/predict/?' do # validate identifier input # transfered input if !params[:identifier].blank? - # remove whitespaces they terminate a SMILES string - # can result in wrong conversion for compound object - @identifier = params[:identifier].gsub(/\s+/, "") + @identifier = params[:identifier] $logger.debug "input:#{@identifier}" # get compound from SMILES @compound = Compound.from_smiles @identifier -- cgit v1.2.3 From efd241beab11fbfc200f0c32ffb9e198ed406c83 Mon Sep 17 00:00:00 2001 From: gebele Date: Thu, 29 Oct 2015 18:20:39 +0000 Subject: added mg/kg_bw/day --- application.rb | 6 ++++-- views/batch.haml | 5 +++-- views/neighbors.haml | 6 ++++-- views/prediction.haml | 6 +++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/application.rb b/application.rb index 229f3a1..1763e3a 100644 --- a/application.rb +++ b/application.rb @@ -202,14 +202,16 @@ get '/predict/?:csv?' do model = array[0] prediction = array[1] compound = key.smiles + mw = key.molecular_weight + weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw) endpoint = "#{model.endpoint.gsub('_', ' ')} (#{model.species})" if prediction[:confidence] == "measured" type = "" - pred = prediction[:value].numeric? ? "#{prediction[:value].round(3)} (#{model.unit})" : prediction[:value] + pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] confidence = "measured activity" elsif prediction[:neighbors].size > 0 type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression" - pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} #{model.unit}" : prediction[:value] + pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} #{model.unit} | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] confidence = prediction[:confidence] else type = "" diff --git a/views/batch.haml b/views/batch.haml index ec987c4..f593188 100644 --- a/views/batch.haml +++ b/views/batch.haml @@ -18,6 +18,7 @@ / key = compound, values = array of arrays with model, prediction - @batch.each do |key, values| - compound = key + - mw = compound.molecular_weight %tr %td{:style=>"vertical-align:top;"} %p= compound.svg @@ -34,7 +35,7 @@ %p / TODO fix scientific notation from database %b Measured activity: - = prediction[:value].numeric? ? "#{prediction[:value].round(3)} (#{model.unit})" : prediction[:value] + = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] %p Compound is part of the training dataset - elsif prediction[:neighbors].size > 0 %p @@ -44,7 +45,7 @@ %br %b Prediction: / TODO scientific notation - = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit})" : prediction[:value] + = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] %br / TODO probability %b Confidence: diff --git a/views/neighbors.haml b/views/neighbors.haml index a741b45..4a1f3ea 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -65,9 +65,11 @@ /%a.btn.btn-link{:href => "#details#{j+1}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(neighbor[0].to_s)}/details"), :id=>"link#{j+1}#{count}"}} %p= Compound.find(neighbor[0]).svg %p= Compound.find(neighbor[0]).smiles + - c = Compound.find(neighbor[0]) + - mw = c.molecular_weight / Measured Activity - %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;"} - = (type == "Regression") ? neighbor[2].collect{|n| '%.2e' % n + " (#{@models[j].unit})"}.join("
") : neighbor[2].join(", ") + %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;white-space:nowrap;"} + = (type == "Regression") ? neighbor[2].collect{|n| weight = c.mmol_to_mg(n, mw); '%.2e' % n + " (#{@models[j].unit})"+"|#{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : neighbor[2].join(", ") / Similarity %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;"} / TODO differentiate between no neighbors found and compound found in dataset, display neighbors for compounds in dataset? diff --git a/views/prediction.haml b/views/prediction.haml index ef0c5db..11d542e 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -18,6 +18,7 @@ %td{:id=>"compound", :style=>"vertical-align:top;"} %p= @compound.svg %p= @compound.smiles + - mw = @compound.molecular_weight - @model_types = {} - @dbhit = {} - @predictions.each_with_index do |prediction,i| @@ -32,7 +33,7 @@ %p / TODO fix scientific notation from database %b Measured activity: - = (type == "Regression") ? "#{"%.2e" % prediction[:value]} (#{@models[i].unit})" : prediction[:value] + = (type == "Regression") ? "#{"%.2e" % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] %p Compound is part of the training dataset - elsif prediction[:neighbors].size > 0 %p @@ -41,8 +42,7 @@ = type %br %b Prediction: - / TODO scientific notation - = (type == "Regression") ? "#{'%.2e' % prediction[:value]} (#{@models[i].unit})" : prediction[:value] + = (type == "Regression") ? "#{'%.2e' % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] / TODO update description / %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction", data: {toggle:"popover", placement:"left", html:"true", content:"LAZAR calculates searches the training dataset for similar compounds (neighbors) and calculates the prediction from their measured activities. LAZAR calculates predictions using Please keep in mind that predictions are based on the measured activities of neighbors."}} %br -- cgit v1.2.3 From a348f222c0b32bbb308083bb03127fe55b1563dc Mon Sep 17 00:00:00 2001 From: gebele Date: Fri, 30 Oct 2015 08:26:04 +0000 Subject: fixed weight for multiple database hits in prediction --- application.rb | 23 +++++++++++++++++------ views/batch.haml | 12 +++++++----- views/prediction.haml | 10 +++++++--- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/application.rb b/application.rb index 1763e3a..fc7e415 100644 --- a/application.rb +++ b/application.rb @@ -203,22 +203,33 @@ get '/predict/?:csv?' do prediction = array[1] compound = key.smiles mw = key.molecular_weight - weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw) endpoint = "#{model.endpoint.gsub('_', ' ')} (#{model.species})" if prediction[:confidence] == "measured" - type = "" - pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] - confidence = "measured activity" + if prediction[:value].is_a?(Array) + prediction[:value].each do |value| + type = "" + weight = Compound.from_smiles(compound).mmol_to_mg(value, mw) + pred = value.numeric? ? "#{'%.2e' % value} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : value + confidence = "measured activity" + @csv += "\"#{compound}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{confidence}\"\n" + end + else + type = "" + weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw) + pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] + confidence = "measured activity" + end elsif prediction[:neighbors].size > 0 + weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw) type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression" - pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} #{model.unit} | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] + pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] confidence = prediction[:confidence] else type = "" pred = "Not enough similar compounds in training dataset." confidence = "" end - @csv += "\"#{compound}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{confidence}\"\n" + @csv += "\"#{compound}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{confidence}\"\n" unless prediction[:value].is_a?(Array) end end @csv diff --git a/views/batch.haml b/views/batch.haml index f593188..9bfa67e 100644 --- a/views/batch.haml +++ b/views/batch.haml @@ -33,10 +33,13 @@ %p - if prediction[:confidence] == "measured" %p - / TODO fix scientific notation from database - %b Measured activity: - = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] - %p Compound is part of the training dataset + %b Measured activity: + - if prediction[:value].is_a?(Array) + = prediction[:value][0].numeric? ? prediction[:value].collect{|v| weight = compound.mmol_to_mg(v, mw); '%.2e' % v + " (#{model.unit})"+" | #{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : prediction[:value].join(", ") + - else + = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] + %p + %b Compound is part of the training dataset - elsif prediction[:neighbors].size > 0 %p / model type (classification|regression) @@ -44,7 +47,6 @@ = model.model.class.to_s.match("Classification") ? "Classification" : "Regression" %br %b Prediction: - / TODO scientific notation = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] %br / TODO probability diff --git a/views/prediction.haml b/views/prediction.haml index 11d542e..a74b95a 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -31,10 +31,14 @@ - if prediction[:confidence] == "measured" - @dbhit[i] = true %p - / TODO fix scientific notation from database %b Measured activity: - = (type == "Regression") ? "#{"%.2e" % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] - %p Compound is part of the training dataset + - p prediction[:value] + - if prediction[:value].is_a?(Array) + = (type == "Regression") ? prediction[:value].collect{|v| weight = Compound.from_smiles(@compound.smiles).mmol_to_mg(v, mw); '%.2e' % v + " (#{@models[i].unit})"+"|#{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : prediction[:value].join(", ") + - else + = (type == "Regression") ? "#{"%.2e" % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] + %p + %b Compound is part of the training dataset - elsif prediction[:neighbors].size > 0 %p / model type (classification|regression) -- cgit v1.2.3 From f7680842ee830af78d860b3a0a09b654368df90a Mon Sep 17 00:00:00 2001 From: gebele Date: Thu, 14 Jan 2016 09:37:39 +0000 Subject: changed weight method for lazar v8-nestec release --- views/neighbors.haml | 4 ++-- views/prediction.haml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/views/neighbors.haml b/views/neighbors.haml index 4a1f3ea..a69f38b 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -66,10 +66,10 @@ %p= Compound.find(neighbor[0]).svg %p= Compound.find(neighbor[0]).smiles - c = Compound.find(neighbor[0]) - - mw = c.molecular_weight + //- mw = c.molecular_weight / Measured Activity %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;white-space:nowrap;"} - = (type == "Regression") ? neighbor[2].collect{|n| weight = c.mmol_to_mg(n, mw); '%.2e' % n + " (#{@models[j].unit})"+"|#{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : neighbor[2].join(", ") + = (type == "Regression") ? neighbor[2].collect{|n| weight = c.mmol_to_mg(n); '%.2e' % n + " (#{@models[j].unit})"+"|#{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : neighbor[2].join(", ") / Similarity %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;"} / TODO differentiate between no neighbors found and compound found in dataset, display neighbors for compounds in dataset? diff --git a/views/prediction.haml b/views/prediction.haml index a74b95a..8d7e3d0 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -18,7 +18,7 @@ %td{:id=>"compound", :style=>"vertical-align:top;"} %p= @compound.svg %p= @compound.smiles - - mw = @compound.molecular_weight + -#- mw = @compound.molecular_weight - @model_types = {} - @dbhit = {} - @predictions.each_with_index do |prediction,i| @@ -34,9 +34,9 @@ %b Measured activity: - p prediction[:value] - if prediction[:value].is_a?(Array) - = (type == "Regression") ? prediction[:value].collect{|v| weight = Compound.from_smiles(@compound.smiles).mmol_to_mg(v, mw); '%.2e' % v + " (#{@models[i].unit})"+"|#{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : prediction[:value].join(", ") + = (type == "Regression") ? prediction[:value].collect{|v| weight = Compound.from_smiles(@compound.smiles).mmol_to_mg(v); '%.2e' % v + " (#{@models[i].unit})"+"|#{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : prediction[:value].join(", ") - else - = (type == "Regression") ? "#{"%.2e" % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] + = (type == "Regression") ? "#{"%.2e" % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value])} (mg/kg_bw/day)" : prediction[:value] %p %b Compound is part of the training dataset - elsif prediction[:neighbors].size > 0 @@ -46,7 +46,7 @@ = type %br %b Prediction: - = (type == "Regression") ? "#{'%.2e' % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] + = (type == "Regression") ? "#{'%.2e' % prediction[:value]} (#{@models[i].unit}) | #{'%.2e' % @compound.mmol_to_mg(prediction[:value])} (mg/kg_bw/day)" : prediction[:value] / TODO update description / %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction", data: {toggle:"popover", placement:"left", html:"true", content:"LAZAR calculates searches the training dataset for similar compounds (neighbors) and calculates the prediction from their measured activities. LAZAR calculates predictions using Please keep in mind that predictions are based on the measured activities of neighbors."}} %br -- cgit v1.2.3 From f0588c7e072ea3e22f26916d669e9baaa8fa3197 Mon Sep 17 00:00:00 2001 From: gebele Date: Tue, 26 Jan 2016 11:45:30 +0000 Subject: enabled sticky headers for neighbors table --- views/neighbors.haml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/views/neighbors.haml b/views/neighbors.haml index a69f38b..6001605 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -29,7 +29,20 @@ debug: false, theme: "bootstrap", headerTemplate: '{content} {icon}', - widgets: ['zebra', 'columns', 'uitheme'], + widgets: ['zebra', 'columns', 'uitheme', 'stickyHeaders'], + widgetOptions: { + stickyHeaders_attachTo : '.tab-content', + stickyHeaders : '', + stickyHeaders_offset : 0, + stickyHeaders_cloneId : '-sticky', + stickyHeaders_addResizeEvent : true, + stickyHeaders_includeCaption : true, + stickyHeaders_zIndex : 2, + stickyHeaders_attachTo : null, + stickyHeaders_xScroll : null, + stickyHeaders_yScroll : null, + stickyHeaders_filteredToTop: true + }, headers: {0: {sorter: false}, 3: {sorter: false}}, sortList: [[2,1]], widthFixed: false -- cgit v1.2.3 From c5ca09fb039e38abd89005d49ef373cf18b79039 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 28 Nov 2016 14:13:18 +0000 Subject: bumped version;training dataset download;show warnings for batch;csv info and upload catch;code cleanup --- VERSION | 2 +- application.rb | 235 +++++++---------------------------------------- config.ru | 2 +- lazar-gui.gemspec | 2 +- views/batch.haml | 106 ++++++++++++++------- views/layout.haml | 38 +------- views/model_details.haml | 4 + views/neighbors.haml | 13 ++- views/predict.haml | 1 + views/prediction.haml | 103 +++++++++++---------- 10 files changed, 180 insertions(+), 326 deletions(-) diff --git a/VERSION b/VERSION index 9084fa2..ec63514 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0 +9 diff --git a/application.rb b/application.rb index 5f64b84..eefd833 100644 --- a/application.rb +++ b/application.rb @@ -1,11 +1,6 @@ #require_relative 'helper.rb' require 'rdiscount' include OpenTox -#require File.join(ENV["HOME"],".opentox","config","lazar-gui.rb") # until added to ot-tools - -# DG: workaround for https://github.com/sinatra/sinatra/issues/808 -# Date: 18/11/2013 -#set :protection, :except => :path_traversal configure :development do $logger = Logger.new(STDOUT) @@ -38,16 +33,6 @@ end get '/predict/modeldetails/:model' do model = OpenTox::Model::Prediction.find params[:model] crossvalidations = OpenTox::Validation::RepeatedCrossValidation.find(model.repeated_crossvalidation_id).crossvalidations - #confidence_plots = crossvalidations.collect{|cv| [cv.id, cv.confidence_plot]} - #confidence_plots.each do |confp| - # File.open(File.join('public', "confp#{confp[0]}.svg"), 'w'){|file| file.write(confp[1])} unless File.exists? File.join('public', "confp#{confp[0]}.svg") - #end - #if model.regression? - # correlation_plots = crossvalidations.collect{|cv| [cv.id, cv.correlation_plot]} - # correlation_plots.each do |corrp| - # File.open(File.join('public', "corrp#{corrp[0]}.svg"), 'w'){|file| file.write(corrp[1])} unless File.exists? File.join('public', "corrp#{corrp[0]}.svg") - # end - #end return haml :model_details, :layout=> false, :locals => {:model => model, :crossvalidations => crossvalidations} end @@ -56,198 +41,47 @@ get '/jme_help/?' do File.read(File.join('views','jme_help.html')) end -# get individual compound details -get '/prediction/:neighbor/details/?' do - @compound = OpenTox::Compound.new params[:neighbor] - @smiles = @compound.smiles - task = OpenTox::Task.run("Get names for '#{@smiles}'.") do - names = @compound.names - end - task.wait - - case task[RDF::OT.hasStatus] - when "Error" - @names = "No names for this compound available." - when "Completed" - @names = @compound.names - else - @names = "No names for this compound available." - end - @inchi = @compound.inchi.gsub("InChI=", "") - - haml :details, :layout => false -end -=begin -# sdf representation for datasets -#TODO fix 502 errors from compound service -get '/predict/:dataset_uri/sdf/?' do - uri = CGI.unescape(params[:dataset_uri]) - $logger.debug uri - bad_request_error "Not a dataset uri." unless URI.dataset? uri - dataset = OpenTox::Dataset.find uri - @compounds = dataset.compounds - @data_entries = dataset.data_entries - sum="" - @compounds.each_with_index{ |c, idx| - sum << c.inchi - sum << c.sdf.sub(/\n\$\$\$\$/,'') - @data_entries[idx].each{ |f,v| - sum << "> <\"#{f}\">\n" - sum << v.join(", ") - sum << "\n\n" - } - sum << "$$$$\n" - } - send_file sum, :filename => "#{dataset.title}.sdf" -end -=end -# fingerprints for compound in predictions -get '/prediction/:model_uri/:type/:compound_uri/fingerprints/?' do - @type = params[:type] - model = OpenTox::Model::Lazar.find params[:model_uri] - feature_dataset = OpenTox::Dataset.find model[RDF::OT.featureDataset] - @compound = OpenTox::Compound.new params[:compound_uri] - @significant_fragments = [] - if @type =~ /classification/i - # collect all feature values with fingerprint - fingerprints = OpenTox::Algorithm::Descriptor.send("smarts_match", [@compound], feature_dataset.features.collect{ |f| f[RDF::DC.title]})[@compound.uri] - #$logger.debug "fingerprints:\t#{fingerprints}\n" - - # collect fingerprints with value 1 - @fingerprint_values = fingerprints.collect{|smarts, value| [smarts, value] if value > 0} - - # collect all features from feature_dataset - @features = feature_dataset.features.collect{|f| f } - - # search for each fingerprint in all features and collect feature values( effect, smarts, pValue ) - @fingerprint_values.each{ |fi, v| @features.each{ |f| @significant_fragments << [f[RDF::OT.effect].to_i, f[RDF::OT.smarts], f[RDF::OT.pValue]] if fi == f[RDF::OT.smarts] } } - - # pass value_map, important to interprete effect value - prediction_feature_uri = "" - model.parameters.each {|p| - if p[RDF::DC.title].to_s == "prediction_feature_uri" - prediction_feature_uri = p[RDF::OT.paramValue].object - end - } - prediction_feature = OpenTox::Feature.find prediction_feature_uri - @value_map = prediction_feature.value_map - - else #regression - feature_calc_algo = "" - model.parameters.each {|p| - if p[RDF::DC.title].to_s == "feature_calculation_algorithm" - feature_calc_algo = p[RDF::OT.paramValue].object - end - } - - @desc = [] - fingerprints = OpenTox::Algorithm::Descriptor.send( feature_calc_algo, [ @compound ], feature_dataset.features.collect{ |f| f[RDF::DC.title] } ) - fingerprints.each{|x, h| h.each{|descriptor, value| @desc << [descriptor, [value]]}} - - pc_descriptor_titles_descriptions = {} - feature_dataset.features.collect{ |f| - pc_descriptor_titles_descriptions[f[RDF::DC.title]]= f[RDF::DC.description] - } - - @desc.each{|d, v| @significant_fragments << [pc_descriptor_titles_descriptions[d], v] } - end - - haml :significant_fragments, :layout => false -end - -get '/prediction/:model_uri/:type/:neighbor/significant_fragments/?' do - @type = params[:type] - @compound = OpenTox::Compound.new params[:neighbor] - model = OpenTox::Model::Lazar.find params[:model_uri] - #$logger.debug "model for significant fragments:\t#{model.uri}" - - feature_dataset = OpenTox::Dataset.find model[RDF::OT.featureDataset] - $logger.debug "feature_dataset_uri:\t#{feature_dataset.uri}\n" - - # load all compounds - feature_dataset.compounds - - # load all features - @features = feature_dataset.features.collect{|f| f} - - # find all features and values for a neighbor compound - @significant_fragments = [] - # check type first - if @type =~ /classification/i - # get compound index in feature dataset - c_idx = feature_dataset.compound_indices @compound.uri - - # collect feature uris with value - @feat = @features.collect{|f| [feature_dataset.data_entry_value(c_idx[0], f.uri), f.uri]} - #$logger.debug "@feat:\t#{@feat}\n" - - # pass feature uris if value > 0 - @feat.each do |f| - # search relevant features - if f[0] > 0 - f = OpenTox::Feature.find f[1] - # pass relevant features with [ effect, smarts, pValue ] - @significant_fragments << [f[RDF::OT.effect].to_i, f[RDF::OT.smarts], f[RDF::OT.pValue].to_f.round(3)] - end - end - # pass value_map, important to interprete effect value - prediction_feature_uri = "" - model.parameters.each {|p| - if p[RDF::DC.title].to_s == "prediction_feature_uri" - prediction_feature_uri = p[RDF::OT.paramValue].object - end - } - prediction_feature = OpenTox::Feature.find prediction_feature_uri - @value_map = prediction_feature.value_map - - else # regression - # find a value in feature dataset by compound and feature - @values = @features.collect{|f| feature_dataset.values(@compound, f)} - #$logger.debug "values in fd:\t#{@values}" - - @features.each_with_index{|f, i| @significant_fragments << [f.description, @values[i]]} - end - #$logger.debug "significant fragments:\t#{@significant_fragments}\n" - - haml :significant_fragments, :layout => false +get '/predict/dataset/:name' do + response['Content-Type'] = "text/csv" + dataset = Dataset.find_by(:name=>params[:name]) + csv = dataset.to_csv + csv end get '/predict/?:csv?' do response['Content-Type'] = "text/csv" - @csv = "\"Compound\",\"Endpoint\",\"Type\",\"Prediction\",\"Confidence\"\n" + @csv = "\"Compound\",\"Endpoint\",\"Type\",\"Prediction\",\"95% Prediction interval\"\n" @@batch.each do |key, values| + compound = key + smiles = compound.smiles values.each do |array| model = array[0] + type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression" prediction = array[1] - compound = key.smiles - mw = key.molecular_weight endpoint = "#{model.endpoint.gsub('_', ' ')} (#{model.species})" if prediction[:confidence] == "measured" if prediction[:value].is_a?(Array) prediction[:value].each do |value| - type = "" - weight = Compound.from_smiles(compound).mmol_to_mg(value, mw) - pred = value.numeric? ? "#{'%.2e' % value} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : value - confidence = "measured activity" - @csv += "\"#{compound}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{confidence}\"\n" + pred = value.numeric? ? "#{value} (#{model.unit}), #{compound.mmol_to_mg(value.delog10)} #{(model.unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : value + int = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval]) + interval = (int.nil? ? "--" : "#{int[1].delog10} - #{int[0].delog10} (#{model.unit})") + @csv += "\"#{smiles}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{interval}\"\n" end else - type = "" - weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw) - pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] + pred = prediction[:value].numeric? ? "#{prediction[:value]} (#{model.unit}), #{compound.mmol_to_mg(prediction[:value].delog10)} #{(model.unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value] confidence = "measured activity" end elsif prediction[:neighbors].size > 0 - weight = Compound.from_smiles(compound).mmol_to_mg(prediction[:value], mw) type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression" - pred = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % weight} (mg/kg_bw/day)" : prediction[:value] - confidence = prediction[:confidence] + pred = prediction[:value].numeric? ? "#{prediction[:value].delog10} (#{model.unit}), #{compound.mmol_to_mg(prediction[:value].delog10)} #{(model.unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value] + int = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval]) + interval = (int.nil? ? "--" : "#{int[1].delog10} - #{int[0].delog10} (#{model.unit})") else type = "" pred = "Not enough similar compounds in training dataset." - confidence = "" + interval = "" end - @csv += "\"#{compound}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{confidence}\"\n" unless prediction[:value].is_a?(Array) + @csv += "\"#{smiles}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{interval}\"\n" unless prediction[:value].is_a?(Array) end end @csv @@ -265,11 +99,21 @@ post '/predict/?' do f.write(params[:fileselect][:tempfile].read) end @filename = params[:fileselect][:filename] - input = OpenTox::Dataset.from_csv_file File.join "tmp", params[:fileselect][:filename] - dataset = OpenTox::Dataset.find input.id + begin + input = OpenTox::Dataset.from_csv_file File.join("tmp", params[:fileselect][:filename]), true + if input.class == OpenTox::Dataset + dataset = OpenTox::Dataset.find input + else + @error_report = "Could not serialize file '#{@filename}' ." + return haml :error + end + rescue + @error_report = "Could not serialize file '#{@filename}' ." + return haml :error + end @compounds = dataset.compounds if @compounds.size == 0 - @error_report = "No valid SMILES submitted." + @error_report = dataset[:warnings] dataset.delete return haml :error end @@ -283,7 +127,9 @@ post '/predict/?' do end end @@batch = @batch + @warnings = dataset[:warnings] dataset.delete + File.delete File.join("tmp", params[:fileselect][:filename]) return haml :batch end @@ -295,7 +141,7 @@ post '/predict/?' do # get compound from SMILES @compound = Compound.from_smiles @identifier if @compound.blank? - @error_report = "Attention, '#{@identifier}' is not a valid SMILES string." + @error_report = "'#{@identifier}' is not a valid SMILES string." return haml :error end @@ -310,17 +156,6 @@ post '/predict/?' do end end -get '/license' do - @license = RDiscount.new(File.read("LICENSE.md")).to_html - haml :license, :layout => false -end - -=begin -get '/faq' do - @faq = RDiscount.new(File.read("FAQ.md")).to_html - haml :faq, :layout => :faq_layout -end -=end get '/style.css' do headers 'Content-Type' => 'text/css; charset=utf-8' scss :style diff --git a/config.ru b/config.ru index 7ee908a..8f9daf5 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,4 @@ -ENV["LAZAR_ENV"] = "development" +ENV["LAZAR_ENV"] = "production" require 'bundler' Bundler.require require File.expand_path './application.rb' diff --git a/lazar-gui.gemspec b/lazar-gui.gemspec index af5f0f9..9a43bd8 100644 --- a/lazar-gui.gemspec +++ b/lazar-gui.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |s| s.rubyforge_project = "lazar-gui" s.files = `git ls-files`.split("\n") - s.add_runtime_dependency "lazar", "~> 0.9.3", '>= 0.9.3' + s.add_runtime_dependency "lazar" s.add_runtime_dependency "gem-path", "~> 0.6.1", '>= 0.6.1' s.add_runtime_dependency "sinatra", "~> 1.4.0", '>= 1.4.0' s.add_runtime_dependency "rdiscount", "~> 2.1.0", '>= 2.1.0' diff --git a/views/batch.haml b/views/batch.haml index 9bfa67e..6c37a2b 100644 --- a/views/batch.haml +++ b/views/batch.haml @@ -2,57 +2,99 @@ %a.btn.btn-warning{:href => to('/predict')} %span.glyphicon.glyphicon-menu-left{:aria=>{:hidden=>"true"}} New Prediction - / displays all prediction result in first table + %a.btn.btn-success{:href=>"#{to("/predict/#{@filename}")}", :title=>"download"} + %span.glyphicon.glyphicon-download-alt + download CSV + + / show processed file name + %topline + %div.row + %div.col-md-4 + %h3 Batch Prediction Results: + %div.col-md-8 + %h3= @filename + + / displays all prediction result in one table %div.table-responsive %table.table.table-bordered{:id=>"batch", :style=>"background-color:white;"} - %thead - %tr - %h3.col-md-4{:style=>"padding-left:0;"} Batch Prediction Results: - %h3.col-md-8= @filename - %tr - %span.btn.btn-default - %a{:href=>"#{to("/predict/#{@filename}")}", :title=>"download"} - %span.glyphicon.glyphicon-download-alt{:aria=>{:hidden=>"true"}} - CSV %tbody - / key = compound, values = array of arrays with model, prediction + - if @warnings + - @warnings.each do |warning| + %tr + %td + %b Warning + %td + = warning.sub(/\b(tmp\/)\b/,"") + / key = compound, values = [model,prediction] - @batch.each do |key, values| - compound = key - - mw = compound.molecular_weight %tr %td{:style=>"vertical-align:top;"} %p= compound.svg %p= compound.smiles - / array = single prediction [endpoint, result] + + / array[0] = model, array[1] = prediction - values.each_with_index do |array,i| %td{:style=>"vertical-align:top;white-space:nowrap;"} - model = array[0] + / model type (classification|regression) + - model.model.class.to_s.match("Classification") ? type = "Classification" : type = "Regression" + - unit = model.unit - prediction = array[1] + %b{:class => "title"} = "#{model.endpoint.gsub('_', ' ')} (#{model.species})" - %p - - if prediction[:confidence] == "measured" + + / check for prediction + - if prediction[:neighbors].size > 0 %p - %b Measured activity: - - if prediction[:value].is_a?(Array) - = prediction[:value][0].numeric? ? prediction[:value].collect{|v| weight = compound.mmol_to_mg(v, mw); '%.2e' % v + " (#{model.unit})"+" | #{'%.2e' % weight} (mg/kg_bw/day)"}.join("
") : prediction[:value].join(", ") - - else - = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] + / show model type (classification|regression) + %b Type: + = type %p - %b Compound is part of the training dataset - - elsif prediction[:neighbors].size > 0 + / check for database hit + - if prediction[:warning] =~ /\b(identical)\b/i + + / show message about dbhit and measurements + %p + %b Compound is part of the training dataset + %p + %b Measured activity: + %br + - if prediction[:measurements].is_a?(Array) + = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10} (#{unit})
#{compound.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("
") : prediction[:measurements].join(", ") + - else + = (type == "Regression") ? "#{prediction[:measurements].delog10} (#{unit})
#{compound.mmol_to_mg(prediction[:measurements].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:measurements] + + + / show prediction %p - / model type (classification|regression) - %b Type: - = model.model.class.to_s.match("Classification") ? "Classification" : "Regression" - %br - %b Prediction: - = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} (#{model.unit}) | #{'%.2e' % compound.mmol_to_mg(prediction[:value], mw)} (mg/kg_bw/day)" : prediction[:value] - %br - / TODO probability - %b Confidence: - = prediction[:confidence].round(3) + %b Prediction: + %br + = (type == "Regression") ? "#{prediction[:value].delog10} (#{unit})
#{compound.mmol_to_mg(prediction[:value].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value] + + / show prediction interval or probability + %p + - if type == "Regression" + %b 95% Prediction interval: + - interval = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval]) + %br + = interval.nil? ? "--" : "#{interval[1].delog10} - #{interval[0].delog10} (#{unit})" + %br + = "#{compound.mmol_to_mg(interval[1].delog10)} - #{compound.mmol_to_mg(interval[0].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if !prediction[:prediction_interval].nil? + - else + %b Probability: + - unless prediction[:probabilities].nil? + %br + = "#{prediction[:probabilities].keys[0]}: #{prediction[:probabilities].values[0]}" + %br + / show warnings %p + - if !prediction[:warning].nil? + %b Warnings: + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Warnings", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"#{prediction[:warning]}"}} + + / no prediction - else %p = "Not enough similar compounds
in training dataset." diff --git a/views/layout.haml b/views/layout.haml index dddf854..5ed63e8 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -29,33 +29,11 @@ %h1.media-heading lazar toxicity predictions %div.col-md-2 - %h1.media-heading + %h5 %small - %a{:href=>"https://nano-lazar.in-silico.ch"} nano-lazar + [version: #{@version}] %div.container-fluid - %topline - %div.row - %div.col-md-8 - Problems, bugs, ideas for improvements ? Please report at our - %a{:href => 'https://github.com/opentox/lazar-gui/issues', :rel => "external"} issue tracker - or send us an email - %a{ :href=>"mailto:info@in-silico.ch", :target=>"_top"} - %img.share{:src=>"/images/Email.png"} - (version #{@version}). - %div.col-md-2 - %div.col-md-2 - %a{:href=>"https://twitter.com/intent/tweet?source=http%3A%2F%2Flazar.in-silico.ch&text=:%20http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Tweet"} - %img.share{:src=>"/images/Twitter.png"} - %a{:href=>"https://plus.google.com/share?url=http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Share on Google+"} - %img.share{:src=>"/images/Google+.png"} - %a{:href=>"http://www.linkedin.com/shareArticle?mini=true&url=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Share on LinkedIn"} - %img.share{:src=>"/images/LinkedIn.png"} - %a{:href=>"https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :target=>"_blank", :title=>"Share on Facebook"} - %img.share{:src=>"/images/Facebook.png"} - %div.row - Previous version: - %a{:href=>"http://lazar-old.in-silico.ch", :rel => "external"} lazar-old :javascript $(document).ready(function(){ $("#back-top").hide(); @@ -79,18 +57,6 @@ %p.text-muted © %a{:href => 'http://www.in-silico.ch', :rel => "external"} in silico toxicology gmbh 2004 - #{Time.now.year.to_s} - | - %a{:href => to("/license"), :rel => "external"} GPL3 License - %supporters.col-md-12 - %p Financial support by - %a{:href=>"http://www.bfr.bund.de/de/start.html", :rel=>"external"} - %img{:src=>"/images/bfr_logo.gif"} - %a{:href=>"http://www.opentox.org/", :rel=>"external"} - %img{:src=>"/images/ot_logo.png"} - %a{:href=>"https://enanomapper.net/", :rel=>"external"} - %img{:src=>"/images/enm_logo.png"} - %a{:href=>"https://www.researchgate.net/institution/Nestle_SA/department/Nestle_Research_Center", :rel=>"external"} - %img{:src=>"/images/nestec.jpg"} #back-top{:style => "z-index:100;position:fixed;bottom:1%;right:1%;"} diff --git a/views/model_details.haml b/views/model_details.haml index 7646471..3fa8c8b 100644 --- a/views/model_details.haml +++ b/views/model_details.haml @@ -12,6 +12,10 @@ Source: = "Training compounds:\t" = training_dataset.compounds.size %br += "Training dataset:\t" +%a{:href=>"#{to("/predict/dataset/#{training_dataset.name}")}"} + = training_dataset.name +%br %b Algorithms: %br Similarity: diff --git a/views/neighbors.haml b/views/neighbors.haml index d9f2796..32b8389 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -67,10 +67,10 @@ Compound %th.sorter-false{:style =>"vertical-align:middle;"} Measured Activity - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Measured Activity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"left", html:"true", content:"Experimental result(s) from the training dataset."}, :style=>"z-index:auto+10;"} + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Measured Activity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"auto", html:"true", content:"Experimental result(s) from the training dataset."}, :style=>"z-index:auto+10;"} %th.sorter-false{:style =>"vertical-align:middle;"} Similarity - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Similarity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"left", html:"true", content:"Tanimoto/Jaccard similarity based on Molprint2D fingerprints."}, :style=>"z-index:auto+10;"} + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Similarity", :tabindex=>"0", data: {trigger:"focus", container:"body", toggle:"popover", placement:"auto", html:"true", content:"Tanimoto/Jaccard similarity based on Molprint2D fingerprints."}, :style=>"z-index:auto+10;"} / %th{:style =>"vertical-align:middle;"} / Supporting Information %tbody @@ -84,11 +84,14 @@ /%a.btn.btn-link{:href => "#details#{j+1}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(neighbor["_id"])}/details"), :id=>"link#{j+1}#{count}"}} %p= c.svg %p= c.smiles + / Measured Activity %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;white-space:nowrap;"} - = (type == "Regression" ? "#{neighbor[:measurement].delog10}" + " (#{unit})" : neighbor[:measurement]) - %br - = "#{c.mmol_to_mg(neighbor[:measurement].delog10)}" + " (#{(unit =~ /\b(mol\/L)\b/) ? "mg/L" : "mg/kg_bw/day"})" if type == "Regression" + - if neighbor[:measurement].is_a?(Array) + = (type == "Regression") ? neighbor[:measurement].collect{|value| "#{value.delog10} (#{unit})
#{c.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("
") : neighbor[:measurement].join(", ") + - else + = (type == "Regression") ? "#{neighbor[:measurement].delog10} (#{unit})
#{c.mmol_to_mg(neighbor[:measurement].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : neighbor[:measurement] + / Similarity = tanimoto %td{:style =>"vertical-align:middle;padding-left:1em;width:20%;"} = neighbor[:similarity].round(3) diff --git a/views/predict.haml b/views/predict.haml index 66006d4..9a7d0d4 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -127,6 +127,7 @@ %p %label{:for=>"fileselect"} or upload a CSV file for batch predictions + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"File format", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"One column with compounds and keyword SMILES or InChI in the first row."}} %br %span.btn.btn-default.btn-file %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv"} diff --git a/views/prediction.haml b/views/prediction.haml index 2454aca..b090be5 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -18,7 +18,6 @@ %td{:id=>"compound", :style=>"vertical-align:top;"} %p= @compound.svg %p= @compound.smiles - -#- mw = @compound.molecular_weight - @model_types = {} - @dbhit = {} - @predictions.each_with_index do |prediction,i| @@ -28,62 +27,66 @@ %td{:style=>"vertical-align:top;white-space:nowrap;"} %b{:class => "title"} = "#{@models[i].endpoint.gsub('_', ' ')} (#{@models[i].species})" - %p - - if prediction[:warning] =~ /\b(identical)\b/i - - @dbhit[i] = true + + / check for prediction + - if prediction[:neighbors].size > 0 %p - /TODO combine with regular view, if prediction value is present - %b Measured activity: - - p prediction[:value] - - if prediction[:value].is_a?(Array) - = (type == "Regression") ? prediction[:value].collect{|value| "#{value} (#{unit}) , #{@compound.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("
") : prediction[:value].join(", ") - - else - = (type == "Regression") ? "#{prediction[:value]} (#{unit}), #{@compound.mmol_to_mg(prediction[:value].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value] - %p - %b Compound is part of the training dataset - / warning popover - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Warnings", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"#{prediction[:warning]}"}} - - elsif prediction[:neighbors].size > 0 - %p - / model type (classification|regression) + / show model type (classification|regression) %b Type: = type - %br - %b Prediction: - / prediction popover - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"

lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.

Classification:
Majority vote of neighbor activities weighted by similarity.

Regression:
Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.

Original publication."}} - %br - = (type == "Regression") ? "#{prediction[:value].delog10} (#{unit})
#{@compound.mmol_to_mg(prediction[:value].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value] - / tabindex=0 seems the best fix for FF|S browsers on OSX better than trigger="click focus" which ends up in double click for FF. - %br - - if type == "Regression" - %b 95% Prediction interval: - - interval = (prediction[:prediction_interval].nil? ? ["- -","- -"] : prediction[:prediction_interval]) - / prediction intervall popover - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction intervall", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"An estimate of prediction uncertainty. The \"real\" value should be with 95% probability within the prediction interval."}} - %br - = "#{interval[0].delog10} - #{interval[1].delog10} (#{unit})" - %br - = "#{@compound.mmol_to_mg(interval[0].delog10)} - #{@compound.mmol_to_mg(interval[1].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if !prediction[:prediction_interval].nil? + %p + / check for database hit + - if prediction[:warning] =~ /\b(identical)\b/i + - @dbhit[i] = true + + / show message about dbhit and measurements + %p + %b Compound is part of the training dataset + %p + %b Measured activity: + %br + - if prediction[:measurements].is_a?(Array) + = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10} (#{unit})
#{@compound.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("
") : prediction[:measurements].join(", ") + - else + = (type == "Regression") ? "#{prediction[:measurements].delog10} (#{unit})
#{@compound.mmol_to_mg(prediction[:measurements].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:measurements] + - else - %b Probability: - - unless prediction[:probabilities].nil? + - @dbhit[i] = false + + / show prediction + %p + %b Prediction: + / prediction popover + -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"

lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.

Classification:
Majority vote of neighbor activities weighted by similarity.

Regression:
Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.

Original publication."}} + %br + = (type == "Regression") ? "#{prediction[:value].delog10} (#{unit})
#{@compound.mmol_to_mg(prediction[:value].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value] + + / show prediction interval or probability + %p + - if type == "Regression" + %b 95% Prediction interval: + - interval = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval]) + / prediction interval popover + -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction intervall", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"An estimate of prediction uncertainty. The \"real\" value should be with 95% probability within the prediction interval."}} %br - = "#{prediction[:probabilities].keys[0]}: #{prediction[:probabilities].values[0]}" + = interval.nil? ? "--" : "#{interval[1].delog10} - #{interval[0].delog10} (#{unit})" %br - = "#{prediction[:probabilities].keys[1]}: #{prediction[:probabilities].values[1]}" - / probability popover - -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Confidence", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"Indicates the applicability domain of a model. Predictions with a high confidence can be expected to be more reliable than predictions with low confidence. Confidence values may take any value between 0 and 1. For most models confidence > 0.025 is a sensible (hard) cutoff to distinguish between reliable and unreliable predictions."}} - %p - /TODO add tooltip for significant ftagments and descriptors - / - if @model_type[i] =~ /classification/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0) - / Significant fragments: - / %a.btn.btn-default.btn-sm{:id=>"linkSigFragments", :href => "#detailsTop", :tabindex=>"0", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[i]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Significant fragments - / - if @model_type[i] =~ /regression/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0) - / Descriptors - / %a.btn.btn-default.btn-sm{:id=>"linkDescriptors", :href => "#detailsTop", :tabindex=>"0", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[i]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Descriptors - / %p + = "#{@compound.mmol_to_mg(interval[1].delog10)} - #{@compound.mmol_to_mg(interval[0].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if !prediction[:prediction_interval].nil? + - else + %b Probability: + - unless prediction[:probabilities].nil? + %br + = "#{prediction[:probabilities].keys[0]}: #{prediction[:probabilities].values[0]}" + %br + = "#{prediction[:probabilities].keys[1]}: #{prediction[:probabilities].values[1]}" + / probability popover + -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Confidence", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"Indicates the applicability domain of a model. Predictions with a high confidence can be expected to be more reliable than predictions with low confidence. Confidence values may take any value between 0 and 1. For most models confidence > 0.025 is a sensible (hard) cutoff to distinguish between reliable and unreliable predictions."}} + + / show warnings %p + - if !prediction[:warning].nil? + %b Warnings: + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Warnings", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"#{prediction[:warning]}"}} - else - @dbhit[i] = false %p -- cgit v1.2.3 From 437b78faf4bcd820ea3193da18abf6b71eda8153 Mon Sep 17 00:00:00 2001 From: gebele Date: Wed, 30 Nov 2016 12:50:53 +0000 Subject: minor fix --- .gitignore | 1 - lazar-gui.gemspec | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a0459cb..49b161f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ Gemfile.lock .sass-cache/ -tmp/* diff --git a/lazar-gui.gemspec b/lazar-gui.gemspec index 9a43bd8..6f58687 100644 --- a/lazar-gui.gemspec +++ b/lazar-gui.gemspec @@ -19,7 +19,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency "rdiscount", "~> 2.1.0", '>= 2.1.0' s.add_runtime_dependency "haml", "~> 4.0.0", '>= 4.0.0' s.add_runtime_dependency "sass", "~> 3.4.0", '>= 3.4.0' - s.add_runtime_dependency "unicorn", "~> 5.1.0", '>= 5.1.0' + s.add_runtime_dependency "unicorn" s.post_install_message = %q{ Service cmds: -- cgit v1.2.3