summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgebele <gebele@in-silico.ch>2017-11-06 11:21:18 +0000
committergebele <gebele@in-silico.ch>2017-11-06 11:21:18 +0000
commitb7e1a4bb8b8e47326928171044c0d7b54d62e278 (patch)
treed9b8bb742cd359f300d20965816333cd527aa155
parent2d19e8a294b0c95a4b49d963f383b9b9b3918ea0 (diff)
added prediction objects;re-ordered code and cleanup
-rw-r--r--application.rb188
-rw-r--r--helper.rb2
-rw-r--r--prediction.rb30
-rw-r--r--task.rb188
-rw-r--r--views/batch.haml389
-rw-r--r--views/task.haml130
6 files changed, 173 insertions, 754 deletions
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 = "<td><table class=\"table\">"
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<response['measurements'].length; i++){
- var value = document.createTextNode(response['measurements'][i]);
- var br = document.createElement("br");
- p.appendChild(value);
- p.appendChild(br);
- };
- };
- // Consensus prediction
- var h3 = document.createElement("h5");
- var t = document.createTextNode("Consensus prediction:");
- if (response['sa_prediction']['prediction'] == false){
- var value = document.createTextNode("non-mutagenic");
- };
- if (response['sa_prediction']['prediction'] == true){
- var value = document.createTextNode("mutagenic");
- };
- h3.appendChild(t);
- p.appendChild(h3);
- p.appendChild(value);
- // Consensus confidence
- var h4 = document.createElement("h5");
- var t = document.createTextNode("Consensus confidence:");
- var value = document.createTextNode(response['confidence']);
- h4.appendChild(t);
- p.appendChild(h4);
- p.appendChild(value);
- // Structural alerts for mutagenicity
- var h5 = document.createElement("h5");
- var t = document.createTextNode("Structural alerts for mutagenicity:");
- h5.appendChild(t);
- p.appendChild(h5);
- if (response['sa_matches'] != false){
- var value = document.createTextNode(response['sa_matches']);
- p.appendChild(value);
- } else {
- var span = document.createElement("span");
- var value = document.createTextNode("none");
- span.style.fontStyle = "italic";
- span.appendChild(value);
- p.appendChild(span);
- };
-
- // append to td
- td.appendChild(p);
- };
-
- // proceed to general structure
- for (val of a){
- var p = document.createElement("p");
- var h = document.createElement("h5");
- p.id = val;
- if (val == "title") {
- var value = document.createTextNode(response['model_name']);
- h.appendChild(value);
- p.appendChild(h);
- } else if (val == "db_hit" && response['db_hit'] != false && response['sa_prediction'] == false) {
- var value = document.createTextNode(response['db_hit']);
- p.appendChild(value);
- } else if (val == "measurements" && response['measurements'] != false) {
- var t = document.createTextNode("Measurements:");
- h.appendChild(t);
- p.appendChild(h);
- if (response['model_type'] == "Regression"){
- for (var i=0; i<response['measurements'].length; i++){
- var value = document.createTextNode(response['measurements'][i]);
- var br = document.createElement("br");
- p.appendChild(value);
- p.appendChild(br);
- if (response['converted_measurements'] != false) {
- var value = document.createTextNode(response['converted_measurements'][i]);
- var br = document.createElement("br");
- p.appendChild(value);
- p.appendChild(br);
- if (i+1 != response['measurements'].length){
- var br2 = document.createElement("br");
- p.appendChild(br2);
- };
- };
- };
- } else if (response['model_type'] == "Classification"){
- for (var i=0; i<response['measurements'].length; i++){
- var value = document.createTextNode(response['measurements'][i]);
- var br = document.createElement("br");
- p.appendChild(value);
- p.appendChild(br);
- };
- };
- } else if (val == "prediction" && response['prediction_value'] != false) {
- var t = document.createTextNode("Prediction:");
- var value = document.createTextNode(response['prediction_value']+" "+response['model_unit']);
- h.appendChild(t);
- p.appendChild(h);
- p.appendChild(value);
- if (response['converted_value'] != false) {
- var br = document.createElement("br");
- var value = document.createTextNode(response['converted_value']+" "+response['converted_model_unit']);
- p.appendChild(br);
- p.appendChild(value);
- };
- if (response['model_type'] == "Classification" && response['probability'] != false){
- var h = document.createElement("h5");
- var t = document.createTextNode("Probability:");
- h.appendChild(t);
- p.appendChild(h);
- for (var i=0; i<response['probability'].length; i++){
- var value = document.createTextNode(response['probability'][i]);
- var br = document.createElement("br");
- p.appendChild(value);
- p.appendChild(br);
- };
- };
- } else if (val == "interval" && response['interval'] != false) {
- var t = document.createTextNode("95% Prediction interval:");
- var value = document.createTextNode(response['interval']+" "+response['model_unit']);
- h.appendChild(t);
- p.appendChild(h);
- p.appendChild(value);
- if (response['converted_interval'] != false) {
- var br = document.createElement("br");
- var value = document.createTextNode(response['converted_interval']+" "+response['converted_model_unit']);
- p.appendChild(br);
- p.appendChild(value);
- };
- } else if (val == "warnings" && response['warnings'] != false && response['db_hit'] == false) {
- var t = document.createTextNode("Warnings: ");
- h.appendChild(t);
- p.appendChild(h);
- for (var i=0; i<response['warnings'].length; i++){
- var value = document.createTextNode(response['warnings'][i]);
- var br = document.createElement("br");
- p.appendChild(value);
- p.appendChild(br);
- };
- } else if (val == "info" && response['info'] != false) {
- var t = document.createTextNode("Info: ");
- var value = document.createTextNode(response['info']);
- h.appendChild(t);
- p.appendChild(h);
- p.appendChild(value);
- };
-
- // append to td
- td.appendChild(p);
- };
- };// if model != Cramer
- if (model == "Cramer"){
- for(i=0; i < response['tds'].length; i++){
- progress('Cramer',i,response['tds'].length);
- var td = document.getElementById(response['tds'][i]);
- var p = document.createElement("p");
- var h = document.createElement("h5");
- var t = document.createTextNode("Oral toxicity (Cramer rules)");
- p.id = "cramer";
- h.appendChild(t);
- p.appendChild(h);
- var h2 = document.createElement("h5");
- var t = document.createTextNode("Cramer rules:");
- h2.appendChild(t);
- p.appendChild(h2);
- if (response['cramer_rules'][i] != "nil"){
- var value = document.createTextNode(response['cramer_rules'][i]);
- p.appendChild(value);
- } else {
- var span = document.createElement("span");
- var value = document.createTextNode("none");
- span.style.fontStyle = "italic";
- span.appendChild(value);
- p.appendChild(span);
- };
- var h3 = document.createElement("h5");
- var t = document.createTextNode("Cramer rules, with extensions:");
- h3.appendChild(t);
- p.appendChild(h3);
- if (response['cramer_rules_extensions'][i] != "nil"){
- var value = document.createTextNode(response['cramer_rules_extensions'][i]);
- p.appendChild(value);
- } else {
- var span = document.createElement("span");
- var value = document.createTextNode("none");
- span.style.fontStyle = "italic";
- span.appendChild(value);
- p.appendChild(span);
- };
-
- // append to td
- td.appendChild(p);
- if (i === response['tds'].length-1) {
- $("img#circle_Cramer").hide();
- $("a#downbutton_Cramer").show();
- };
-
- };
- };// if model == Cramer
- // if last compound change progress to download;
- if (last == true) {
- $("img#circle_"+model).hide();
- $("a#downbutton_"+model).show();
+ progress(response['percent'],id);
+ if (response['percent'] == 100){
+ window.clearInterval(markers[id]);
+ $("a#downbutton_"+id).removeClass("disabled");
+ $("a#detailsbutton_"+id).removeClass("disabled");
};
});
};
-
-
+ function simpleTemplating(data) {
+ var html = '<ul class=pagination>';
+ $.each(data, function(index, item){
+ html += '<li>'+ item +'</li>'+'</br>';
+ });
+ html += '</ul>';
+ 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 = '<ul class=pagination>';
- $.each(data, function(index, item){
- html += '<li>'+ item +'</li>'+'</br>';
- });
- html += '</ul>';
- 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}