summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgebele <gebele@in-silico.ch>2017-07-31 15:18:22 +0000
committergebele <gebele@in-silico.ch>2017-07-31 15:18:22 +0000
commit292ffcd5eccb05b2bea1aab64504134f5cdd0834 (patch)
treefdaa343242c817228d446db5423eede31d824f0c
parent2f881ce99d9f1cc60e2d25107667456260b8878b (diff)
introduce batch predictions and QMRF for public service;layout refinements for better readability
-rw-r--r--Gemfile1
-rw-r--r--VERSION2
-rw-r--r--application.rb339
-rw-r--r--lazar-gui.gemspec3
-rw-r--r--tmp/.gitignore2
-rw-r--r--unicorn.rb7
-rw-r--r--views/batch.haml160
-rw-r--r--views/layout.haml26
-rw-r--r--views/model_details.haml289
-rw-r--r--views/predict.haml30
-rw-r--r--views/prediction.haml8
-rw-r--r--views/style.scss4
12 files changed, 579 insertions, 292 deletions
diff --git a/Gemfile b/Gemfile
index c86c89a..04e129a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,7 @@
source "https://rubygems.org"
gemspec
gem "lazar", :path => "../lazar"
+gem "qsar-report", :path => "../qsar-report"
gem "gem-path"
gem "sinatra"
gem "sinatra-reloader"
diff --git a/VERSION b/VERSION
index 781dcb0..26aaba0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.3
+1.2.0
diff --git a/application.rb b/application.rb
index aac1c39..1694b6e 100644
--- a/application.rb
+++ b/application.rb
@@ -73,43 +73,10 @@ get '/predict/dataset/:name' do
csv
end
-get '/predict/?:csv?' do
+get '/predict/:tmppath/:filename/?' do
response['Content-Type'] = "text/csv"
- @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]
- endpoint = "#{model.endpoint.gsub('_', ' ')} (#{model.species})"
- if prediction[:confidence] == "measured"
- if prediction[:value].is_a?(Array)
- prediction[:value].each do |value|
- 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
- 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
- type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression"
- 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."
- interval = ""
- end
- @csv += "\"#{smiles}\",\"#{endpoint}\",\"#{type}\",\"#{pred}\",\"#{interval}\"\n" unless prediction[:value].is_a?(Array)
- end
- end
- @csv
+ path = "/tmp/#{params[:tmppath]}"
+ send_file path, :filename => "lazar_batch_prediction_#{params[:filename]}", :type => "text/csv", :disposition => "attachment"
end
post '/predict/?' do
@@ -142,24 +109,119 @@ post '/predict/?' do
dataset.delete
return haml :error
end
+
+ # for csv export
@batch = {}
- @compounds.each do |compound|
- @batch[compound] = []
- params[:selection].keys.each do |model_id|
- model = OpenTox::Model::Validation.find model_id
+ # for haml table
+ @view = {}
+
+ @compounds.each{|c| @view[c] = []}
+ params[:selection].keys.each do |model_id|
+ model = OpenTox::Model::Validation.find model_id
+ @batch[model] = []
+ @compounds.each_with_index do |compound,idx|
prediction = model.predict(compound)
- @batch[compound] << [model, prediction]
+ @batch[model] << [compound, prediction]
+ @view[compound] << [model,prediction]
end
end
- @@batch = @batch
+
+ @csvhash = {}
@warnings = dataset[:warnings]
+ dupEntries = {}
+ delEntries = ""
+
+ # split duplicates and deleted entries
+ @warnings.each do |w|
+ substring = w.match(/line .* of/)
+ unless substring.nil?
+ delEntries += "\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"#{w.sub(/\b(tmp\/)\b/,"")}\"\n"
+ end
+ substring = w.match(/rows .* Entries/)
+ unless substring.nil?
+ lines = []
+ substring[0].split(",").each{|s| lines << s[/\d+/]}
+ lines.shift
+ lines.each{|l| dupEntries[l.to_i] = w.split(".").first}
+ end
+ end
+
+ @batch.each_with_index do |hash, idx|
+ @csvhash[idx] = ""
+ model = hash[0]
+ values = hash[1]
+ dupEntries.keys.each{|k| values.insert(k-1, dupEntries[k])}.compact!
+ values.each_with_index do |array, id|
+ unless array.kind_of? String
+ compound = array[0]
+ prediction = array[1]
+ smiles = compound.smiles
+ type = model.model.class.to_s.match("Classification") ? "Classification" : "Regression"
+ endpoint = "#{model.endpoint.gsub('_', ' ')} (#{model.species})"
+ pred = propA = propB = interval = inApp = inT = note = ""
+ if prediction[:neighbors]
+ if prediction[:value]
+ pred = prediction[:value].numeric? ? "#{prediction[:value].delog10.signif(3)} (#{model.unit}), #{compound.mmol_to_mg(prediction[:value].delog10.signif(3))} #{(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.signif(3)} - #{int[0].delog10.signif(3)} (#{model.unit})")
+ inApp = "yes"
+ inT = prediction[:info] =~ /\b(identical)\b/i ? "yes" : "no"
+ note = prediction[:warnings].join("\n") + ( prediction[:info] ? prediction[:info].sub(/\'.*\'/,"") : "\n" )
+ unless prediction[:probabilities].nil?
+ if id == 0
+ probFirst = probLast = ""
+ probFirst = prediction[:probabilities].keys.first.capitalize
+ prediction[:probabilities].keys.last.split("-").each{|s| probLast += s.capitalize}
+ @csvhash[idx] = "\"ID\",\"Endpoint\",\"Type\",\"Unique SMILES\",\"Prediction\",\"predProbability#{probFirst}\",\"predProbability#{probLast}\",\"95% Prediction interval\",\"inApplicabilityDomain\",\"inTrainningSet\",\"Note\"\n"
+ unless delEntries.blank? and id == 0
+ @csvhash[idx] += delEntries
+ end
+ end
+ propA = "#{prediction[:probabilities].values_at(prediction[:probabilities].keys.first)[0].to_f.signif(3)}"
+ propB = "#{prediction[:probabilities].values_at(prediction[:probabilities].keys.last)[0].to_f.signif(3)}"
+ else
+ @csvhash[idx] = "\"ID\",\"Endpoint\",\"Type\",\"Unique SMILES\",\"Prediction\",\"predProbability\",\"predProbability\",\"95% Prediction interval\",\"inApplicabilityDomain\",\"inTrainningSet\",\"Note\"\n"
+ unless delEntries.blank? and id == 0
+ @csvhash[idx] += delEntries
+ end
+ end
+ # only one neighbor
+ else
+ inApp = "no"
+ inT = prediction[:info] =~ /\b(identical)\b/i ? "yes" : "no"
+ note = prediction[:warnings].join("\n") + ( prediction[:info] ? prediction[:info].sub(/\'.*\'/,"") : "\n" )
+ end
+ else # no prediction value
+ inApp = "no"
+ inT = prediction[:info] =~ /\b(identical)\b/i ? "yes" : "no"
+ note = prediction[:warnings].join("\n") + ( prediction[:info] ? prediction[:info].sub(/\'.*\'/,"") : "\n" )
+ end
+ if @warnings
+ @warnings.each do |w|
+ note += (w.split(".").first + ".") if /\b(#{Regexp.escape(smiles)})\b/ === w
+ end
+ end
+ else
+ endpoint = type = smiles = pred = propA = propB = interval = inApp = inT = ""
+ note = array
+ end
+ @csvhash[idx] += "\"#{id+1}\",\"#{endpoint}\",\"#{type}\",\"#{smiles}\",\"#{pred}\",\"#{propA}\",\"#{propB}\",\"#{interval}\",\"#{inApp}\",\"#{inT}\",\"#{note.chomp}\"\n"
+ end
+ end
+ t = Tempfile.new
+ @csvhash.each do |model, csv|
+ t.write(csv)
+ t.write("\n")
+ end
+ t.rewind
+ @tmppath = t.path.split("/").last
+
dataset.delete
File.delete File.join("tmp", params[:fileselect][:filename])
return haml :batch
end
# validate identifier input
- # transfered input
if !params[:identifier].blank?
@identifier = params[:identifier]
$logger.debug "input:#{@identifier}"
@@ -181,6 +243,197 @@ post '/predict/?' do
end
end
+get "/report/:id/?" do
+ lazarpath = `gem path lazar`
+ lazarpath = File.dirname lazarpath
+ lazarpath = File.dirname lazarpath
+ qmrfpath = `gem path qsar-report`
+ qmrfpath = File.dirname qmrfpath
+ qmrfpath = File.dirname qmrfpath
+ prediction_model = Model::Validation.find params[:id]
+ model = prediction_model.model
+ validation_template = "./views/model_details.haml"
+
+ if File.directory?(lazarpath)
+ lazar_commit = `cd #{lazarpath}; git rev-parse HEAD`.strip
+ lazar_commit = "https://github.com/opentox/lazar/tree/#{lazar_commit}"
+ else
+ lazar_commit = "https://github.com/opentox/lazar/releases/tag/v#{Gem.loaded_specs["lazar"].version}"
+ end
+
+ report = OpenTox::QMRFReport.new
+
+ # QSAR Identifier Title 1.1
+ report.value "QSAR_title", "Lazar model for #{prediction_model.species} #{prediction_model.endpoint}"
+
+ # Software coding the model 1.3
+ report.change_catalog :software_catalog, :firstsoftware, {:name => "lazar", :description => "lazar Lazy Structure- Activity Relationships", :number => "1", :url => "https://lazar.in-silico.ch", :contact => "info@in-silico.ch"}
+ report.ref_catalog :QSAR_software, :software_catalog, :firstsoftware
+
+ # Date of QMRF 2.1
+ report.value "qmrf_date", "#{Time.now.strftime('%d %B %Y')}"
+
+ # QMRF author(s) and contact details 2.1
+ report.change_catalog :authors_catalog, :firstauthor, {:name => "Christoph Helma", :affiliation => "in silico toxicology gmbh", :contact => "Rastatterstr. 41, CH-4057 Basel", :email => "info@in-silico.ch", :number => "1", :url => "www.in-silico.ch"}
+ report.ref_catalog :qmrf_authors, :authors_catalog, :firstauthor
+
+ # Model developer(s) and contact details 2.5
+ report.change_catalog :authors_catalog, :modelauthor, {:name => "Christoph Helma", :affiliation => "in silico toxicology gmbh", :contact => "Rastatterstr. 41, CH-4057 Basel", :email => "info@in-silico.ch", :number => "1", :url => "www.in-silico.ch"}
+ report.ref_catalog :model_authors, :authors_catalog, :modelauthor
+
+ # Date of model development and/or publication 2.6
+ report.value "model_date", "#{Time.parse(model.created_at.to_s).strftime('%Y')}"
+
+ # Reference(s) to main scientific papers and/or software package 2.7
+ report.change_catalog :publications_catalog, :publications_catalog_1, {:title => "Maunz, Guetlein, Rautenberg, Vorgrimmler, Gebele and Helma (2013), lazar: a modular predictive toxicology framework ", :url => "http://dx.doi.org/10.3389/fphar.2013.00038"}
+ report.ref_catalog :references, :publications_catalog, :publications_catalog_1
+
+ # Reference(s) to main scientific papers and/or software package 2.7
+ report.change_catalog :publications_catalog, :publications_catalog_2, {:title => "Maunz A and Helma C (2008) Prediction of chemical toxicity with local support vector regression and activity-specific kernels. SAR & QSAR in Environmental Research 19 (5-6), 413-431", :url => "http://dx.doi.org/10.1080/10629360802358430"}
+ report.ref_catalog :references, :publications_catalog, :publications_catalog_2
+
+ # Species 3.1
+ report.value "model_species", prediction_model.species
+
+ # Endpoint 3.2
+ report.change_catalog :endpoints_catalog, :endpoints_catalog_1, {:name => prediction_model.endpoint, :group => ""}
+ report.ref_catalog :model_endpoint, :endpoints_catalog, :endpoints_catalog_1
+
+ # Endpoint Units 3.4
+ report.value "endpoint_units", "#{prediction_model.unit}"
+
+ model_type = model.class.to_s.gsub('OpenTox::Model::Lazar','')
+
+ # Type of model 4.1
+ report.value "algorithm_type", "#{model_type}"
+
+ # Explicit algorithm 4.2
+ report.change_catalog :algorithms_catalog, :algorithms_catalog_1, {:definition => "see Helma 2016 and lazar.in-silico.ch, submitted version: #{lazar_commit}", :description => "Neighbor algorithm: #{model.algorithms["similarity"]["method"].gsub('_',' ').titleize}#{(model.algorithms["similarity"][:min] ? ' with similarity > ' + model.algorithms["similarity"][:min].to_s : '')}"}
+ report.ref_catalog :algorithm_explicit, :algorithms_catalog, :algorithms_catalog_1
+ report.change_catalog :algorithms_catalog, :algorithms_catalog_3, {:definition => "see Helma 2016 and lazar.in-silico.ch, submitted version: #{lazar_commit}", :description => "modified k-nearest neighbor #{model_type}"}
+ report.ref_catalog :algorithm_explicit, :algorithms_catalog, :algorithms_catalog_3
+ if model.algorithms["prediction"]
+ pred_algorithm_params = (model.algorithms["prediction"][:method] == "rf" ? "random forest" : model.algorithms["prediction"][:method])
+ end
+ report.change_catalog :algorithms_catalog, :algorithms_catalog_2, {:definition => "see Helma 2016 and lazar.in-silico.ch, submitted version: #{lazar_commit}", :description => "Prediction algorithm: #{model.algorithms["prediction"].to_s.gsub('OpenTox::Algorithm::','').gsub('_',' ').gsub('.', ' with ')} #{(pred_algorithm_params ? pred_algorithm_params : '')}"}
+ report.ref_catalog :algorithm_explicit, :algorithms_catalog, :algorithms_catalog_2
+
+ # Descriptors in the model 4.3
+ if model.algorithms["descriptors"][:type]
+ report.change_catalog :descriptors_catalog, :descriptors_catalog_1, {:description => "", :name => "#{model.algorithms["descriptors"][:type]}", :publication_ref => "", :units => ""}
+ report.ref_catalog :algorithms_descriptors, :descriptors_catalog, :descriptors_catalog_1
+ end
+
+ # Descriptor selection 4.4
+ report.value "descriptors_selection", "#{model.algorithms["feature_selection"].gsub('_',' ')} #{model.algorithms["feature_selection"].collect{|k,v| k.to_s + ': ' + v.to_s}.join(', ')}" if model.algorithms["feature_selection"]
+
+ # Algorithm and descriptor generation 4.5
+ report.value "descriptors_generation", "exhaustive breadth first search for paths in chemical graphs (simplified MolFea algorithm)"
+
+ # Software name and version for descriptor generation 4.6
+ report.change_catalog :software_catalog, :software_catalog_2, {:name => "lazar, submitted version: #{lazar_commit}", :description => "simplified MolFea algorithm", :number => "2", :url => "https://lazar.in-silico.ch", :contact => "info@in-silico.ch"}
+ report.ref_catalog :descriptors_generation_software, :software_catalog, :software_catalog_2
+
+ # Chemicals/Descriptors ratio 4.7
+ report.value "descriptors_chemicals_ratio", "not applicable (classification based on activities of neighbors, descriptors are used for similarity calculation)"
+
+ # Description of the applicability domain of the model 5.1
+ report.value "app_domain_description", "<html><head></head><body>
+ <p>
+ The applicability domain (AD) of the training set is characterized by
+ the confidence index of a prediction (high confidence index: close to
+ the applicability domain of the training set/reliable prediction, low
+ confidence: far from the applicability domain of the
+ trainingset/unreliable prediction). The confidence index considers (i)
+ the similarity and number of neighbors and (ii) contradictory examples
+ within the neighbors. A formal definition can be found in Helma 2006.
+ </p>
+ <p>
+ The reliability of predictions decreases gradually with increasing
+ distance from the applicability domain (i.e. decreasing confidence index)
+ </p>
+ </body>
+ </html>"
+
+ # Method used to assess the applicability domain 5.2
+ report.value "app_domain_method", "see Helma 2006 and Maunz 2008"
+
+ # Software name and version for applicability domain assessment 5.3
+ report.change_catalog :software_catalog, :software_catalog_3, {:name => "lazar, submitted version: #{lazar_commit}", :description => "integrated into main lazar algorithm", :number => "3", :url => "https://lazar.in-silico.ch", :contact => "info@in-silico.ch"}
+ report.ref_catalog :app_domain_software, :software_catalog, :software_catalog_3
+
+ # Limits of applicability 5.4
+ report.value "applicability_limits", "Predictions with low confidence index, unknown substructures and neighbors that might act by different mechanisms"
+
+ # Availability of the training set 6.1
+ report.change_attributes "training_set_availability", {:answer => "Yes"}
+
+ # Available information for the training set 6.2
+ report.change_attributes "training_set_data", {:cas => "Yes", :chemname => "Yes", :formula => "Yes", :inchi => "Yes", :mol => "Yes", :smiles => "Yes"}
+
+ # Data for each descriptor variable for the training set 6.3
+ report.change_attributes "training_set_descriptors", {:answer => "No"}
+
+ # Data for the dependent variable for the training set 6.4
+ report.change_attributes "dependent_var_availability", {:answer => "All"}
+
+ # Other information about the training set 6.5
+ report.value "other_info", "#{prediction_model.source}"
+
+ # Pre-processing of data before modelling 6.6
+ report.value "preprocessing", (model.class == OpenTox::Model::LazarRegression ? "-log10 transformation" : "none")
+
+ # Robustness - Statistics obtained by leave-many-out cross-validation 6.9
+ if prediction_model.repeated_crossvalidation
+ $logger.error "#####################{prediction_model}"
+ crossvalidations = prediction_model.crossvalidations
+ out = haml File.read(validation_template), :layout=> false, :locals => {:model => prediction_model, :crossvalidations => crossvalidations}
+ report.value "lmo", out
+ end
+
+ # Mechanistic basis of the model 8.1
+ report.value "mechanistic_basis","<html><head></head><body>
+ <p>
+ Compounds with similar structures (neighbors) are assumed to have
+ similar activities as the query compound. For the determination of
+ activity specific similarities only statistically relevant subtructures
+ (paths) are used. For this reason there is a priori no bias towards
+ specific mechanistic hypothesis.
+ </p>
+ </body>
+</html>"
+
+ # A priori or a posteriori mechanistic interpretation 8.2
+ report.value "mechanistic_basis_comments","a posteriori for individual predictions"
+
+ # Other information about the mechanistic interpretation 8.3
+ report.value "mechanistic_basis_info","<html><head></head><body><p>Hypothesis about biochemical mechanisms can be derived from individual
+ predictions by inspecting neighbors and relevant fragments.</p>
+ <p>Neighbors are compounds that are similar in respect to a certain
+ endpoint and it is likely that compounds with high similarity act by
+ similar mechanisms as the query compound. Links at the webinterface
+ prove an easy access to additional experimental data and literature
+ citations for the neighbors and the query structure.</p>
+ <p>Activating and deactivating parts of the query compound are highlighted
+ in red and green on the webinterface. Fragments that are unknown (or too
+ infrequent for statistical evaluation are marked in yellow and
+ additional statistical information about the individual fragments can be
+ retrieved. Please note that lazar predictions are based on neighbors and
+ not on fragments. Fragments and their statistical significance are used
+ for the calculation of activity specific similarities.</p>"
+
+ # Bibliography 9.2
+ report.ref_catalog :bibliography, :publications_catalog, :publications_catalog_1
+ report.ref_catalog :bibliography, :publications_catalog, :publications_catalog_2
+ report.change_catalog :publications_catalog, :publications_catalog_3, {:title => "Helma (2006), Lazy structure-activity relationships (lazar) for the prediction of rodent carcinogenicity and Salmonella mutagenicity.", :url => "http://dx.doi.org/10.1007/s11030-005-9001-5"}
+ report.ref_catalog :bibliography, :publications_catalog, :publications_catalog_3
+
+ # output
+ t = Tempfile.new
+ t << report.to_xml
+ send_file t.path, :filename => "QMRF_report_#{model.name}.xml", :type => "application/xml", :disposition => "attachment"
+end
+
get '/license' do
@license = RDiscount.new(File.read("LICENSE.md")).to_html
haml :license, :layout => false
diff --git a/lazar-gui.gemspec b/lazar-gui.gemspec
index 8ee62cf..2f40224 100644
--- a/lazar-gui.gemspec
+++ b/lazar-gui.gemspec
@@ -14,12 +14,13 @@ Gem::Specification.new do |s|
s.files = `git ls-files`.split("\n")
s.add_runtime_dependency "lazar", ">= 1.0.0"
- s.add_runtime_dependency "gem-path"
s.add_runtime_dependency "sinatra"
s.add_runtime_dependency "rdiscount"
s.add_runtime_dependency "haml"
s.add_runtime_dependency "sass"
s.add_runtime_dependency "unicorn"
+ s.add_runtime_dependency "qsar-report"
+ s.add_runtime_dependency "gem-path"
s.post_install_message = %q{
Service cmds:
diff --git a/tmp/.gitignore b/tmp/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/tmp/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/unicorn.rb b/unicorn.rb
index 010ebbb..4e65aaa 100644
--- a/unicorn.rb
+++ b/unicorn.rb
@@ -1,7 +1,2 @@
-#worker_processes 4
+worker_processes 4
timeout 6000
-listen 8088
-log_dir = "#{ENV['HOME']}"
-log_file = File.join log_dir, "lazar.log"
-stderr_path log_file
-stdout_path log_file
diff --git a/views/batch.haml b/views/batch.haml
index c1b45f6..38c8c6e 100644
--- a/views/batch.haml
+++ b/views/batch.haml
@@ -2,11 +2,11 @@
%a.btn.btn-warning{:href => to('/predict')}
%span.glyphicon.glyphicon-menu-left{:aria=>{:hidden=>"true"}}
New Prediction
- %a.btn.btn-success{:href=>"#{to("/predict/#{@filename}")}", :title=>"download"}
+ %a.btn.btn-success{:id => "downbutton", :href=>"#{to("/predict/#{@tmppath}/#{@filename}")}", :title=>"download"}
%span.glyphicon.glyphicon-download-alt
- download CSV
+ Download CSV
- / show processed file name
+ / show file name
%topline
%div.row
%div.col-md-4
@@ -18,83 +18,95 @@
%div.table-responsive
%table.table.table-bordered{:id=>"batch", :style=>"background-color:white;"}
%tbody
- - if @warnings
- - @warnings.each do |warning|
+ - if @warnings
+ - @warnings.each do |warning|
+ %tr
+ %td
+ %b Warning
+ %td
+ = warning.sub(/\b(tmp\/)\b/,"")
+ - @view.each do |compound, array|
%tr
- %td
- %b Warning
- %td
- = warning.sub(/\b(tmp\/)\b/,"")
- / key = compound, values = [model,prediction]
- - @batch.each do |key, values|
- - compound = key
- %tr
- %td{:style=>"vertical-align:top;"}
- %p= compound.svg
- %p= compound.smiles
-
- / 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})"
-
- / check for prediction
- - if prediction[:neighbors].size > 0
- %p
- / show model type (classification|regression)
- %b Type:
- = type
- %p
- / check for database hit
- - if prediction[:info] =~ /\b(identical)\b/i
-
- / show message about dbhit and measurements
+ %td{:style=>"vertical-align:top;"}
+ %p= compound.svg
+ %p= compound.smiles
+ - array.each do |model,prediction|
+ %td{:style=>"vertical-align:top;white-space:nowrap;"}
+ - model.model.class.to_s.match("Classification") ? type = "Classification" : type = "Regression"
+ - unit = model.unit
+
+ %b{:class => "title"}
+ = "#{model.endpoint.gsub('_', ' ')} (#{model.species})"
+
+ / check for prediction
+ - if prediction[:value]
%p
- %b Compound is part of the training dataset
+ / show model type (classification|regression)
+ %b Type:
+ = type
+ %p
+ / check for database hit
+ - if prediction[:info] =~ /\b(identical)\b/i
+
+ / show message about dbhit and measurements
%p
- %b Measured activity:
+ %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| $logger.debug value ; "#{value.delog10.signif(3)} (#{unit})</br>#{compound.mmol_to_mg(value.delog10.signif(3))} #{unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"}.join("</br>") : prediction[:measurements].join(", ")
+ - else
+ - $logger.debug prediction[:measurements]
+ - $logger.debug prediction[:measurements].delog10
+ - $logger.debug prediction[:measurements].delog10.signif(3)
+ = (type == "Regression") ? "#{prediction[:measurements].delog10.signif(3)} (#{unit})</br>#{compound.mmol_to_mg(prediction[:measurements].delog10.signif(3))} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:measurements]
+
+
+ / show prediction
+ %p
+ %b Prediction:
%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(", ")
+ = (type == "Regression") ? "#{prediction[:value].delog10.signif(3)} (#{unit})</br>#{compound.mmol_to_mg(prediction[:value].delog10.signif(3))} #{(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.signif(3)} - #{interval[0].delog10.signif(3)} (#{unit})"
+ %br
+ = "#{compound.mmol_to_mg(interval[1].delog10.signif(3))} - #{compound.mmol_to_mg(interval[0].delog10.signif(3))} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if !prediction[:prediction_interval].nil?
- 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
- %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
+ %b Probability:
+ - unless prediction[:probabilities].nil?
+ - probabilities = ""
+ - prediction[:probabilities].each{|k,v| probabilities += "#{k}: #{v.signif(3)}<br>"}
+ %br
+ = probabilities
+ / show warnings
%p
- - if type == "Regression"
- %b 95% Prediction interval:
- - interval = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval])
+ - if !prediction[:info].blank?
+ %b Info:
%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?
+ %p=prediction[:info].sub(/\'.*\'/,"").sub(/,/, ",<br>")
+ - if !prediction[:warnings].blank?
+ %b Warnings:
+ - prediction[:warnings].uniq.each do |warning|
%br
- = "#{prediction[:probabilities].keys[0]}: #{prediction[:probabilities].values[0]}"
+ %p=warning.sub(/substances/, "substances<br>").sub(/prediction\:/, "prediction\:<br>")
+
+ / no prediction
+ - else
+ %br
+ - if !prediction[:info].blank?
+ %b Info:
+ %br
+ %p=prediction[:info].sub(/\'.*\'/,"").sub(/,/, ",<br>")
+ - if !prediction[:warnings].blank?
+ %b Warnings:
+ - prediction[:warnings].uniq.each do |warning|
%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."
+ %p=warning.sub(/substances/, "substances<br>").sub(/prediction\:/, "prediction\:<br>")
+ %tr
diff --git a/views/layout.haml b/views/layout.haml
index d8ff735..5e76d85 100644
--- a/views/layout.haml
+++ b/views/layout.haml
@@ -31,7 +31,9 @@
%div.col-md-3
%h1.media-heading
%small
- %a{:href=>"https://nano-lazar.in-silico.ch", :rel=>"external"} nano-lazar
+ %a.btn{:href=>"https://nano-lazar.in-silico.ch", :rel=>"external"}
+ nano-lazar
+ %span.glyphicon.glyphicon-new-window
%div.container-fluid
%topline.alert
@@ -86,16 +88,18 @@
%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"}
+ %supporters
+ %div.panel.panel-default
+ Financial support by
+ %div.panel-body
+ %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 5c3aa4f..d85d2fb 100644
--- a/views/model_details.haml
+++ b/views/model_details.haml
@@ -1,141 +1,156 @@
-%b Model:
-%br
-Source:
-%a{:href=>model.source, :rel=>"external"}
- = model.source
-%br
-- model.classification? ? type = "Classification" : type = "Regression"
-= "Type:\t"
-= type
-%br
-- training_dataset = OpenTox::Dataset.find model.model.training_dataset_id
-= "Training compounds:\t"
-= training_dataset.data_entries.size
-%br
-= "Training dataset:\t"
-%a{:href=>"#{to("/predict/dataset/#{training_dataset.name}")}"}
- = training_dataset.name
-%br
-%b Algorithms:
-%br
-Similarity:
-%a{:href=> "http://www.rubydoc.info/gems/lazar/OpenTox%2F#{model.model.algorithms["similarity"]["method"].sub("::", "%2F")}", :rel=>"external"}
- = model.model.algorithms["similarity"]["method"]
-= ", min: #{model.model.algorithms["similarity"]["min"]}"
-%br
-Prediction:
-%a{:href=>"http://www.rubydoc.info/gems/lazar/OpenTox%2F#{model.model.algorithms["prediction"]["method"].sub("::","%2f")}", :rel=>"external"}
- = model.model.algorithms["prediction"]["method"]
-%br
-Descriptors:
-= model.model.algorithms["descriptors"]["method"]+","
-= model.model.algorithms["descriptors"]["type"]
-%p
-- if type == "Classification"
- %b Independent crossvalidations:
-- else
- %b Independent crossvalidations (-log10 transformed):
-%div.row{:id=>"validations#{model.id}", :style=>"background-color:#f5f5f5;"}
- - crossvalidations.each do |cv|
- %span.col-xs-4.col-sm-4.col-md-4.col-lg-4
- = "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) if cv.accuracy
- %br
- = "Weighted accuracy:\t"
- = cv.weighted_accuracy.round(3) if cv.weighted_accuracy
- - if cv.true_rate
+%div.panel.panel-default
+ %div.panel-heading
+ %b Model:
+ %div.panel-body
+ Source:
+ %a{:href=>model.source, :rel=>"external"}
+ = model.source
+ %br
+ - model.classification? ? type = "Classification" : type = "Regression"
+ = "Type:\t"
+ = type
+ %br
+ - training_dataset = OpenTox::Dataset.find model.model.training_dataset_id
+ = "Training compounds:\t"
+ = training_dataset.data_entries.size
+ %br
+ = "Training dataset:\t"
+ %a{:href=>"#{to("/predict/dataset/#{training_dataset.name}")}"}
+ = training_dataset.name
+
+%div.panel.panel-default
+ %div.panel-heading
+ %b Algorithms:
+ %div.panel-body
+ Similarity:
+ %a{:href=> "http://www.rubydoc.info/gems/lazar/OpenTox%2F#{model.model.algorithms["similarity"]["method"].sub("::", "%2F")}", :rel=>"external"}
+ = model.model.algorithms["similarity"]["method"]
+ = ", min: #{model.model.algorithms["similarity"]["min"]}"
+ %br
+ Prediction:
+ %a{:href=>"http://www.rubydoc.info/gems/lazar/OpenTox%2F#{model.model.algorithms["prediction"]["method"].sub("::","%2f")}", :rel=>"external"}
+ = model.model.algorithms["prediction"]["method"]
+ %br
+ Descriptors:
+ = model.model.algorithms["descriptors"]["method"]+","
+ = model.model.algorithms["descriptors"]["type"]
+
+%div.panel.panel-default
+ - if type == "Classification"
+ %div.panel-heading
+ %b Independent crossvalidations:
+ - else
+ %div.panel-heading
+ %b Independent crossvalidations (-log10 transformed):
+ %div.panel-body
+ /%div.row{:id=>"validations#{model.id}", :style=>"background-color:#f5f5f5;"}
+ %div.row{:id=>"validations#{model.id}"}
+ - crossvalidations.each do |cv|
+ %span.col-xs-4.col-sm-4.col-md-4.col-lg-4
+ = "Num folds:\t"
+ = cv.folds
%br
- = "True positive rate:\t"
- = cv.true_rate[cv.accept_values[0]].round(3)
+ = "Num instances:\t"
+ = cv.nr_instances
%br
- = "True negative rate:\t"
- = cv.true_rate[cv.accept_values[1]].round(3)
- - if cv.predictivity
- %br
- = "Positive predictive value:\t"
- = cv.predictivity[cv.accept_values[0]].round(3)
- %br
- = "Negative predictive value:\t"
- = cv.predictivity[cv.accept_values[1]].round(3)
- %p
- - ["confusion_matrix", "weighted_confusion_matrix"].each_with_index do |matrix,idx|
- %b= (idx == 0 ? "Confusion Matrix" : "Weighted 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
- =( idx == 1 ? cv.send(matrix)[0][0].round(3) : cv.send(matrix)[0][0])
- %td
- =( idx == 1 ? cv.send(matrix)[0][1].round(3) : cv.send(matrix)[0][1])
- -#%td
- =cv.confusion_matrix[0][0]+cv.confusion_matrix[0][1]
- %tr
- %td
- %td inactive
- %td
- =( idx == 1 ? cv.send(matrix)[1][0].round(3) : cv.send(matrix)[1][0])
- %td
- =( idx == 1 ? cv.send(matrix)[1][1].round(3) : cv.send(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
+ = "Num unpredicted"
+ = cv.nr_unpredicted
+ - if model.classification?
+ %br
+ = "Accuracy:\t"
+ = cv.accuracy.round(3) if cv.accuracy
+ %br
+ = "Weighted accuracy:\t"
+ = cv.weighted_accuracy.round(3) if cv.weighted_accuracy
+ - if cv.true_rate
+ %br
+ = "True positive rate:\t"
+ = cv.true_rate[cv.accept_values[0]].round(3)
+ %br
+ = "True negative rate:\t"
+ = cv.true_rate[cv.accept_values[1]].round(3)
+ - if cv.predictivity
+ %br
+ = "Positive predictive value:\t"
+ = cv.predictivity[cv.accept_values[0]].round(3)
%br
- %br
- /= "Confidence plot:"
- /%p.plot
- / %img{:src=>"confp#{cv.id}.svg"}
- - if model.regression?
- %br
- %a.ht5{:href=>"https://en.wikipedia.org/wiki/Root-mean-square_deviation", :rel=>"external"} RMSE:
- = cv.rmse.round(3) if cv.rmse
- %br
- %a.ht5{:href=>"https://en.wikipedia.org/wiki/Mean_absolute_error", :rel=>"external"} MAE:
- = cv.mae.round(3) if cv.mae
- %br
- %a.ht5{:href=>"https://en.wikipedia.org/wiki/Coefficient_of_determination", :rel=>"external"}= "R"+"<sup>2</sup>"+":"
- = cv.r_squared.round(3) if cv.r_squared
- %br
- /= "Confidence plot:"
- /%p.plot
- / %img{:src=>"/confp#{cv.id}.svg"}
- /%br
- /= "Correlation plot"
- /%p.plot
- / %img{:src=>"/corrp#{cv.id}.svg"}
+ = "Negative predictive value:\t"
+ = cv.predictivity[cv.accept_values[1]].round(3)
+ %p
+ - ["confusion_matrix", "weighted_confusion_matrix"].each_with_index do |matrix,idx|
+ %b= (idx == 0 ? "Confusion Matrix" : "Weighted 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
+ =( idx == 1 ? cv.send(matrix)[0][0].round(3) : cv.send(matrix)[0][0])
+ %td
+ =( idx == 1 ? cv.send(matrix)[0][1].round(3) : cv.send(matrix)[0][1])
+ -#%td
+ =cv.confusion_matrix[0][0]+cv.confusion_matrix[0][1]
+ %tr
+ %td
+ %td inactive
+ %td
+ =( idx == 1 ? cv.send(matrix)[1][0].round(3) : cv.send(matrix)[1][0])
+ %td
+ =( idx == 1 ? cv.send(matrix)[1][1].round(3) : cv.send(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
+ %br
+ %br
+ /= "Confidence plot:"
+ /%p.plot
+ / %img{:src=>"confp#{cv.id}.svg"}
+ - if model.regression?
+ %br
+ %a.ht5{:href=>"https://en.wikipedia.org/wiki/Root-mean-square_deviation", :rel=>"external"} RMSE:
+ = cv.rmse.round(3) if cv.rmse
+ %br
+ %a.ht5{:href=>"https://en.wikipedia.org/wiki/Mean_absolute_error", :rel=>"external"} MAE:
+ = cv.mae.round(3) if cv.mae
+ %br
+ %a.ht5{:href=>"https://en.wikipedia.org/wiki/Coefficient_of_determination", :rel=>"external"}= "R"+"<sup>2</sup>"+":"
+ = cv.r_squared.round(3) if cv.r_squared
+ %br
+ /= "Confidence plot:"
+ /%p.plot
+ / %img{:src=>"/confp#{cv.id}.svg"}
+ /%br
+ /= "Correlation plot"
+ /%p.plot
+ / %img{:src=>"/corrp#{cv.id}.svg"}
-%br
+%div.panel.panel-default
+ %div.panel-heading
+ %b QMRF:
+ %div.panel-body
+ %a.btn.btn-default.btn-xs{:href=>"#{to("/report/#{model.id}")}", :id=>"report#{model.id}", :style=>"font-size:small;"}
+ %span.glyphicon.glyphicon-download-alt
+ XML
diff --git a/views/predict.haml b/views/predict.haml
index 59630d0..9fb56cb 100644
--- a/views/predict.haml
+++ b/views/predict.haml
@@ -125,13 +125,12 @@
%br
%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)
- -#%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", :disabled=>"disabled"}
- %input{:type=>"hidden", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv", :disabled=>"disabled"}
+ %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"}
%fieldset#middle.well
%h2 2. Select one or more endpoints
@@ -140,19 +139,26 @@
%div{:id=>endpoint.gsub(/\s+/, "_")}
%h4.head-back=endpoint
- @models.select{|m| m.endpoint == endpoint}.each do |model|
- %div.row{:id => model.id}
- %span.col-sm-4
+ %div.row{:id => model.id,:style=>"margin-bottom:1em;"}
+ %span.col-lg-4.col-md-4.col-sm-4.col-xs-4
%input{:type => "checkbox", :name => "selection[#{model.id}]", :id => "selection[#{model.species.gsub(/\s+/, "_")}]", :value => true, :disabled => false}
%label{:for => "selection[#{model.species.gsub(/\s+/, "_")}]"}
= model.species
- %span.col-sm-8
+ %span.col-lg-8.col-md-8.col-sm-8.col-xs-8
%a.btn.btn-default.btn-xs{:data=>{:toggle=>"collapse"}, :href=>"#details#{model.id}", :onclick=>"load#{model.id}Details('#{model}')", :id => "link#{model.id}", :style=>"font-size:small;"}
+ %span.glyphicon.glyphicon-menu-right
Details | Validation
%img.h2{:src=>"/images/wait30trans.gif", :id=>"circle#{model.id}", :class=>"circle#{model.id}", :alt=>"wait", :style=>"display:none;"}
%div.panel-collapse.collapse{:id=>"details#{model.id}", :style=>"margin-left:1em;"}
:javascript
function load#{model.id}Details(model) {
button = document.getElementById("link#{model.id}");
+ span = button.childNodes[1];
+ if (span.className == "glyphicon glyphicon-menu-right"){
+ span.className = "glyphicon glyphicon-menu-down";
+ } else if (span.className = "glyphicon glyphicon-menu-down"){
+ span.className = "glyphicon glyphicon-menu-right";
+ };
image = document.getElementById("circle#{model.id}");
if ($('modeldetails#{model.id}').length == 0) {
$(button).hide();
@@ -170,9 +176,9 @@
}
%fieldset#bottom.well
%div.row
- %div.col-md-2
+ %div.col-lg-2.col-md-2.col-sm-2.col-xs-2
%h2
3. Predict
- %div.col-md-10
+ %div.col-lg-10.col-md-10.col-sm-10.col-xs-10
%input.btn.btn-warning.h2{ :type => "submit", :id => "submit", :value=>">>", :onclick => "getsmiles()"}
%img.h2{:src=>"/images/wait30trans.gif", :id=>"circle", :class=>"circle", :alt=>"wait", :style=>"display:none;"}
diff --git a/views/prediction.haml b/views/prediction.haml
index 24d62fa..a657dba 100644
--- a/views/prediction.haml
+++ b/views/prediction.haml
@@ -81,11 +81,11 @@
/ show warnings and info
%p
- if !prediction[:info].blank?
- %b info:
+ %b Info:
%br
%p=prediction[:info].sub(/excluded/, "excluded<br>")
- if !prediction[:warnings].blank?
- %b warnings:
+ %b Warnings:
- prediction[:warnings].uniq.each do |warning|
%br
%p=warning
@@ -94,11 +94,11 @@
%br
- @dbhit[i] = false
- if !prediction[:info].blank?
- %b info:
+ %b Info:
%br
%p=prediction[:info].sub(/excluded/, "excluded<br>")
- if !prediction[:warnings].blank?
- %b warnings:
+ %b Warnings:
- prediction[:warnings].uniq.each do |warning|
%br
%p=warning.sub(/substances/, "substances<br>").sub(/prediction\:/, "prediction\:<br>")
diff --git a/views/style.scss b/views/style.scss
index 308d1ba..ac070a1 100644
--- a/views/style.scss
+++ b/views/style.scss
@@ -35,7 +35,6 @@ h4.head-back, h5.head-back{
}
.nav-tabs {
background-color: #E7E7E7;
- //margin-bottom: 0;
li.active a:hover {
background-color: #f5f5f5;
@@ -84,11 +83,10 @@ ul.share-buttons{
padding-right: 5px;
}
supporters{
- background-color: white;
text-align:center;
img{
width: 200px;
- margin-right: 1em;
+ margin: 1em;
}
}