diff options
Diffstat (limited to 'report')
-rwxr-xr-x | report/environment.rb | 5 | ||||
-rw-r--r-- | report/plot_factory.rb | 166 | ||||
-rwxr-xr-x | report/report_application.rb | 2 | ||||
-rwxr-xr-x | report/report_content.rb | 82 | ||||
-rwxr-xr-x | report/report_factory.rb | 46 | ||||
-rwxr-xr-x | report/report_persistance.rb | 71 | ||||
-rw-r--r-- | report/report_service.rb | 3 | ||||
-rwxr-xr-x | report/validation_access.rb | 29 | ||||
-rwxr-xr-x | report/validation_data.rb | 88 | ||||
-rwxr-xr-x | report/xml_report.rb | 2 |
10 files changed, 351 insertions, 143 deletions
diff --git a/report/environment.rb b/report/environment.rb index 12e3272..59465aa 100755 --- a/report/environment.rb +++ b/report/environment.rb @@ -4,7 +4,7 @@ 'rexml/document', 'ruby-plot', 'opentox-ruby' ].each do |g| require g end -gem 'ruby-plot', '= 0.0.2' +gem 'ruby-plot', "~>0.4.0" #R.quit @@ -12,8 +12,7 @@ module Reports end require "lib/ot_predictions.rb" -#require "lib/active_record_setup.rb" -require "lib/data_mapper_util.rb" +require "lib/ohm_util.rb" require "report/plot_factory.rb" require "report/xml_report.rb" diff --git a/report/plot_factory.rb b/report/plot_factory.rb index 43c45fc..a4e415a 100644 --- a/report/plot_factory.rb +++ b/report/plot_factory.rb @@ -77,8 +77,9 @@ module Reports x << x_i y << y_i end - - RubyPlot::plot_points(out_file, "Regression plot", "Predicted values", "Actual values", names, x, y ) + + raise "no predictions performed" if x.size==0 || x[0].size==0 + RubyPlot::regression_point_plot(out_file, "Regression plot", "Predicted values", "Actual values", names, x, y ) end @@ -101,7 +102,7 @@ module Reports tp_rates = [] attribute_values.each do |value| begin - data = transform_predictions(validation_set.filter({split_set_attribute => value}), class_value, false) + data = transform_roc_predictions(validation_set.filter({split_set_attribute => value}), class_value, false) names << value.to_s fp_rates << data[:fp_rate][0] tp_rates << data[:tp_rate][0] @@ -111,11 +112,50 @@ module Reports end RubyPlot::plot_lines(out_file, "ROC-Plot", "False positive rate", "True Positive Rate", names, fp_rates, tp_rates ) else - data = transform_predictions(validation_set, class_value, show_single_curves) + data = transform_roc_predictions(validation_set, class_value, show_single_curves) RubyPlot::plot_lines(out_file, "ROC-Plot", "False positive rate", "True Positive Rate", data[:names], data[:fp_rate], data[:tp_rate], data[:faint] ) end end + + def self.create_confidence_plot( out_file, validation_set, class_value, split_set_attribute=nil, show_single_curves=false ) + + LOGGER.debug "creating confidence plot for '"+validation_set.size.to_s+"' validations, out-file:"+out_file.to_s + + if split_set_attribute + attribute_values = validation_set.get_values(split_set_attribute) + names = [] + confidence = [] + performance = [] + attribute_values.each do |value| + begin + data = transform_confidence_predictions(validation_set.filter({split_set_attribute => value}), class_value, false) + names << value.to_s + confidence << data[:confidence][0] + performance << data[:performance][0] + rescue + LOGGER.warn "could not create confidence plot for "+value.to_s + end + end + #RubyPlot::plot_lines(out_file, "Percent Correct vs Confidence Plot", "Confidence", "Percent Correct", names, fp_rates, tp_rates ) + case validation_set.unique_feature_type + when "classification" + RubyPlot::accuracy_confidence_plot(out_file, "Percent Correct vs Confidence Plot", "Confidence", "Percent Correct", names, confidence, performance) + when "regression" + RubyPlot::accuracy_confidence_plot(out_file, "RMSE vs Confidence Plot", "Confidence", "RMSE", names, confidence, performance, true) + end + else + data = transform_confidence_predictions(validation_set, class_value, show_single_curves) + case validation_set.unique_feature_type + when "classification" + RubyPlot::accuracy_confidence_plot(out_file, "Percent Correct vs Confidence Plot", "Confidence", "Percent Correct", data[:names], data[:confidence], data[:performance]) + when "regression" + RubyPlot::accuracy_confidence_plot(out_file, "RMSE vs Confidence Plot", "Confidence", "RMSE", data[:names], data[:confidence], data[:performance], true) + end + end + end + + def self.create_bar_plot( out_file, validation_set, title_attribute, value_attributes ) LOGGER.debug "creating bar plot, out-file:"+out_file.to_s @@ -127,7 +167,7 @@ module Reports validation_set.validations.each do |v| values = [] value_attributes.each do |a| - validation_set.get_domain_for_attr(a).each do |class_value| + validation_set.get_accept_values_for_attr(a).each do |class_value| value = v.send(a) if value.is_a?(Hash) if class_value==nil @@ -161,7 +201,7 @@ module Reports end - def self.create_ranking_plot( svg_out_file, validation_set, compare_attribute, equal_attribute, rank_attribute, class_value=nil ) + def self.create_ranking_plot( out_file, validation_set, compare_attribute, equal_attribute, rank_attribute, class_value=nil ) #compute ranks #puts "rank attibute is "+rank_attribute.to_s @@ -184,14 +224,14 @@ module Reports ranks, nil, #0.1, validation_set.num_different_values(equal_attribute), - svg_out_file) + out_file) end protected - def self.plot_ranking( title, comparables_array, ranks_array, confidence = nil, numdatasets = nil, svg_out_file = nil ) + def self.plot_ranking( title, comparables_array, ranks_array, confidence = nil, numdatasets = nil, out_file = nil ) (confidence and numdatasets) ? conf = "-q "+confidence.to_s+" -k "+numdatasets.to_s : conf = "" - svg_out_file ? show = "-o" : show = "" + out_file ? show = "-o" : show = "" (title and title.length > 0) ? tit = '-t "'+title+'"' : tit = "" #title = "-t \""+ranking_value_prop+"-Ranking ("+comparables.size.to_s+" "+comparable_prop+"s, "+num_groups.to_s+" "+ranking_group_prop+"s, p < "+p.to_s+")\" " @@ -208,12 +248,12 @@ module Reports end raise "rank plot failed" unless $?==0 - if svg_out_file - f = File.new(svg_out_file, "w") + if out_file + f = File.new(out_file, "w") f.puts res end - svg_out_file ? svg_out_file : res + out_file ? out_file : res end def self.demo_ranking_plot @@ -221,7 +261,7 @@ module Reports end private - def self.transform_predictions(validation_set, class_value, add_single_folds=false) + def self.transform_roc_predictions(validation_set, class_value, add_single_folds=false) if (validation_set.size > 1) @@ -229,7 +269,7 @@ module Reports sum_roc_values = { :predicted_values => [], :actual_values => [], :confidence_values => []} (0..validation_set.size-1).each do |i| - roc_values = validation_set.get(i).get_predictions.get_roc_values(class_value) + roc_values = validation_set.get(i).get_predictions.get_prediction_values(class_value) sum_roc_values[:predicted_values] += roc_values[:predicted_values] sum_roc_values[:confidence_values] += roc_values[:confidence_values] sum_roc_values[:actual_values] += roc_values[:actual_values] @@ -252,24 +292,118 @@ module Reports faint << false return { :names => names, :fp_rate => fp_rate, :tp_rate => tp_rate, :faint => faint } else - roc_values = validation_set.validations[0].get_predictions.get_roc_values(class_value) + roc_values = validation_set.validations[0].get_predictions.get_prediction_values(class_value) tp_fp_rates = get_tp_fp_rates(roc_values) return { :names => ["default"], :fp_rate => [tp_fp_rates[:fp_rate]], :tp_rate => [tp_fp_rates[:tp_rate]] } end end + def self.transform_confidence_predictions(validation_set, class_value, add_single_folds=false) + + if (validation_set.size > 1) + + names = []; performance = []; confidence = []; faint = [] + sum_confidence_values = { :predicted_values => [], :actual_values => [], :confidence_values => []} + + (0..validation_set.size-1).each do |i| + confidence_values = validation_set.get(i).get_predictions.get_prediction_values(class_value) + sum_confidence_values[:predicted_values] += confidence_values[:predicted_values] + sum_confidence_values[:confidence_values] += confidence_values[:confidence_values] + sum_confidence_values[:actual_values] += confidence_values[:actual_values] + + if add_single_folds + begin + pref_conf_rates = get_performance_confidence_rates(confidence_values) + names << "fold "+i.to_s + performance << pref_conf_rates[:performance] + confidence << pref_conf_rates[:confidence] + faint << true + rescue + LOGGER.warn "could not get confidence vals for fold "+i.to_s + end + end + end + pref_conf_rates = get_performance_confidence_rates(sum_confidence_values, validation_set.unique_feature_type) + names << nil # "all" + performance << pref_conf_rates[:performance] + confidence << pref_conf_rates[:confidence] + faint << false + return { :names => names, :performance => performance, :confidence => confidence, :faint => faint } + + else + confidence_values = validation_set.validations[0].get_predictions.get_prediction_values(class_value) + pref_conf_rates = get_performance_confidence_rates(confidence_values, validation_set.unique_feature_type) + return { :names => ["default"], :performance => [pref_conf_rates[:performance]], :confidence => [pref_conf_rates[:confidence]] } + end + end + def self.demo_rock_plot roc_values = {:confidence_values => [0.1, 0.9, 0.5, 0.6, 0.6, 0.6], :predicted_values => [1, 0, 0, 1, 0, 1], :actual_values => [0, 1, 0, 0, 1, 1]} tp_fp_rates = get_tp_fp_rates(roc_values) data = { :names => ["default"], :fp_rate => [tp_fp_rates[:fp_rate]], :tp_rate => [tp_fp_rates[:tp_rate]] } - RubyPlot::plot_lines("/tmp/plot.svg", + RubyPlot::plot_lines("/tmp/plot.png", "ROC-Plot", "False positive rate", "True Positive Rate", data[:names], data[:fp_rate], data[:tp_rate], data[:faint] ) end + def self.get_performance_confidence_rates(roc_values, feature_type) + + c = roc_values[:confidence_values] + p = roc_values[:predicted_values] + a = roc_values[:actual_values] + raise "no prediction values for roc-plot" if p.size==0 + + (0..p.size-2).each do |i| + ((i+1)..p.size-1).each do |j| + if c[i]<c[j] + c.swap!(i,j) + a.swap!(i,j) + p.swap!(i,j) + end + end + end + #puts c.inspect+"\n"+a.inspect+"\n"+p.inspect+"\n\n" + + perf = [] + conf = [] + + case feature_type + when "classification" + count = 0 + correct = 0 + (0..p.size-1).each do |i| + count += 1 + correct += 1 if p[i]==a[i] + if i>0 && (c[i]>=conf[-1]-0.00001) + perf.pop + conf.pop + end + perf << correct/count.to_f * 100 + conf << c[i] + end + when "regression" + count = 0 + sum_squared_error = 0 + (0..p.size-1).each do |i| + count += 1 + sum_squared_error += (p[i]-a[i])**2 + if i>0 && (c[i]>=conf[-1]-0.00001) + perf.pop + conf.pop + end + perf << Math.sqrt(sum_squared_error/count.to_f) + conf << c[i] + end + end + #puts perf.inspect + + return {:performance => perf,:confidence => conf} + end + + def self.get_tp_fp_rates(roc_values) c = roc_values[:confidence_values] diff --git a/report/report_application.rb b/report/report_application.rb index 5a47063..258daa7 100755 --- a/report/report_application.rb +++ b/report/report_application.rb @@ -82,6 +82,8 @@ get '/report/:type/:id' do report = rs.get_report(params[:type],params[:id],accept_header) format = Reports::ReportFormat.get_format(accept_header) content_type format + # default encoding is utf-8, html conversion produces iso-8859-1 encoding + content_type "text/html", 'charset' => 'ISO-8859-1' if format=="text/html" #PENDING: get_report should return file or string, check for result.is_file instead of format if format=="application/x-yaml" or format=="application/rdf+xml" report diff --git a/report/report_content.rb b/report/report_content.rb index 1345e6f..ca04f25 100755 --- a/report/report_content.rb +++ b/report/report_content.rb @@ -8,7 +8,7 @@ class Reports::ReportContent attr_accessor :xml_report, :tmp_files def initialize(title) - @xml_report = Reports::XMLReport.new(title, Time.now.strftime("Created at %m.%d.%Y - %H:%M")) + @xml_report = Reports::XMLReport.new(title, Time.now.strftime("Created at %d.%m.%Y - %H:%M")) @tmp_file_count = 0 @current_section = @xml_report.get_root_element end @@ -147,21 +147,21 @@ class Reports::ReportContent image_caption=nil) image_title = "Regression plot" unless image_title - - section_regr = @xml_report.add_section(@current_section, section_title) + #section_regr = @xml_report.add_section(@current_section, section_title) + section_regr = @current_section prediction_set = validation_set.collect{ |v| v.get_predictions } if prediction_set.size>0 section_text += "\nWARNING: regression plot information not available for all validation results" if prediction_set.size!=validation_set.size @xml_report.add_paragraph(section_regr, section_text) if section_text - plot_file_name = "regr_plot"+@tmp_file_count.to_s+".svg" + plot_file_name = "regr_plot"+@tmp_file_count.to_s+".png" @tmp_file_count += 1 begin plot_file_path = add_tmp_file(plot_file_name) Reports::PlotFactory.create_regression_plot( plot_file_path, prediction_set, name_attribute ) - @xml_report.add_imagefigure(section_regr, image_title, plot_file_name, "SVG", 120, image_caption) - rescue RuntimeError => ex + @xml_report.add_imagefigure(section_regr, image_title, plot_file_name, "PNG", 100, image_caption) + rescue Exception => ex LOGGER.error("Could not create regression plot: "+ex.message) rm_tmp_file(plot_file_name) @xml_report.add_paragraph(section_regr, "could not create regression plot: "+ex.message) @@ -178,7 +178,8 @@ class Reports::ReportContent image_titles=nil, image_captions=nil) - section_roc = @xml_report.add_section(@current_section, section_title) + #section_roc = @xml_report.add_section(@current_section, section_title) + section_roc = @current_section prediction_set = validation_set.collect{ |v| v.get_predictions && v.get_predictions.confidence_values_available? } if prediction_set.size>0 @@ -189,18 +190,18 @@ class Reports::ReportContent end @xml_report.add_paragraph(section_roc, section_text) if section_text - class_domain = validation_set.get_class_domain - class_domain.size.times do |i| - class_value = class_domain[i] + accept_values = validation_set.get_accept_values + accept_values.size.times do |i| + class_value = accept_values[i] image_title = image_titles ? image_titles[i] : "ROC Plot for class-value '"+class_value.to_s+"'" image_caption = image_captions ? image_captions[i] : nil - plot_file_name = "roc_plot"+@tmp_file_count.to_s+".svg" + plot_file_name = "roc_plot"+@tmp_file_count.to_s+".png" @tmp_file_count += 1 begin plot_file_path = add_tmp_file(plot_file_name) Reports::PlotFactory.create_roc_plot( plot_file_path, prediction_set, class_value, split_set_attribute, false )#prediction_set.size>1 ) - @xml_report.add_imagefigure(section_roc, image_title, plot_file_name, "SVG", 120, image_caption) - rescue RuntimeError => ex + @xml_report.add_imagefigure(section_roc, image_title, plot_file_name, "PNG", 100, image_caption) + rescue Exception => ex msg = "WARNING could not create roc plot for class value '"+class_value.to_s+"': "+ex.message LOGGER.error(msg) rm_tmp_file(plot_file_name) @@ -213,6 +214,49 @@ class Reports::ReportContent end + def add_confidence_plot( validation_set, + split_set_attribute = nil, + section_title="Confidence plots", + section_text=nil, + image_titles=nil, + image_captions=nil) + + #section_conf = @xml_report.add_section(@current_section, section_title) + section_conf = @current_section + prediction_set = validation_set.collect{ |v| v.get_predictions && v.get_predictions.confidence_values_available? } + + if prediction_set.size>0 + if prediction_set.size!=validation_set.size + section_text += "\nWARNING: plot information not available for all validation results" + LOGGER.error "WARNING: plot information not available for all validation results:\n"+ + "validation set size: "+validation_set.size.to_s+", prediction set size: "+prediction_set.size.to_s + end + @xml_report.add_paragraph(section_conf, section_text) if section_text + + image_title = image_titles ? image_titles[i] : "Percent Correct vs Confidence Plot" + image_caption = image_captions ? image_captions[i] : nil + plot_file_name = "conf_plot"+@tmp_file_count.to_s+".png" + @tmp_file_count += 1 + + begin + + plot_file_path = add_tmp_file(plot_file_name) + Reports::PlotFactory.create_confidence_plot( plot_file_path, prediction_set, nil, split_set_attribute, false ) + @xml_report.add_imagefigure(section_conf, image_title, plot_file_name, "PNG", 100, image_caption) + + rescue Exception => ex + msg = "WARNING could not create confidence plot: "+ex.message + LOGGER.error(msg) + rm_tmp_file(plot_file_name) + @xml_report.add_paragraph(section_conf, msg) + end + + else + @xml_report.add_paragraph(section_conf, "No prediction-confidence info for confidence plot available.") + end + + end + def add_ranking_plots( validation_set, compare_attribute, equal_attribute, @@ -236,11 +280,11 @@ class Reports::ReportContent image_titles=nil, image_captions=nil) - class_domain = validation_set.get_domain_for_attr(rank_attribute) - puts "ranking plot for "+rank_attribute.to_s+", class values: "+class_domain.to_s + accept_values = validation_set.get_class_values_for(rank_attribute) + puts "ranking plot for "+rank_attribute.to_s+", class values: "+accept_values.to_s - class_domain.size.times do |i| - class_value = class_domain[i] + accept_values.size.times do |i| + class_value = accept_values[i] if image_titles image_title = image_titles[i] else @@ -270,11 +314,11 @@ class Reports::ReportContent section_bar = @xml_report.add_section(@current_section, section_title) @xml_report.add_paragraph(section_bar, section_text) if section_text - plot_file_name = "bar_plot"+@tmp_file_count.to_s+".svg" + plot_file_name = "bar_plot"+@tmp_file_count.to_s+".png" @tmp_file_count += 1 plot_file_path = add_tmp_file(plot_file_name) Reports::PlotFactory.create_bar_plot(plot_file_path, validation_set, title_attribute, value_attributes ) - @xml_report.add_imagefigure(section_bar, image_title, plot_file_name, "SVG", 120, image_caption) + @xml_report.add_imagefigure(section_bar, image_title, plot_file_name, "PNG", 100, image_caption) end private diff --git a/report/report_factory.rb b/report/report_factory.rb index e770d2f..08d9418 100755 --- a/report/report_factory.rb +++ b/report/report_factory.rb @@ -68,15 +68,21 @@ module Reports::ReportFactory case val.feature_type when "classification" report.add_result(validation_set, [:validation_uri] + VAL_ATTR_TRAIN_TEST + VAL_ATTR_CLASS, "Results", "Results") - report.add_roc_plot(validation_set) report.add_confusion_matrix(val) + report.add_section("Plots") + report.add_roc_plot(validation_set) + report.add_confidence_plot(validation_set) + report.end_section when "regression" report.add_result(validation_set, [:validation_uri] + VAL_ATTR_TRAIN_TEST + VAL_ATTR_REGR, "Results", "Results") + report.add_section("Plots") report.add_regression_plot(validation_set, :model_uri) + report.add_confidence_plot(validation_set) + report.end_section end task.progress(90) if task - report.add_result(validation_set, Lib::ALL_PROPS, "All Results", "All Results") + report.add_result(validation_set, Validation::ALL_PROPS, "All Results", "All Results") report.add_predictions( validation_set ) task.progress(100) if task report @@ -89,7 +95,7 @@ module Reports::ReportFactory validation_set.get_values(:crossvalidation_id,false).inspect) if validation_set.unique_value(:crossvalidation_id)==nil validation_set.load_cv_attributes raise OpenTox::BadRequestError.new("num validations ("+validation_set.size.to_s+") is not equal to num folds ("+ - validation_set.unique_value(:num_folds).to_s+")") unless validation_set.unique_value(:num_folds)==validation_set.size + validation_set.unique_value(:num_folds).to_s+")") unless validation_set.unique_value(:num_folds).to_i==validation_set.size raise OpenTox::BadRequestError.new("num different folds is not equal to num validations") unless validation_set.num_different_values(:crossvalidation_fold)==validation_set.size raise OpenTox::BadRequestError.new("validations must have unique feature type, i.e. must be either all regression, "+ +"or all classification validations") unless validation_set.unique_feature_type @@ -104,19 +110,27 @@ module Reports::ReportFactory case validation_set.unique_feature_type when "classification" report.add_result(merged, [:crossvalidation_uri]+VAL_ATTR_CV+VAL_ATTR_CLASS-[:crossvalidation_fold],"Mean Results","Mean Results") - report.add_roc_plot(validation_set, nil, "ROC Plots over all folds") - report.add_roc_plot(validation_set, :crossvalidation_fold) report.add_confusion_matrix(merged.validations[0]) + report.add_section("Plots") + report.add_roc_plot(validation_set) + report.add_roc_plot(validation_set, :crossvalidation_fold) + report.add_confidence_plot(validation_set) + report.add_confidence_plot(validation_set, :crossvalidation_fold) + report.end_section report.add_result(validation_set, VAL_ATTR_CV+VAL_ATTR_CLASS-[:num_folds], "Results","Results",nil,"validation") when "regression" report.add_result(merged, [:crossvalidation_uri]+VAL_ATTR_CV+VAL_ATTR_REGR-[:crossvalidation_fold],"Mean Results","Mean Results") + report.add_section("Plots") report.add_regression_plot(validation_set, :crossvalidation_fold) + report.add_confidence_plot(validation_set) + report.add_confidence_plot(validation_set, :crossvalidation_fold) + report.end_section report.add_result(validation_set, VAL_ATTR_CV+VAL_ATTR_REGR-[:num_folds], "Results","Results") end task.progress(90) if task - report.add_result(validation_set, Lib::ALL_PROPS, "All Results", "All Results") + report.add_result(validation_set, Validation::ALL_PROPS, "All Results", "All Results") report.add_predictions( validation_set ) #, [:crossvalidation_fold] ) task.progress(100) if task report @@ -194,7 +208,25 @@ module Reports::ReportFactory end when "regression" - raise OpenTox::BadRequestError.new("algorithm comparison for regression not yet implemented") + + attributes = VAL_ATTR_CV+VAL_ATTR_REGR-[:crossvalidation_fold] + attributes = ([ :dataset_uri ] + attributes).uniq + + dataset_grouping.each do |validations| + + set = Reports::ValidationSet.create(validations) + + dataset = validations[0].dataset_uri + merged = set.merge([:algorithm_uri, :dataset_uri, :crossvalidation_id, :crossvalidation_uri]) + merged.sort(:dataset_uri) + + report.add_section("Dataset: "+dataset) + report.add_result(merged,attributes, + "Mean Results","Mean Results",nil,"crossvalidation") + report.add_paired_ttest_table(set, :algorithm_uri, :r_square) + report.end_section + end + end task.progress(100) if task report diff --git a/report/report_persistance.rb b/report/report_persistance.rb index df4930c..c85ad68 100755 --- a/report/report_persistance.rb +++ b/report/report_persistance.rb @@ -188,28 +188,29 @@ module Reports # serialize :model_uris # alias_attribute :date, :created_at - class ReportData - include DataMapper::Resource + class ReportData < Ohm::Model - property :id, Serial - property :report_type, String, :length => 255 - property :created_at, DateTime - property :validation_uris, Object - property :crossvalidation_uris, Object - property :model_uris, Object - property :algorithm_uris, Object + attribute :report_type + attribute :date + attribute :validation_uris + attribute :crossvalidation_uris + attribute :model_uris + attribute :algorithm_uris + + index :report_type + index :validation_uris + index :crossvalidation_uris attr_accessor :subjectid - after :save, :check_policy - private - def check_policy - OpenTox::Authorization.check_policy(report_uri, subjectid) + def self.create(params={}) + params[:date] = Time.new + super params end - public - def date - created_at + def save + super + OpenTox::Authorization.check_policy(report_uri, subjectid) end def report_uri @@ -241,36 +242,24 @@ module Reports def new_report(report_content, type, meta_data, uri_provider, subjectid=nil) raise "report meta data missing" unless meta_data - report = ReportData.new(meta_data) + meta_data[:report_type] = type + report = ReportData.create(meta_data) report.subjectid = subjectid - report.report_type = type - report.save + OpenTox::Authorization.check_policy(report.report_uri, subjectid) new_report_with_id(report_content, type, report.id) end def list_reports(type, filter_params={}) - filter_params["report_type"]=type unless filter_params.has_key?("report_type") - #ReportData.find_like(filter_params).delete_if{|r| r.report_type!=type}.collect{ |r| r.id } - - filter_params = Lib::DataMapperUtil.check_params(ReportData, filter_params) - # unfortunately, datamapper does not allow searching in Objects - # do filtering for list = Object params manually - list_params = {} - [:validation_uris, :crossvalidation_uris, :algorithm_uris, :model_uris].each do |l| - list_params[l] = filter_params.delete(l) if filter_params.has_key?(l) - end - - reports = ReportData.all(filter_params).delete_if{|r| r.report_type!=type} - list_params.each do |k,v| - reports = reports.delete_if{ |r| !r.send(k).include?(v) } - end + LOGGER.debug "find reports for params: "+filter_params.inspect + reports = Lib::OhmUtil.find( ReportData, filter_params ) reports.collect{ |r| r.id } end def get_report(type, id, format, force_formating, params) - report = ReportData.first({:id => id, :report_type => type}) - raise OpenTox::NotFoundError.new("Report with id='"+id.to_s+"' and type='"+type.to_s+"' not found.") unless report + report = ReportData[id] + raise OpenTox::NotFoundError.new("Report with id='"+id.to_s+"' and type='"+type.to_s+"' not found.") if + report==nil or report.report_type!=type # begin # report = ReportData.find(:first, :conditions => {:id => id, :report_type => type}) # rescue ActiveRecord::RecordNotFound @@ -294,9 +283,10 @@ module Reports # raise OpenTox::NotFoundError.new("Report with id='"+id.to_s+"' and type='"+type.to_s+"' not found.") # end # ReportData.delete(id) - report = ReportData.first({:id => id, :report_type => type}) - raise OpenTox::NotFoundError.new("Report with id='"+id.to_s+"' and type='"+type.to_s+"' not found.") unless report - report.destroy + report = ReportData[id] + raise OpenTox::NotFoundError.new("Report with id='"+id.to_s+"' and type='"+type.to_s+"' not found.") if + report==nil || report.report_type!=type + report.delete if (subjectid) begin res = OpenTox::Authorization.delete_policies_from_uri(report.report_uri, subjectid) @@ -310,9 +300,6 @@ module Reports end end -Reports::ReportData.auto_upgrade! -Reports::ReportData.raise_on_save_failure = true - #module Reports # def self.check_filter_params(model, filter_params) # prop_names = model.properties.collect{|p| p.name.to_s} diff --git a/report/report_service.rb b/report/report_service.rb index 91eefe8..722c3d6 100644 --- a/report/report_service.rb +++ b/report/report_service.rb @@ -83,6 +83,9 @@ module Reports LOGGER.debug "report persisted with id: '"+id.to_s+"'" task.progress(100) if task + #HACK - format to html right after creation, as dynamically create html may cause deadlocks + get_report(type, id, "text/html") + return get_uri(type, id) end diff --git a/report/validation_access.rb b/report/validation_access.rb index 53ecc46..e9b6e19 100755 --- a/report/validation_access.rb +++ b/report/validation_access.rb @@ -21,11 +21,11 @@ class Reports::ValidationDB # rescue => ex # raise "could not access crossvalidation with id "+validation_id.to_s+", error-msg: "+ex.message # end - cv = Lib::Crossvalidation.get( cv_id ) + cv = Validation::Crossvalidation.get( cv_id ) raise OpenTox::NotFoundError.new "crossvalidation with id "+cv_id.to_s+" not found" unless cv raise OpenTox::BadRequestError.new("crossvalidation with id '"+cv_id.to_s+"' not finished") unless cv.finished - #res += Lib::Validation.find( :all, :conditions => { :crossvalidation_id => cv_id } ).collect{|v| v.validation_uri.to_s} - res += Lib::Validation.all( :crossvalidation_id => cv_id ).collect{|v| v.validation_uri.to_s } + #res += Validation::Validation.find( :all, :conditions => { :crossvalidation_id => cv_id } ).collect{|v| v.validation_uri.to_s} + res += Validation::Validation.find( :crossvalidation_id => cv_id ).collect{|v| v.validation_uri.to_s } else res += [u.to_s] end @@ -42,16 +42,16 @@ class Reports::ValidationDB v = nil raise OpenTox::NotAuthorizedError.new "Not authorized: GET "+uri.to_s if AA_SERVER and !OpenTox::Authorization.authorized?(uri,"GET",subjectid) - v = Lib::Validation.get(validation_id) + v = Validation::Validation.get(validation_id) raise OpenTox::NotFoundError.new "validation with id "+validation_id.to_s+" not found" unless v raise OpenTox::BadRequestError.new "validation with id "+validation_id.to_s+" is not finished yet" unless v.finished - (Lib::VAL_PROPS + Lib::VAL_CV_PROPS).each do |p| + (Validation::VAL_PROPS + Validation::VAL_CV_PROPS).each do |p| validation.send("#{p.to_s}=".to_sym, v.send(p)) end - {:classification_statistics => Lib::VAL_CLASS_PROPS, - :regression_statistics => Lib::VAL_REGR_PROPS}.each do |subset_name,subset_props| + {:classification_statistics => Validation::VAL_CLASS_PROPS, + :regression_statistics => Validation::VAL_REGR_PROPS}.each do |subset_name,subset_props| subset = v.send(subset_name) subset_props.each{ |prop| validation.send("#{prop.to_s}=".to_sym, subset[prop]) } if subset end @@ -60,11 +60,11 @@ class Reports::ValidationDB def init_cv(validation) #cv = Lib::Crossvalidation.find(validation.crossvalidation_id) - cv = Lib::Crossvalidation.get(validation.crossvalidation_id) + cv = Validation::Crossvalidation.get(validation.crossvalidation_id) raise OpenTox::BadRequestError.new "no crossvalidation found with id "+validation.crossvalidation_id.to_s unless cv - Lib::CROSS_VAL_PROPS.each do |p| - validation.send("#{p.to_s}=".to_sym, cv[p]) + Validation::CROSS_VAL_PROPS.each do |p| + validation.send("#{p.to_s}=".to_sym, cv.send(p.to_s)) end end @@ -74,8 +74,13 @@ class Reports::ValidationDB validation.predicted_variable, subjectid, task) end - def get_class_domain( validation ) - OpenTox::Feature.new( validation.prediction_feature ).domain + def get_accept_values( validation, subjectid=nil ) + # PENDING So far, one has to load the whole dataset to get the accept_value from ambit + d = OpenTox::Dataset.find( validation.test_target_dataset_uri, subjectid ) + accept_values = d.features[validation.prediction_feature][OT.acceptValue] + raise "cannot get accept values from dataset "+validation.test_target_dataset_uri.to_s+" for feature "+ + validation.prediction_feature+":\n"+d.features[validation.prediction_feature].to_yaml unless accept_values!=nil + accept_values end def feature_type( validation, subjectid=nil ) diff --git a/report/validation_data.rb b/report/validation_data.rb index 15d51ec..42b179b 100755 --- a/report/validation_data.rb +++ b/report/validation_data.rb @@ -51,13 +51,13 @@ end module Reports - # = Reports::Validation + # = ReportValidation # # contains all values of a validation object # - class Validation + class ReportValidation - @@validation_access = Reports::ValidationDB.new + @@validation_access = ValidationDB.new # for overwriting validation source (other than using webservices) def self.reset_validation_access(validation_access) @@ -69,7 +69,7 @@ module Reports end # create member variables for all validation properties - @@validation_attributes = Lib::ALL_PROPS + + @@validation_attributes = Validation::ALL_PROPS + VAL_ATTR_VARIANCE.collect{ |a| (a.to_s+"_variance").to_sym } + VAL_ATTR_RANKING.collect{ |a| (a.to_s+"_ranking").to_sym } @@validation_attributes.each{ |a| attr_accessor a } @@ -85,7 +85,7 @@ module Reports # returns/creates predictions, cache to save rest-calls/computation time # # call-seq: - # get_predictions => Reports::Predictions + # get_predictions => Predictions # def get_predictions( task=nil ) if @predictions @@ -104,9 +104,9 @@ module Reports # returns the predictions feature values (i.e. the domain of the class attribute) # - def get_class_domain() - @class_domain = @@validation_access.get_class_domain(self) unless @class_domain - @class_domain + def get_accept_values() + @accept_values = @@validation_access.get_accept_values(self, @subjectid) unless @accept_values + @accept_values end # is classification/regression validation? cache to save rest-calls @@ -127,13 +127,13 @@ module Reports @@validation_access.init_cv(self) end - @@persistance = Reports::ReportService.persistance + @@persistance = ReportService.persistance def validation_report_uri #puts "searching for validation report: "+self.validation_uri.to_s return @validation_report_uri if @validation_report_uri!=nil ids = @@persistance.list_reports("validation",{:validation_uris=>validation_uri }) - @validation_report_uri = Reports::ReportService.instance.get_uri("validation",ids[-1]) if ids and ids.size>0 + @validation_report_uri = ReportService.instance.get_uri("validation",ids[-1]) if ids and ids.size>0 end def cv_report_uri @@ -142,7 +142,7 @@ module Reports raise "no cv uri "+to_yaml unless self.crossvalidation_uri ids = @@persistance.list_reports("crossvalidation",{:crossvalidation=>self.crossvalidation_uri.to_s }) #puts "-> "+ids.inspect - @cv_report_uri = Reports::ReportService.instance.get_uri("crossvalidation",ids[-1]) if ids and ids.size>0 + @cv_report_uri = ReportService.instance.get_uri("crossvalidation",ids[-1]) if ids and ids.size>0 end def clone_validation @@ -160,9 +160,9 @@ module Reports def initialize(validation_uris=nil, subjectid=nil) @unique_values = {} - validation_uris = Reports::Validation.resolve_cv_uris(validation_uris, subjectid) if validation_uris + validation_uris = ReportValidation.resolve_cv_uris(validation_uris, subjectid) if validation_uris @validations = Array.new - validation_uris.each{|u| @validations.push(Reports::Validation.new(u, subjectid))} if validation_uris + validation_uris.each{|u| @validations.push(ReportValidation.new(u, subjectid))} if validation_uris end @@ -233,7 +233,7 @@ module Reports # def get_true_prediction_feature_value # if all_classification? -# class_values = get_class_domain +# class_values = get_accept_values # if class_values.size == 2 # (0..1).each do |i| # return class_values[i] if (class_values[i].to_s.downcase == "true" || class_values[i].to_s.downcase == "active") @@ -243,21 +243,23 @@ module Reports # return nil # end - def get_class_domain( ) - return unique_value("get_class_domain") + def get_accept_values( ) + return unique_value("get_accept_values") end - def get_domain_for_attr( attribute ) - class_domain = get_class_domain() - if Lib::Validation.classification_property?(attribute) and - !Lib::Validation.depends_on_class_value?(attribute) - [ nil ] - elsif Lib::Validation.classification_property?(attribute) and - class_domain.size==2 and - Lib::Validation.complement_exists?(attribute) - [ class_domain[0] ] + def get_accept_values_for_attr( attribute ) + if !Validation::Validation.classification_property?(attribute) + [] else - class_domain + accept_values = get_accept_values() + if !Validation::Validation.depends_on_class_value?(attribute) + [ nil ] + elsif accept_values.size==2 and + Validation::Validation.complement_exists?(attribute) + [ accept_values[0] ] + else + accept_values + end end end @@ -270,10 +272,10 @@ module Reports # returns a new set with all validation that have values as specified in the map # # call-seq: - # filter(map) => Reports::ValidationSet + # filter(map) => ValidationSet # def filter(map) - new_set = Reports::ValidationSet.new + new_set = ValidationSet.new validations.each{ |v| new_set.validations.push(v) if v.has_values?(map) } return new_set end @@ -282,10 +284,10 @@ module Reports # e.g. create set with predictions: collect{ |validation| validation.get_predictions!=null } # # call-seq: - # filter_proc(proc) => Reports::ValidationSet + # filter_proc(proc) => ValidationSet # def collect - new_set = Reports::ValidationSet.new + new_set = ValidationSet.new validations.each{ |v| new_set.validations.push(v) if yield(v) } return new_set end @@ -298,10 +300,10 @@ module Reports #puts col_values.inspect # get domain for classification attribute, i.e. ["true","false"] - class_domain = get_domain_for_attr(attribute_val) + accept_values = get_accept_values_for_attr(attribute_val) # or the attribute has a complementary value, i.e. true_positive_rate # -> domain is reduced to one class value - first_value_elem = (class_domain.size==1 && class_domain[0]!=nil) + first_value_elem = (accept_values.size==1 && accept_values[0]!=nil) cell_values = {} row_values.each do |row| @@ -311,7 +313,7 @@ module Reports if v.send(attribute_row)==row and v.send(attribute_col)==col raise "two validation have equal row and column values"if val!=nil val = v.send(attribute_val) - val = val[class_domain[0]] if first_value_elem + val = val[accept_values[0]] if first_value_elem val = val.to_nice_s end end @@ -357,13 +359,13 @@ module Reports else attribute_not_nil[index] = true if remove_nil_attributes - class_domain = get_domain_for_attr(a) + accept_values = get_accept_values_for_attr(a) # get domain for classification attribute, i.e. ["true","false"] - if class_domain.size==1 && class_domain[0]!=nil + if accept_values.size==1 && accept_values[0]!=nil # or the attribute has a complementary value, i.e. true_positive_rate # -> domain is reduced to one class value raise "illegal state, value for "+a.to_s+" is no hash: '"+val.to_s+"'" unless (val.is_a?(Hash)) - val = val[class_domain[0]] + val = val[accept_values[0]] end if variance @@ -398,19 +400,19 @@ module Reports # to_array(attributes) => array # def merge(equal_attributes) - new_set = Reports::ValidationSet.new + new_set = ValidationSet.new # unique values stay unique when merging # derive unique values before, because model dependent props cannot be accessed later (when mergin validations from different models) new_set.unique_values = @unique_values #compute grouping - grouping = Reports::Util.group(@validations, equal_attributes) + grouping = Util.group(@validations, equal_attributes) #puts "groups "+grouping.size.to_s - Lib::MergeObjects.register_merge_attributes( Reports::Validation, - Lib::VAL_MERGE_AVG,Lib::VAL_MERGE_SUM,Lib::VAL_MERGE_GENERAL) unless - Lib::MergeObjects.merge_attributes_registered?(Reports::Validation) + Lib::MergeObjects.register_merge_attributes( ReportValidation, + Validation::VAL_MERGE_AVG,Validation::VAL_MERGE_SUM,Validation::VAL_MERGE_GENERAL) unless + Lib::MergeObjects.merge_attributes_registered?(ReportValidation) #merge grouping.each do |g| @@ -438,12 +440,12 @@ module Reports def compute_ranking(equal_attributes, ranking_attribute, class_value=nil ) #puts "compute_ranking("+equal_attributes.inspect+", "+ranking_attribute.inspect+", "+class_value.to_s+" )" - new_set = Reports::ValidationSet.new + new_set = ValidationSet.new (0..@validations.size-1).each do |i| new_set.validations.push(@validations[i].clone_validation) end - grouping = Reports::Util.group(new_set.validations, equal_attributes) + grouping = Util.group(new_set.validations, equal_attributes) grouping.each do |group| # put indices and ranking values for current group into hash diff --git a/report/xml_report.rb b/report/xml_report.rb index 4b9a11a..4fbfae3 100755 --- a/report/xml_report.rb +++ b/report/xml_report.rb @@ -184,7 +184,7 @@ module Reports row = Element.new("row") r.each do |v| entry = Element.new("entry") - if auto_link_urls && v.to_s =~ /depict/ || v.to_s =~ /image$/ #PENDING + if auto_link_urls && v.to_s =~ /depict/ || v.to_s =~ /image\/png$/ #PENDING add_image(entry, v.to_s) elsif auto_link_urls && v.to_s =~ /^http(s?):\/\// add_url(entry, v.to_s, v.to_s) |