diff options
Diffstat (limited to 'application.rb')
-rw-r--r-- | application.rb | 98 |
1 files changed, 68 insertions, 30 deletions
diff --git a/application.rb b/application.rb index 8d96dbe..3b88700 100644 --- a/application.rb +++ b/application.rb @@ -17,11 +17,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 @@ -75,6 +80,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 @@ -225,7 +231,7 @@ 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 => "" - 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| task.progress(5) @model.update :status => "Uploading and saving dataset", :task_uri => task.uri @@ -243,14 +249,17 @@ 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 + when ".sdf" + sdf = params[:file][:tempfile].read + @dataset.load_sdf(sdf, subjectid) 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." @@ -267,11 +276,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/) @@ -285,7 +294,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, @@ -293,38 +302,51 @@ 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 - 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 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') @@ -350,8 +372,14 @@ post '/predict/?' do # post chemical name to model confidence = nil title = nil db_activities = [] - lazar = OpenTox::Model::Lazar.new model.uri + lazar = OpenTox::Model::Lazar.find model.uri prediction_dataset_uri = lazar.run({:compound_uri => @compound.uri, :subjectid => subjectid}) + LOGGER.debug "Prediction dataset_uri: #{prediction_dataset_uri}" + if lazar.value_map + @value_map = lazar.value_map + else + @value_map = nil + end prediction_dataset = OpenTox::LazarPrediction.find(prediction_dataset_uri, subjectid) if prediction_dataset.metadata[OT.hasSource].match(/dataset/) @predictions << { @@ -366,12 +394,17 @@ post '/predict/?' do # post chemical name to model :title => model.name, :error => prediction.metadata[OT.error] } + elsif prediction_dataset.value(@compound).nil? + @predictions << { + :title => model.name, + :error => "Not enough similar compounds in training dataset." + } else @predictions << { :title => model.name, :model_uri => model.uri, - :prediction => prediction.metadata[OT.prediction], - :confidence => prediction.metadata[OT.confidence] + :prediction => prediction_dataset.value(@compound), + :confidence => prediction_dataset.confidence(@compound) } end end @@ -385,8 +418,13 @@ post "/lazar/?" do # get detailed prediction @page = 0 @page = params[:page].to_i if params[:page] @model_uri = params[:model_uri] - lazar = OpenTox::Model::Lazar.new @model_uri + lazar = OpenTox::Model::Lazar.find @model_uri prediction_dataset_uri = lazar.run(:compound_uri => params[:compound_uri], :subjectid => session[:subjectid]) + if lazar.value_map + @value_map = lazar.value_map + else + @value_map = nil + end @prediction = OpenTox::LazarPrediction.find(prediction_dataset_uri, session[:subjectid]) @compound = OpenTox::Compound.new(params[:compound_uri]) haml :lazar |