diff options
author | gebele <gebele@alfadeo.de> | 2011-07-26 11:48:03 +0200 |
---|---|---|
committer | gebele <gebele@alfadeo.de> | 2011-07-26 11:48:03 +0200 |
commit | 26ec3b805361bfebc61c5aaed2a3e568c6434049 (patch) | |
tree | bbe5a49e70160ac337fa744639518824927b8019 | |
parent | 0befb6511f24b616a10b06bccf0c55fae36a567b (diff) | |
parent | 41945b3dc251ca00580916c3cbc7d26c2093ca89 (diff) |
merged from development-> feature/policy
-rw-r--r-- | application.rb | 75 | ||||
-rw-r--r-- | helper.rb | 8 | ||||
-rw-r--r-- | model.rb | 10 | ||||
-rwxr-xr-x | public/javascripts/toxcreate.js | 13 | ||||
-rw-r--r-- | views/classification_validation.haml | 59 | ||||
-rw-r--r-- | views/create.haml | 17 | ||||
-rw-r--r-- | views/layout.haml | 13 | ||||
-rw-r--r-- | views/model.haml | 10 | ||||
-rw-r--r-- | views/style.sass | 1 |
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 << { @@ -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 @@ -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 © %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 |