summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgebele <gebele@alfadeo.de>2011-07-26 11:48:03 +0200
committergebele <gebele@alfadeo.de>2011-07-26 11:48:03 +0200
commit26ec3b805361bfebc61c5aaed2a3e568c6434049 (patch)
treebbe5a49e70160ac337fa744639518824927b8019
parent0befb6511f24b616a10b06bccf0c55fae36a567b (diff)
parent41945b3dc251ca00580916c3cbc7d26c2093ca89 (diff)
merged from development-> feature/policy
-rw-r--r--application.rb75
-rw-r--r--helper.rb8
-rw-r--r--model.rb10
-rwxr-xr-xpublic/javascripts/toxcreate.js13
-rw-r--r--views/classification_validation.haml59
-rw-r--r--views/create.haml17
-rw-r--r--views/layout.haml13
-rw-r--r--views/model.haml10
-rw-r--r--views/style.sass1
9 files changed, 142 insertions, 64 deletions
diff --git a/application.rb b/application.rb
index 6ed6da2..9242e22 100644
--- a/application.rb
+++ b/application.rb
@@ -18,11 +18,16 @@ set :lock, true
helpers do
- def error(message)
+ # message will be displayed to the user
+ # error will be raised -> taks will be set to error -> error details available via task-uri
+ def error(message, error=nil)
LOGGER.error message
@model.update :status => "Error", :error_messages => message
- flash[:notice] = message
- redirect url_for('/create')
+ if error
+ raise error
+ else
+ raise message
+ end
end
private
@@ -76,6 +81,7 @@ end
get '/models/?' do
@models = ToxCreateModel.all.sort(:order => "DESC")
+ @models.each{|m| raise "internal redis error: model is nil" unless m}
subjectstring = session[:subjectid] ? "?subjectid=#{CGI.escape(session[:subjectid])}" : ""
haml :models, :locals=>{:models=>@models, :subjectstring => subjectstring}
end
@@ -315,7 +321,12 @@ post '/models' do # create a new model
@model = ToxCreateModel.create(:name => name, :subjectid => subjectid)
@model.update :web_uri => url_for("/model/#{@model.id}", :full), :warnings => ""
+<<<<<<< HEAD
task = OpenTox::Task.create("Uploading dataset and creating lazar model",url_for("/models",:full)) do |task|
+=======
+ task = OpenTox::Task.create("Toxcreate Task - Uploading dataset and creating lazar model",url_for("/models",:full)) do |task|
+
+>>>>>>> development
task.progress(5)
@model.update :status => "Uploading and saving dataset", :task_uri => task.uri
@@ -332,14 +343,14 @@ post '/models' do # create a new model
File.rename(params[:file][:tempfile].path, excel_file) # add extension, spreadsheet does not read files without extensions
@dataset.load_spreadsheet(Excel.new excel_file, subjectid)
if @dataset.metadata[OT.Errors]
- error "Incorrect file format. Please follow the instructions for #{link_to "Excel", "/help"} or #{link_to "CSV", "/help"} formats."
+ raise "Incorrect file format. Please follow the instructions for #{link_to "Excel", "/help"} or #{link_to "CSV", "/help"} formats."
end
else
- error "#{params[:file][:filename]} has a unsupported file type."
+ raise "#{params[:file][:filename]} has an unsupported file type."
end
@dataset.save(subjectid)
rescue => e
- error "Dataset creation failed with #{e.message}"
+ error "Dataset creation failed '#{e.message}'",e
end
if @dataset.features.keys.size != 1
error "More than one feature in dataset #{params[:file][:filename]}. Please delete irrelvant columns and try again."
@@ -356,11 +367,11 @@ post '/models' do # create a new model
@model.update :warnings => @dataset.metadata[OT.Warnings] unless @dataset.metadata[OT.Warnings] and @dataset.metadata[OT.Warnings].empty?
task.progress(15)
begin
- lazar = OpenTox::Model::Lazar.create(:dataset_uri => @dataset.uri, :prediction_feature => @prediction_feature.uri, :subjectid => subjectid)
+ lazar = OpenTox::Model::Lazar.create( {:dataset_uri => @dataset.uri, :prediction_feature => @prediction_feature.uri, :subjectid => subjectid},
+ OpenTox::SubTask.new(task,15,25))
rescue => e
- error "Model creation failed with '#{e.message}'."# Please check if the input file is in a valid #{link_to "Excel", "/help"} or #{link_to "CSV", "/help"} format."
+ error "Model creation failed",e # Please check if the input file is in a valid #{link_to "Excel", "/help"} or #{link_to "CSV", "/help"} format."
end
- task.progress(25)
=begin
type = "unknown"
if lazar.metadata[RDF.type].grep(/Classification/)
@@ -374,7 +385,7 @@ post '/models' do # create a new model
if CONFIG[:services]["opentox-validation"]
@model.update :status => "Validating model"
begin
- validation = OpenTox::Crossvalidation.create( {
+ crossvalidation = OpenTox::Crossvalidation.create( {
:algorithm_uri => lazar.metadata[OT.algorithm],
:dataset_uri => lazar.parameter("dataset_uri"),
:subjectid => subjectid,
@@ -382,38 +393,57 @@ post '/models' do # create a new model
:algorithm_params => "feature_generation_uri=#{lazar.parameter("feature_generation_uri")}" },
nil, OpenTox::SubTask.new(task,25,80))
- @model.update(:validation_uri => validation.uri)
+ @model.update(:validation_uri => crossvalidation.uri)
LOGGER.debug "Validation URI: #{@model.validation_uri}"
# create summary
- validation.summary(subjectid).each do |k,v|
- begin
- eval "@model.update :#{k.to_s} => v" if v
- rescue
- eval "@model.update :#{k.to_s} => 0"
+ validation = crossvalidation.statistics(subjectid)
+ @model.update(:nr_predictions => validation.metadata[OT.numInstances].to_i - validation.metadata[OT.numUnpredicted].to_i)
+ if validation.metadata[OT.classificationStatistics]
+ @model.update(:correct_predictions => validation.metadata[OT.classificationStatistics][OT.percentCorrect].to_f)
+ @model.update(:confusion_matrix => validation.confusion_matrix.to_yaml)
+ @model.update(:weighted_area_under_roc => validation.metadata[OT.classificationStatistics][OT.weightedAreaUnderRoc].to_f)
+ validation.metadata[OT.classificationStatistics][OT.classValueStatistics].each do |m|
+ if m[OT.classValue] =~ TRUE_REGEXP
+ #HACK: estimate true feature value correctly
+ @model.update(:sensitivity => m[OT.truePositiveRate])
+ @model.update(:specificity => m[OT.trueNegativeRate])
+ break
+ end
end
+ else
+ @model.update(:r_square => validation.metadata[OT.regressionStatistics][OT.rSquare].to_f)
+ @model.update(:root_mean_squared_error => validation.metadata[OT.regressionStatistics][OT.rootMeanSquaredError].to_f)
+ @model.update(:mean_absolute_error => validation.metadata[OT.regressionStatistics][OT.meanAbsoluteError].to_f)
end
-
+ rescue => e
+ @model.update :warnings => @model.warnings.to_s+"\nModel crossvalidation failed with #{e.message}."
+ error "Model validation failed",e
+ end
+
+ begin
@model.update :status => "Creating validation report"
- validation_report_uri = validation.find_or_create_report(subjectid, OpenTox::SubTask.new(task,80,90)) #unless @model.dirty?
+ validation_report_uri = crossvalidation.find_or_create_report(subjectid, OpenTox::SubTask.new(task,80,90)) #unless @model.dirty?
@model.update :validation_report_uri => validation_report_uri, :status => "Creating QMRF report"
qmrf_report = OpenTox::Crossvalidation::QMRFReport.create(@model.uri, subjectid, OpenTox::SubTask.new(task,90,99))
@model.update(:validation_qmrf_uri => qmrf_report.uri, :status => "Completed")
-
rescue => e
+<<<<<<< HEAD
LOGGER.debug "Model validation failed with #{e.message}."
@model.save # to avoid dirty models
@model.update :warnings => @model.warnings + "\nModel validation failed with #{e.message}.", :status => "Error", :error_messages => e.message
+=======
+ error "Model report creation failed",e
+>>>>>>> development
end
-
else
@model.update(:status => "Completed") #, :warnings => @model.warnings + "\nValidation service cannot be accessed from localhost.")
- task.progress(100)
+ task.progress(99)
end
lazar.uri
end
@model.update :task_uri => task.uri
-
+ sleep 0.25 # power nap: ohm sometimes returns nil values for model.status or for model itself
flash[:notice] = "Model creation and validation started - this may last up to several hours depending on the number and size of the training compounds."
redirect url_for('/models')
@@ -441,6 +471,7 @@ post '/predict/?' do # post chemical name to model
db_activities = []
lazar = OpenTox::Model::Lazar.new model.uri
prediction_dataset_uri = lazar.run({:compound_uri => @compound.uri, :subjectid => subjectid})
+ LOGGER.debug "Prediction dataset_uri: #{prediction_dataset_uri}"
prediction_dataset = OpenTox::LazarPrediction.find(prediction_dataset_uri, subjectid)
if prediction_dataset.metadata[OT.hasSource].match(/dataset/)
@predictions << {
diff --git a/helper.rb b/helper.rb
index 2bbab30..408f8bc 100644
--- a/helper.rb
+++ b/helper.rb
@@ -53,7 +53,13 @@ helpers do
def sort(descriptors)
features = {:activating => [], :deactivating => []}
- descriptors.each { |d| features[d[OT.effect].to_sym] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} }
+ descriptors.each do |d|
+ if d[OT.effect] =~ TRUE_REGEXP
+ features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]}
+ elsif d[OT.effect] =~ FALSE_REGEXP
+ features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]}
+ end
+ end
features
end
diff --git a/model.rb b/model.rb
index 5b1f4f5..e433893 100644
--- a/model.rb
+++ b/model.rb
@@ -27,14 +27,10 @@ class ToxCreateModel < Ohm::Model
#attributey :validation_qmrf_task_uri
attribute :validation_qmrf_uri
-
+ attribute :confusion_matrix
attribute :nr_compounds
- attribute :nr_predictions
- attribute :true_positives
- attribute :false_positives
- attribute :true_negatives
- attribute :false_negatives
- attribute :correct_predictions
+ attribute :nr_predictions
+ attribute :correct_predictions
attribute :weighted_area_under_roc
attribute :sensitivity
attribute :specificity
diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js
index 196e7d0..72065cb 100755
--- a/public/javascripts/toxcreate.js
+++ b/public/javascripts/toxcreate.js
@@ -4,10 +4,10 @@ $(function() {
var id = id;
this.bind("click", function() {
if($("a#show_model_" + id + "_warnings").html()=="show") {
- $("dd#model_" + id + "_warnings").slideDown("slow");
+ $("div#model_" + id + "_warnings").slideDown("slow");
$("a#show_model_" + id + "_warnings").html("hide");
}else{
- $("dd#model_" + id + "_warnings").slideUp("slow");
+ $("div#model_" + id + "_warnings").slideUp("slow");
$("a#show_model_" + id + "_warnings").html("show");
}
return false;
@@ -50,7 +50,7 @@ $(function() {
if( status_before != status_after) {
$("span#model_" + id + "_status").html(data);
loadModel(id, 'model');
- if (status_after == "Completed") id = -1;
+ if (status_after == "Completed" || status_after == "Error") id = -1;
}
},
error: function(data) {
@@ -101,6 +101,7 @@ $(function() {
success: function(data) {
if (view == "model") $("div#model_" + id).html(data);
if (view.match(/validation/)) $("dl#model_validation_" + id).html(data);
+ addExternalLinks();
},
error: function(data) {
//alert("loadModel error");
@@ -326,6 +327,10 @@ jQuery.fn.deleteModel = function(type, options) {
};
$(document).ready(function() {
+ addExternalLinks();
+});
+
+addExternalLinks = function() {
$('A[rel="external"]').each(function() {
$(this).attr('alt', 'Link opens in new window.');
$(this).attr('title', 'Link opens in new window.');
@@ -334,4 +339,4 @@ $(document).ready(function() {
window.open($(this).attr('href'));
return false;
});
-});
+};
diff --git a/views/classification_validation.haml b/views/classification_validation.haml
index 5649d7f..f25a321 100644
--- a/views/classification_validation.haml
+++ b/views/classification_validation.haml
@@ -1,33 +1,44 @@
%dt Correct predictions:
%dd
- = sprintf("%.2f", model.correct_predictions.to_f) if model.correct_predictions
- = '%'
+ = sprintf("%.2f", model.correct_predictions.to_f) if model.correct_predictions
+ = '%'
%dt
- %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :rel => "external"} Weighted area under ROC:
+ %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :rel => "external"} Weighted area under ROC:
%dd
- = sprintf("%.3f", model.weighted_area_under_roc.to_f) if model.weighted_area_under_roc
+ = sprintf("%.3f", model.weighted_area_under_roc.to_f) if model.weighted_area_under_roc
%dt
- %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :rel => "external"} Specificity:
+ %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :rel => "external"} Specificity:
%dd= sprintf("%.3f", model.specificity.to_f) if model.specificity
%dt
- %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :rel => "external"} Sensitivity:
+ %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :rel => "external"} Sensitivity:
%dd= sprintf("%.3f", model.sensitivity.to_f) if model.sensitivity
%dt
- %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :rel => "external"} Confusion Matrix:
-%dd
- %table
- %tr
- %td{:colspan => 2, :rowspan => 2}
- %th{:colspan => 2} Measured
- %tr
- %th{:bgcolor => "#CCD2DC"} active
- %th{:bgcolor => "#CCD2DC"} inactive
- %tr
- %th{:rowspan => 2} Predicted
- %th{:bgcolor => "#CCD2DC"} active
- %td= model.true_positives if model.true_positives
- %td= model.false_positives if model.false_positives
- %tr
- %th{:bgcolor => "#CCD2DC"} inactive
- %td= model.false_negatives if model.false_negatives
- %td= model.true_negatives if model.true_negatives
+ %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :rel => "external"} Confusion Matrix:
+- if model.confusion_matrix
+ - cm = YAML.load(model.confusion_matrix)
+ %dd
+ %table
+ %tr
+ %td{:colspan => 2, :rowspan => 2}
+ %th{:colspan => (cm.size - 1)} Measured
+ %tr
+ - (1..cm[0].size-1).each do |i|
+ %th{:bgcolor => "#CCD2DC"}
+ = cm[0][i]
+ %tr
+ %th{:rowspan => (cm.size - 1)} Predicted
+ - (0..cm[1].size-1).each do |i|
+ - if i == 0
+ %th{:bgcolor => "#CCD2DC"}
+ = cm[1][i]
+ - else
+ %td= cm[1][i]
+ - if cm.size > 2
+ - (2..cm.size-1).each do |i|
+ %tr
+ - (0..cm[i].size-1).each do |j|
+ - if j == 0
+ %th{:bgcolor => "#CCD2DC"}
+ = cm[i][j]
+ - else
+ %td= cm[i][j]
diff --git a/views/create.haml b/views/create.haml
index 757adc2..11482c5 100644
--- a/views/create.haml
+++ b/views/create.haml
@@ -1,6 +1,12 @@
.input
- This service creates
+ This service creates and validates new
+ %em= toggle_link("#classification","classification")
+ and
+ %em= toggle_link("#regression","regression")
+ structure-activity models from your experimental data. The models can be used to predict toxicity of new chemicals (e.g. for
+ %a{:href => "http://ec.europa.eu/environment/chemicals/reach/reach_intro.htm", :rel => "external"} REACH
+ purposes) and to reduce the need for animal testing. The following methods are currently available:
%ul
%li
= toggle_link("#lazar_description","lazar")
@@ -10,9 +16,14 @@
= toggle_link("#lazar_description","lazar")
%em= toggle_link("#regression","regression")
models (experimental)
- from your uploaded datasets. Further modelling algorithms will be added in future versions.
-
+ Further modelling algorithms will be added in future versions.
+
%p
+ To create a prediction model, you will need to upload training data that includes chemical structures and their measured toxicity values, in
+ = link_to "Excel", '/help'
+ or
+ = link_to "CSV", '/help'
+ file formats.
Please read the
= link_to "instructions for creating training datasets", '/help'
before submitting.
diff --git a/views/layout.haml b/views/layout.haml
index 174db9f..6f6afcb 100644
--- a/views/layout.haml
+++ b/views/layout.haml
@@ -14,7 +14,7 @@
.logo
%img{:src => "ToxCreate_rgb_72.png", :alt => 'ToxCreate', :align => 'right'}/
%br
- Create and evaluate models to predict toxicity
+ Creates computational models to predict toxicity
.index
%ul
%li{:class => ("selected" if /\/create|echa|ambit|feature/ =~ request.path )}
@@ -47,7 +47,18 @@
= yield
.footer
+ Disclaimer: ToxCreate uses state-of-the-art published and tested algorithms and methodologies with full validation information. However, just as with experimental measurements, computational predictions are subject to varying degrees of accuracy and uncertainty, so please read the full report carefully, particularly the validation information. No liability is accepted for any inaccuracy in predictions.
+ %p
+ - tag = `git tag`.split("\n").last
+ - tagdate = `git show #{tag}|grep Date`.chomp
+ Version:
+ = tag
+ ,
+ = tagdate
&copy;
%a{:href => 'http://www.in-silico.ch', :rel => "external"} in silico toxicology
2009-2011, powered by
%a{:href => 'http://www.opentox.org', :rel => "external"} <span style="color:#5D308A;font-family:arial,sans-serif,helvetica;letter-spacing:-1px;">Open</span><span style="color:#000;font-family:arial,sans-serif,helvetica;font-weight:bold;letter-spacing:-1px;">Tox</span>
+ (a project funded by the
+ %a{:href => "http://cordis.europa.eu/fp7/"} 7th Framework Programme
+ of the European Commission)
diff --git a/views/model.haml b/views/model.haml
index c64d81e..d2637c8 100644
--- a/views/model.haml
+++ b/views/model.haml
@@ -43,10 +43,16 @@
- if model.error_messages
%dt Errors:
%dd= model.error_messages
+ - if CONFIG[:logger]=="debug"
+ %dt Task:
+ %dd
+ %a{:href => "#{model.task_uri}", :rel => "external"}
+ = model.task_uri
- if model.warnings
%dt Warnings:
- %a{:href => "#", :id => "show_model_#{model.id}_warnings"} show
- %dd{:id => "model_#{model.id}_warnings", :style => "display: none;"}= model.warnings
+ %dd
+ %a{:href => "#", :id => "show_model_#{model.id}_warnings"} show
+ %div{:id => "model_#{model.id}_warnings", :style => "display: none;"}= model.warnings
%dt Algorithm:
%dd= toggle_link("#lazar_description","lazar")
- if model.type
diff --git a/views/style.sass b/views/style.sass
index 8abc028..94bf766 100644
--- a/views/style.sass
+++ b/views/style.sass
@@ -220,6 +220,7 @@ body
.footer
margin: 0.5em
padding: 0.5em
+ font-size: small
.active
color: red