summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgebele <gebele@in-silico.ch>2016-11-28 14:13:18 +0000
committergebele <gebele@in-silico.ch>2016-11-28 14:13:18 +0000
commitc5ca09fb039e38abd89005d49ef373cf18b79039 (patch)
tree4c1199782dd90b97bdcb874dcb0ef25a11c0615c
parentbfd31ed2c9d0cde8a53238c7368eb3d49c580b7d (diff)
bumped version;training dataset download;show warnings for batch;csv info and upload catch;code cleanupv9-nestec
-rw-r--r--VERSION2
-rw-r--r--application.rb235
-rw-r--r--config.ru2
-rw-r--r--lazar-gui.gemspec2
-rw-r--r--views/batch.haml106
-rw-r--r--views/layout.haml38
-rw-r--r--views/model_details.haml4
-rw-r--r--views/neighbors.haml13
-rw-r--r--views/predict.haml1
-rw-r--r--views/prediction.haml103
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("</br>") : 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})</br>#{compound.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : prediction[:measurements].join(", ")
+ - else
+ = (type == "Regression") ? "#{prediction[:measurements].delog10} (#{unit})</br>#{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})</br>#{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 </br>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
&copy;
%a{:href => 'http://www.in-silico.ch', :rel => "external"} <i style="font-family: serife">in silico</i> 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:"<a href=\"https://en.wikipedia.org/wiki/Jaccard_index\">Tanimoto/Jaccard</a> similarity based on <a href=\"https://openbabel.org/docs/dev/FileFormats/MolPrint2D_format.html\">Molprint2D</a> 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:"<a href=\"https://en.wikipedia.org/wiki/Jaccard_index\">Tanimoto/Jaccard</a> similarity based on <a href=\"https://openbabel.org/docs/dev/FileFormats/MolPrint2D_format.html\">Molprint2D</a> 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})</br>#{c.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : neighbor[:measurement].join(", ")
+ - else
+ = (type == "Regression") ? "#{neighbor[:measurement].delog10} (#{unit})</br>#{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("</br>") : 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:"<p>lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.<p><b>Classification:</b></br>Majority vote of neighbor activities weighted by similarity.<p><b>Regression:</b></br>Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.<p><a href=\"http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract\", target=\"_blank\"> Original publication</a>."}}
- %br
- = (type == "Regression") ? "#{prediction[:value].delog10} (#{unit})</br>#{@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})</br>#{@compound.mmol_to_mg(value.delog10)} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : prediction[:measurements].join(", ")
+ - else
+ = (type == "Regression") ? "#{prediction[:measurements].delog10} (#{unit})</br>#{@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:"<p>lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.<p><b>Classification:</b></br>Majority vote of neighbor activities weighted by similarity.<p><b>Regression:</b></br>Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.<p><a href=\"http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract\", target=\"_blank\"> Original publication</a>."}}
+ %br
+ = (type == "Regression") ? "#{prediction[:value].delog10} (#{unit})</br>#{@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