From b7e1a4bb8b8e47326928171044c0d7b54d62e278 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 6 Nov 2017 11:21:18 +0000 Subject: added prediction objects;re-ordered code and cleanup --- application.rb | 188 ++++----------------------- helper.rb | 2 - prediction.rb | 30 +++++ task.rb | 188 +++++---------------------- views/batch.haml | 389 +++++++++++++------------------------------------------ views/task.haml | 130 ------------------- 6 files changed, 173 insertions(+), 754 deletions(-) create mode 100644 prediction.rb delete mode 100644 views/task.haml diff --git a/application.rb b/application.rb index e4b9e38..0957d71 100644 --- a/application.rb +++ b/application.rb @@ -1,3 +1,6 @@ +require_relative 'task.rb' +require_relative 'prediction.rb' +require_relative 'helper.rb' include OpenTox configure :production do @@ -23,171 +26,15 @@ error do haml :error end -helpers do - def embedded_svg image, options={} - doc = Nokogiri::HTML::DocumentFragment.parse image - svg = doc.at_css 'svg' - title = doc.at_css 'title' - if options[:class].present? - svg['class'] = options[:class] - end - if options[:title].present? - title.children.remove - text_node = Nokogiri::XML::Text.new(options[:title], doc) - title.add_child(text_node) - end - doc.to_html.html_safe - end - - def to_csv(m,predictions,compounds) - model = (m != "Cramer" ? Model::Validation.find(m.to_s) : "Cramer") - csv = "" - if model == "Cramer" - compounds = compounds.collect{|c| c.smiles} - - prediction = [Toxtree.predict(compounds, "Cramer rules"), Toxtree.predict(compounds, "Cramer rules with extensions")] - output = {} - output["model_name"] = "Oral toxicity (Cramer rules)" - output["model_type"] = false - output["model_unit"] = false - ["measurements", "converted_measurements", "prediction_value", "converted_value", "interval", "converted_interval", "probability", "db_hit", "warnings", "info", "toxtree", "sa_prediction", "sa_matches", "confidence"].each do |key| - output["#{key}"] = false - end - output["toxtree"] = true - output["cramer_rules"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules"]}}.flatten.compact - output["cramer_rules_extensions"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules, with extensions"]}}.flatten.compact - - # header - csv = "ID,Endpoint,Unique SMILES,Cramer rules,Cramer rules with extensions\n" - - compounds.each_with_index do |smiles, idx| - csv << "#{idx+1},#{output["model_name"]},#{smiles},"\ - "#{output["cramer_rules"][idx] != "nil" ? output["cramer_rules"][idx] : "none" },"\ - "#{output["cramer_rules_extensions"][idx] != "nil" ? output["cramer_rules_extensions"][idx] : "none"}\n" - end - - else - output = {} - predictions.each_with_index do |prediction,idx| - compound = compounds[idx] - line = "" - output["model_name"] = "#{model.endpoint.gsub('_', ' ')} (#{model.species})" - output["model_type"] = model.model.class.to_s.match("Classification") ? type = "Classification" : type = "Regression" - output["model_unit"] = (type == "Regression") ? "(#{model.unit})" : "" - output["converted_model_unit"] = (type == "Regression") ? "#{model.unit =~ /\b(mmol\/L)\b/ ? "(mg/L)" : "(mg/kg_bw/day)"}" : "" - ["measurements", "converted_measurements", "prediction_value", "converted_value", "interval", "converted_interval", "probability", "db_hit", "warnings", "info", "toxtree", "sa_prediction", "sa_matches", "confidence"].each do |key| - output["#{key}"] = false - end - - if prediction[:value] - inApp = (prediction[:warnings].join(" ") =~ /Cannot/ ? "no" : (prediction[:warnings].join(" ") =~ /may|Insufficient/ ? "maybe" : "yes")) - if prediction[:info] =~ /\b(identical)\b/i - prediction[:info] = "This compound was part of the training dataset. All information "\ - "from this compound was removed from the training data before the "\ - "prediction, to obtain unbiased results." - end - note = "\"#{prediction[:warnings].uniq.join(" ")}\"" - - output["prediction_value"] = (type == "Regression") ? "#{prediction[:value].delog10.signif(3)}" : "#{prediction[:value]}" - output["converted_value"] = "#{compound.mmol_to_mg(prediction[:value].delog10).signif(3)}" if type == "Regression" - - output["db_hit"] = prediction[:info] if prediction[:info] - - if prediction[:measurements].is_a?(Array) - output["measurements"] = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10.signif(3)} (#{model.unit})"} : prediction[:measurements].collect{|value| "#{value}"} - output["converted_measurements"] = (type == "Regression") ? prediction[:measurements].collect{|value| "#{compound.mmol_to_mg(value.delog10).signif(3)} #{model.unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"} : false - else - output["measurements"] = (type == "Regression") ? "#{prediction[:measurements].delog10.signif(3)} (#{model.unit})}" : "#{prediction[:measurements]}" - output["converted_measurements"] = (type == "Regression") ? "#{compound.mmol_to_mg(prediction[:measurements].delog10).signif(3)} #{(model.unit =~ /\b(mmol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : false - - end #db_hit - - if type == "Regression" - - if !prediction[:prediction_interval].nil? - interval = prediction[:prediction_interval] - output['interval'] = "#{interval[1].delog10.signif(3)} - #{interval[0].delog10.signif(3)}" - output['converted_interval'] = "#{compound.mmol_to_mg(interval[1].delog10).signif(3)} - #{compound.mmol_to_mg(interval[0].delog10).signif(3)}" - end #prediction interval - - line += "#{idx+1},#{output['model_name']},#{compound.smiles},"\ - "\"#{prediction[:info] ? prediction[:info] : "no"}\",\"#{prediction[:measurements].join("; ") if prediction[:info]}\","\ - "#{output['prediction_value'] != false ? output['prediction_value'] : ""},"\ - "#{output['converted_value'] != false ? output['converted_value'] : ""},"\ - "#{output['interval'].split(" - ").first.strip unless output['interval'] == false},"\ - "#{output['interval'].split(" - ").last.strip unless output['interval'] == false},"\ - "#{output['converted_interval'].split(" - ").first.strip unless output['converted_interval'] == false},"\ - "#{output['converted_interval'].split(" - ").last.strip unless output['converted_interval'] == false},"\ - "#{inApp},#{note.nil? ? "" : note.chomp}\n" - else # Classification - - # consensus mutagenicity - sa_prediction = KaziusAlerts.predict(compound.smiles) - lazar_mutagenicity = prediction - confidence = 0 - lazar_mutagenicity_val = (lazar_mutagenicity[:value] == "non-mutagenic" ? false : true) - if sa_prediction[:prediction] == false && lazar_mutagenicity_val == false - confidence = 0.85 - elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == true - confidence = 0.85 * ( 1 - sa_prediction[:error_product] ) - elsif sa_prediction[:prediction] == false && lazar_mutagenicity_val == true - confidence = 0.11 - elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == false - confidence = ( 1 - sa_prediction[:error_product] ) - 0.57 - end - output['sa_prediction'] = sa_prediction - output['sa_matches'] = sa_prediction[:matches].collect{|a| a.first}.join("; ") unless sa_prediction[:matches].blank? - output['confidence'] = confidence.signif(3) - output['model_name'] = "Lazar #{model.endpoint.gsub('_', ' ').downcase} (#{model.species}):" - output['probability'] = prediction[:probabilities] ? prediction[:probabilities].collect{|k,v| "#{k}: #{v.signif(3)}"} : false - - line += "#{idx+1},Consensus mutagenicity,#{compound.smiles},"\ - "\"#{prediction[:info] ? prediction[:info] : "no"}\",\"#{prediction[:measurements].join("; ") if prediction[:info]}\","\ - "#{sa_prediction[:prediction] == false ? "non-mutagenic" : "mutagenic"},"\ - "#{output['confidence']},#{output['sa_matches'] != false ? "\"#{output['sa_matches']}\"" : "none"},"\ - "#{output['prediction_value']},"\ - "#{output['probability'][0] != false ? output['probability'][0].split(":").last : ""},"\ - "#{output['probability'][1] != false ? output['probability'][1].split(":").last : ""},"\ - "#{inApp},#{note.nil? ? "" : note}\n" - - end - - output["warnings"] = prediction[:warnings] if prediction[:warnings] - - else #no prediction value - inApp = "no" - if prediction[:info] =~ /\b(identical)\b/i - prediction[:info] = "This compound was part of the training dataset. All information "\ - "from this compound was removed from the training data before the "\ - "prediction, to obtain unbiased results." - end - note = "\"#{prediction[:warnings].join(" ")}\"" - - output["warnings"] = prediction[:warnings] - output["info"] = prediction[:info] if prediction[:info] - - if type == "Regression" - line += "#{idx+1},#{output['model_name']},#{compound.smiles},#{prediction[:info] ? prediction[:info] : "no"},"\ - "#{prediction[:measurements] if prediction[:info]},,,,,,,"+ [inApp,note].join(",")+"\n" - else - line += "#{idx+1},Consensus mutagenicity,#{compound.smiles},#{prediction[:info] ? prediction[:info] : "no"},"\ - "#{prediction[:measurements] if prediction[:info]},,,,,,,"+ [inApp,note].join(",")+"\n" - end - - end - csv += line - end - csv - end - end - -end - get '/?' do redirect to('/predict') end get '/predict/?' do + if params[:tpid] && !params[:tpid].blank? + pid = params[:tpid].to_i + Process.kill(9,pid) #if (Process.getpgid(pid) rescue nil).present? + end @models = Model::Validation.all @models = @models.delete_if{|m| m.model.name =~ /\b(Net cell association)\b/} @endpoints = @models.collect{|m| m.endpoint}.sort.uniq @@ -222,7 +69,6 @@ get '/task/?' do string = "" prediction = task.predictions[params[:model]][pageNumber.to_i] sorter = [] - $logger.debug prediction if prediction[:info] sorter << {"Info" => prediction[:info]} if prediction[:measurements_string].kind_of?(Array) @@ -357,7 +203,18 @@ post '/predict/?' do counter = 1 predictions = [] @compounds.each do |compound| - prediction = m.predict(compound) + if Prediction.where(compound: compound.id, model: m.id).exists? + $logger.debug "prediction already exists !" + prediction = Prediction.find_by(compound: compound.id, model: m.id).prediction + else + prediction = m.predict(compound) + # save prediction object + prediction_object = Prediction.new + prediction_object[:compound] = compound.id + prediction_object[:model] = m.id + prediction_object[:prediction] = prediction + prediction_object.save + end if type == "Classification"# consensus mutagenicity sa_prediction = KaziusAlerts.predict(compound.smiles) lazar_mutagenicity = prediction @@ -421,9 +278,6 @@ post '/predict/?' do "#{output["cramer_rules"][idx] != "nil" ? output["cramer_rules"][idx] : "none" },"\ "#{output["cramer_rules_extensions"][idx] != "nil" ? output["cramer_rules_extensions"][idx] : "none"}\n" end - #predictions = [] - #predictions << {"Cramer rules" => output["cramer_rules"]} - #predictions << {"Cramer rules, with extensions" => output["cramer_rules_extensions"]} predictions = {} predictions["Cramer rules"] = output["cramer_rules"].collect{|rule| rule != "nil" ? rule : "none"} predictions["Cramer rules, with extensions"] = output["cramer_rules_extensions"].collect{|rule| rule != "nil" ? rule : "none"} @@ -442,9 +296,11 @@ post '/predict/?' do end#models end#main task + @pid = task.pid + $logger.debug "application pid: #{@pid}" File.delete File.join("tmp", params[:fileselect][:filename]) - return haml :task + return haml :batch end # single compound prediction diff --git a/helper.rb b/helper.rb index 8837161..12a6ce2 100644 --- a/helper.rb +++ b/helper.rb @@ -97,7 +97,6 @@ helpers do else # Classification # consensus mutagenicity - sa_prediction = KaziusAlerts.predict(compound.smiles) lazar_mutagenicity = prediction confidence = 0 @@ -153,7 +152,6 @@ helpers do end csv += line end - $logger.debug csv csv end end diff --git a/prediction.rb b/prediction.rb new file mode 100644 index 0000000..4e46d52 --- /dev/null +++ b/prediction.rb @@ -0,0 +1,30 @@ +module OpenTox + + class Prediction + + include OpenTox + include Mongoid::Document + include Mongoid::Timestamps + store_in collection: "predictions" + field :compound, type: BSON::ObjectId + field :model, type: BSON::ObjectId + field :prediction, type: Hash, default:{} + + attr_accessor :compound, :model, :prediction + + def compound + self[:compound] + end + + def model + self[:model] + end + + def prediction + self[:prediction] + end + + end + +end + diff --git a/task.rb b/task.rb index 295e580..9b9ca26 100644 --- a/task.rb +++ b/task.rb @@ -1,177 +1,53 @@ DEFAULT_TASK_MAX_DURATION = 36000 + module OpenTox - # Class for handling asynchronous tasks class Task - attr_accessor :pid, :observer_pid + include OpenTox + include Mongoid::Document + include Mongoid::Timestamps + store_in collection: "tasks" + field :pid, type: Integer + field :percent, type: Float, default: 0 + field :predictions, type: Hash, default:{} + field :csv, type: String - def metadata - super true # always update metadata - end + attr_accessor :pid, :percent, :predictions, :csv - def self.task_uri - Task.new.uri - end - - def self.run(description, creator=nil, uri=nil) - - task = Task.new uri - #task[RDF::OT.created_at] = DateTime.now - #task[RDF::OT.hasStatus] = "Running" - #task[RDF::DC.description] = description.to_s - #task[RDF::DC.creator] = creator.to_s - #task[RDF::OT.percentageCompleted] = "0" - #task.put - pid = fork do - begin - #task.completed yield - rescue => e - # wrap non-opentox-errors first - #e = OpenTox::Error.new(500,e.message,nil,e.backtrace) unless e.is_a?(OpenTox::Error) - #$logger.error "error in task #{task.uri} created by #{creator}" # creator is not logged because error is logged when thrown - #RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => e.to_ntriples},{:content_type => 'text/plain'}) - #task.kill - end - end - Process.detach(pid) - #task.pid = pid - - # watch if task has been cancelled - #observer_pid = fork do - # task.wait - # begin - # Process.kill(9,task.pid) if task.cancelled? - # rescue - # $logger.warn "Could not kill process of task #{task.uri}, pid: #{task.pid}" - # end - #end - #Process.detach(observer_pid) - #task.observer_pid = observer_pid - #task - pid - - end - - def kill - Process.kill(9,@pid) - Process.kill(9,@observer_pid) - rescue # no need to raise an exception if processes are not running - end - - def description - self.[](RDF::DC.description) - end - - def creator - self.[](RDF::DC.creator) + def pid + self[:pid] end - def cancel - kill - self.[]=(RDF::OT.hasStatus, "Cancelled") - self.[]=(RDF::OT.finished_at, DateTime.now) - put - end - - def completed(uri) - self.[]=(RDF::OT.resultURI, uri) - self.[]=(RDF::OT.hasStatus, "Completed") - self.[]=(RDF::OT.finished_at, DateTime.now) - self.[]=(RDF::OT.percentageCompleted, "100") - put - end - - # waits for a task, unless time exceeds or state is no longer running - def wait - start_time = Time.new - due_to_time = start_time + DEFAULT_TASK_MAX_DURATION - dur = 0.2 - while running? - sleep dur - dur = [[(Time.new - start_time)/20.0,0.3].max,300.0].min - request_timeout_error "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time) - end + def percent + self[:percent] end - - end - - def code - RestClientWrapper.get(@uri).code.to_i - end - - # get only header for status requests - def running? - code == 202 - end - - def cancelled? - code == 503 - end - - def completed? - code == 200 - end - - def error? - code >= 400 and code != 503 - end - - [:hasStatus, :resultURI, :created_at, :finished_at, :percentageCompleted].each do |method| - define_method method do - response = self.[](RDF::OT[method]) - response = self.[](RDF::OT1[method]) unless response # API 1.1 compatibility - response + + def predictions + self[:predictions] end - end - - # Check status of a task - # @return [String] Status - def status - self[RDF::OT.hasStatus] - end - def error_report - get - report = {} - query = RDF::Query.new({ - :report => { - RDF.type => RDF::OT.ErrorReport, - :property => :value, - } - }) - query.execute(@rdf).each do |solution| - report[solution.property] = solution.value.to_s + def csv + self[:csv] end - report - end - - #TODO: subtasks (only for progress in validation) - class SubTask - def initialize(task, min, max) - #TODO add subtask code + def update_percent(percent) + self[:percent] = percent + save end - def self.create(task, min, max) - if task - SubTask.new(task, min, max) - else - nil + def self.run + task = Task.new #uri + pid = fork do + yield end + Process.detach(pid) + task[:pid] = pid + task.save + task end - - def waiting_for(task_uri) - #TODO add subtask code - end - - def progress(pct) - #TODO add subtask code - end - - def running?() - #TODO add subtask code - end + end end + diff --git a/views/batch.haml b/views/batch.haml index fccd88c..2fb5966 100644 --- a/views/batch.haml +++ b/views/batch.haml @@ -1,14 +1,14 @@ :javascript - function progress(model,idx,total) { - var p = 100/total; - var percent = Math.round((idx+1)*p); - var bar = document.getElementById("bar_"+model); - var prog = document.getElementById("progress_"+model); - bar.style.width = percent + '%'; + + function progress(value,id) { + var percent = Math.round(value); + var bar = document.getElementById("bar_"+id); + var prog = document.getElementById("progress_"+id); + bar.style.width = value + '%'; if (percent == 100){ prog.style.display = "none"; }; - } + }; var HttpClient = function() { this.get = function(aUrl, aCallback) { @@ -22,248 +22,66 @@ } }; - function renderResponse(model,idx,compound,last,total,tmppath) { - // create request - if (model == "Cramer"){ - var dataset = '#{@dataset.id}'; - var uri = "#{to("/batch/")}" + model + '/?dataset=' + escape(dataset) + '&tmppath=' + tmppath; - } else { - var dataset = '#{@dataset.id}'; - var uri = "#{to("/batch/")}" + model + '/?compound=' + escape(compound) + '&dataset=' + dataset + '&idx=' + idx + '&tmppath=' + tmppath; - }; + var markers = []; + + function renderTask(task_id,model_id,id) { + var uri = "#{to("/")}" + 'task/?turi=' + task_id; var aClient = new HttpClient(); aClient.get(uri, function(res) { - // progress bar function - progress(model,idx,total); - var response = JSON.parse(res); - var td = document.getElementById("prediction_"+compound+'_'+model+'_'+idx); - //td.innerHTML = ""; - if (model != "Cramer"){ - // init general structure - a = ["title", "type", "db_hit", "measurements", "prediction", "interval", "probability", "warnings", "info"]; - - // handles consesus mutagenicity - if (response['sa_prediction'] != false){ - var p = document.createElement("p"); - var h = document.createElement("h5"); - p.id = "sa"; - // Consensus mutagenicity - var t = document.createTextNode("Consensus mutagenicity"); - h.appendChild(t); - p.appendChild(h); - // handle db_hit first - if (response['db_hit'] != false){ - var value = document.createTextNode(response['db_hit']); - p.appendChild(value); - var h2 = document.createElement("h5"); - var t = document.createTextNode("Measurements:"); - h2.appendChild(t); - p.appendChild(h2); - for (var i=0; i'+'
'; + }); + html += ''; + return html; + }; + function pagePredictions(task_id,model_id,id){ + button = document.getElementById("detailsbutton_"+id); + span = button.childNodes[1]; + if (span.className == "glyphicon glyphicon-menu-right"){ + span.className = "glyphicon glyphicon-menu-down"; + $('#data-container_'+id).show(); + $('#pager_'+id).show(); + $('#pager_'+id).pagination({ + dataSource: '#{to("/")}' + 'task/?predictions=' + task_id + '&model=' + model_id , + locator: 'predictions', + totalNumber: #{@compounds.size}, + pageSize: 1, + showPageNumbers: true, + showGoInput: true, + formatGoInput: 'go to <%= input %>', + formatAjaxError: function(jqXHR, textStatus, errorThrown) { + $('#data-container_'+id).html(errorThrown); + }, + /*ajax: { + beforeSend: function() { + $('#data-container_'+id).html('Loading content ...'); + } + },*/ + callback: function(data, pagination) { + var html = simpleTemplating(data); + $('#data-container_'+id).html(html); + $('#data-container_'+id).css("min-height", $(window).height() + "px" ); + } + }); + } else if (span.className = "glyphicon glyphicon-menu-down"){ + span.className = "glyphicon glyphicon-menu-right"; + $('#data-container_'+id).hide(); + $('#pager_'+id).hide(); + }; + }; %div.well - %a.btn.btn-warning{:href => to('/predict')} + %a.btn.btn-warning{:href => to("/predict?tpid=#{@pid}")} %span.glyphicon.glyphicon-menu-left{:aria=>{:hidden=>"true"}} New Prediction @@ -274,63 +92,34 @@ %h3 Batch Prediction Results: %div.col-md-8 %h3= @filename - - / displays prediction result in table tabs - #tabs - %ul.nav.nav-tabs.nav-justified{:id=>"batchTabs", :role=>"tablist"} - - @models.each_with_index do |model,i| - - m = Model::Validation.find model unless model == "Cramer" - %li{:class => ("active" if i == 0)} - %a{:href => "#results_#{i+1}", :id => "linkTab#{i+1}", data: {toggle:"tab"}} - = (model == "Cramer") ? "Oral toxicity (Cramer rules)" : "#{m.endpoint} (#{m.species})" - %img.dlwait{:src=>"/images/wait30trans.gif", :id=>"circle_#{model}", :class=>"circle", :alt=>"wait", :style=>"display:none;"} - %a.csv.btn{:id => "downbutton_#{model}", :href=>"#{to("/predict/#{@tmppaths[model]}/#{model}/#{@filename}")}", :title=>"download", :style=>"display:none;"} + + + - @models.each_with_index do |model,idx| + - m = Model::Validation.find model unless model == "Cramer" + - task = @tasks[idx].id + - predictions = @tasks[idx].predictions["#{model}"] + #result.panel{:id=>idx} + %div.row + %div.col-md-6 + %h5= (model == "Cramer") ? "Oral toxicity (Cramer rules)" : (m.endpoint =~ /Mutagenicity/i ? "Consensus mutagenicity" : "#{m.endpoint} (#{m.species})") + #pager{:id=>idx} + %div.col-md-6.h5 + %a.btn.btn-default.btn-xs.disabled{:id => "detailsbutton_#{idx}", :data=>{:toggle=>"collapse"}, :href=>"javascript:void(0)", :onclick=>"pagePredictions('#{task}','#{model}','#{idx}')", :style=>"font-size:small;"} + %span.glyphicon.glyphicon-menu-right + Details + %a.btn.btn-default.btn-xs.disabled{:id => "downbutton_#{idx}", :href=>"#{to("/predict/csv/#{task}/#{model}/#{@filename}")}", :title=>"download", :style=>"font-size:small;"} %span.glyphicon.glyphicon-download-alt CSV - - %div.tab-content - - csize = @compounds.size - - msize = @models.size - - timer = 0 - - @models.each_with_index do |model,j| - #results.tab-pane{:id=>"#{j+1}", :class => ("active" if j == 0)} - %div{:id=>"progress_"+model, :style=>"width:100%;height:2px;position:relative;background-color:#ccc;"} - %div{:id=>"bar_"+model, :style=>"background-color: #4CAF50;width:10px;height:2px;position:absolute;"} - %table.table.table-bordered - %tbody - - @compounds.each_with_index do |compound,cidx| - - timer += 800 - :javascript - $(document).ready(function() { - $("img.circle").show(); - var model = '#{model}', - msize = #{msize}, - idx = #{j+1}, - last = false, - compound = '#{compound.id}', - csize = #{csize}, - cidx = #{cidx}, - timer = #{timer}, - tmppath = '#{@tmppaths[model]}'; - // check for last request; - if (cidx+1 == csize) { - last = true; - }; - setTimeout(function(){ - if (model != "Cramer"){ - renderResponse(model,cidx,compound,last,csize,tmppath); - } else if (model == "Cramer" && cidx == 0){ - renderResponse(model,cidx,compound,last,csize,tmppath); - }; - }, timer ); - }); - // table layout: - // one row per prediction; - // first col compound; sec col results - %tr{:id=>model} - // compound - %td.col-md-6{:id=>"compound"} - %p=embedded_svg(compound.svg, title: compound.smiles) - %p=compound.smiles - // prediction values from js function - %td.col-md-6{:id=>"prediction_#{compound.id}_#{model}_#{cidx}", :style => "vertical-align:top;"} + %div{:id=>"progress_#{idx}", :style=>"width:100%;height:3px;position:relative;background-color:#ccc;"} + %div{:id=>"bar_#{idx}", :style=>"background-color: #4CAF50;width:10px;height:3px;position:absolute;"} + - # increase interval timer for large datasets + - ctimer = ((@compounds.size/1000) == 0 ? 1000 : ((@compounds.size/1000)*1000)) + :javascript + var timer = #{ctimer}; + $(document).ready(function(){ + markers[#{idx}] = setInterval(function(){ + renderTask('#{task}','#{model}',#{idx}); + }, timer ); + }); + #data-container{:id=>idx,:style=>"width:100%;"} + -#pager{:id=>idx} diff --git a/views/task.haml b/views/task.haml deleted file mode 100644 index 6d87416..0000000 --- a/views/task.haml +++ /dev/null @@ -1,130 +0,0 @@ -:javascript - - function progress(value,id) { - var percent = Math.round(value); - var bar = document.getElementById("bar_"+id); - var prog = document.getElementById("progress_"+id); - bar.style.width = value + '%'; - if (percent == 100){ - prog.style.display = "none"; - }; - } - - var HttpClient = function() { - this.get = function(aUrl, aCallback) { - var anHttpRequest = new XMLHttpRequest(); - anHttpRequest.onreadystatechange = function() { - if (anHttpRequest.readyState == 4 && anHttpRequest.status == 200) - aCallback(anHttpRequest.responseText); - } - anHttpRequest.open( "GET", aUrl, true ); - anHttpRequest.send( null ); - } - }; - - var markers = []; - - function renderTask(task_id,model_id,id) { - var uri = "#{to("/")}" + 'task/?turi=' + task_id; - var aClient = new HttpClient(); - aClient.get(uri, function(res) { - var response = JSON.parse(res); - progress(response['percent'],id); - if (response['percent'] == 100){ - window.clearInterval(markers[id]); - $("a#downbutton_"+id).removeClass("disabled"); - $("a#detailsbutton_"+id).removeClass("disabled"); - //pagePredictions(task_id,model_id,id); - }; - }); - }; - function simpleTemplating(data) { - var html = ''; - return html; - }; - function pagePredictions(task_id,model_id,id){ - //var compounds = #{@compounds_ids}; - //console.log(compounds[id]); - //var compound = compounds[id]; - button = document.getElementById("detailsbutton_"+id); - span = button.childNodes[1]; - if (span.className == "glyphicon glyphicon-menu-right"){ - span.className = "glyphicon glyphicon-menu-down"; - $('#data-container_'+id).show(); - $('#pager_'+id).show(); - $('#pager_'+id).pagination({ - dataSource: '#{to("/")}' + 'task/?predictions=' + task_id + '&model=' + model_id , - locator: 'predictions', - totalNumber: #{@compounds.size}, - pageSize: 1, - showPageNumbers: true, - showGoInput: true, - formatGoInput: 'go to <%= input %>', - formatAjaxError: function(jqXHR, textStatus, errorThrown) { - $('#data-container_'+id).html(errorThrown); - }, - /*ajax: { - beforeSend: function() { - $('#data-container_'+id).html('Loading content ...'); - } - },*/ - callback: function(data, pagination) { - var html = simpleTemplating(data); - $('#data-container_'+id).html(html); - $('#data-container_'+id).css("min-height", $(window).height() + "px" ); - //$('#data-container_'+id).height(500); - } - }); - } else if (span.className = "glyphicon glyphicon-menu-down"){ - span.className = "glyphicon glyphicon-menu-right"; - $('#data-container_'+id).hide(); - $('#pager_'+id).hide(); - }; - }; -%div.well - %a.btn.btn-warning{:href => to('/predict')} - %span.glyphicon.glyphicon-menu-left{:aria=>{:hidden=>"true"}} - New Prediction - - / show file name - %topline - %div.row - %div.col-md-4 - %h3 Batch Prediction Results: - %div.col-md-8 - %h3= @filename - - - - @models.each_with_index do |model,idx| - - m = Model::Validation.find model unless model == "Cramer" - - task = @tasks[idx].id - - predictions = @tasks[idx].predictions["#{model}"] - #result.panel{:id=>idx} - %div.row - %div.col-md-6 - %h5= (model == "Cramer") ? "Oral toxicity (Cramer rules)" : (m.endpoint =~ /Mutagenicity/i ? "Consensus mutagenicity" : "#{m.endpoint} (#{m.species})") - #pager{:id=>idx} - %div.col-md-6.h5 - %a.btn.btn-default.btn-xs.disabled{:id => "detailsbutton_#{idx}", :data=>{:toggle=>"collapse"}, :href=>"javascript:void(0)", :onclick=>"pagePredictions('#{task}','#{model}','#{idx}')", :style=>"font-size:small;"} - %span.glyphicon.glyphicon-menu-right - Details - %a.btn.btn-default.btn-xs.disabled{:id => "downbutton_#{idx}", :href=>"#{to("/predict/csv/#{task}/#{model}/#{@filename}")}", :title=>"download", :style=>"font-size:small;"} - %span.glyphicon.glyphicon-download-alt - CSV - %div{:id=>"progress_#{idx}", :style=>"width:100%;height:3px;position:relative;background-color:#ccc;"} - %div{:id=>"bar_#{idx}", :style=>"background-color: #4CAF50;width:10px;height:3px;position:absolute;"} - - # increase interval timer for large datasets - - ctimer = ((@compounds.size/1000) == 0 ? 1000 : ((@compounds.size/1000)*1000)) - :javascript - var timer = #{ctimer}; - $(document).ready(function(){ - markers[#{idx}] = setInterval(function(){ - renderTask('#{task}','#{model}',#{idx}); - }, timer ); - }); - #data-container{:id=>idx,:style=>"width:100%;"} - -#pager{:id=>idx} -- cgit v1.2.3