diff options
author | Christoph Helma <helma@in-silico.ch> | 2015-08-27 20:25:16 +0200 |
---|---|---|
committer | Christoph Helma <helma@in-silico.ch> | 2015-08-27 20:25:16 +0200 |
commit | 7dcae58f3af869b4c58e6091cee099acff113ad2 (patch) | |
tree | 1c9d16803d26ae663539a1721a63e4999b941323 /views | |
parent | 46166d66c458eb9d922f0c6c4958654a761a7529 (diff) |
Initial GUI for Nestec models
Diffstat (limited to 'views')
-rw-r--r-- | views/neighbors.haml | 150 | ||||
-rw-r--r-- | views/predict.haml | 111 | ||||
-rw-r--r-- | views/prediction.haml | 127 |
3 files changed, 112 insertions, 276 deletions
diff --git a/views/neighbors.haml b/views/neighbors.haml index 22dff56..9f60e7c 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -4,110 +4,74 @@ / display preordered in table view ; %div.results{:style=>"display:none"} - - count_m = 0 %h3 Neighbors: / tabs div #tabs %ul.nav.nav-tabs.nav-justified{:id=>"neighborTabs", :role=>"tablist"} / each model a tab head ; - - @prediction_models.each do |m| - - count_m += 1 - - m_title = m.title.split("_").last(2)[0] + - @models.each_with_index do |model,i| %li - %a{:href => "#results_#{count_m}", :id => "linkTab#{count_m}", data: {toggle:"tab"}} - = m_title - - count_rs = 0 + %a{:href => "#results_#{i+1}", :id => "linkTab#{i+1}", data: {toggle:"tab"}} + = "#{model.endpoint} (#{model.species})" %div.tab-content / unpack to single arrays - - @predictions.each do |pa| + - @predictions.each_with_index do |prediction,j| / pass model type for significant fragments view - - @type = @model_type[count_rs] - - count_rs += 1 - #results.tab-pane.fade{:id=>"#{count_rs}"} - - pa.each do |p| - / prepare dataset for neighbors table ; - / delete first array which contains prediction ; - / following arrays are the neighbor predictions ; - - @model_uri = p.metadata[RDF::OT.hasSource][0] - - p.data_entries.shift - - p.compounds.shift - - / call the tablesorter plugin ; - / presort by similarity ; - :javascript - $(document).ready(function(){ - $("table##{count_rs}").tablesorter({ - debug: false, - //table: 'ui-widget ui-widget-content ui-corner-all', - //header: 'ui-widget-header ui-corner-all ui-state-default', - theme: "bootstrap", - //widthFixed: true, - //hover: 'ui-state-hover', - //even: 'ui-widget-content', - //odd: 'ui-state-default', - headerTemplate: '{content} {icon}', - widgets: ['zebra', 'columns', 'uitheme'], - headers: {0: {sorter: false}, 3: {sorter: false}}, - sortList: [[2,1]] - }); + #results.tab-pane.fade{:id=>"#{j+1}"} + / prepare dataset for neighbors table ; + / delete first array which contains prediction ; + / following arrays are the neighbor predictions ; + / call the tablesorter plugin ; + / presort by similarity ; + :javascript + $(document).ready(function(){ + $("table##{j+1}").tablesorter({ + debug: false, + theme: "bootstrap", + headerTemplate: '{content} {icon}', + widgets: ['zebra', 'columns', 'uitheme'], + headers: {0: {sorter: false}, 3: {sorter: false}}, + sortList: [[2,1]] }); - - $logger.debug "neighbors compounds:\t#{p.data_entries[0]}\n" - - if p.data_entries[0][2] != nil && p.data_entries[0].size != 3 - -#%h2= "Neighbors: " - - %div.table-responsive - %table.tablesorter{:id=>"#{count_rs}", :style=>"border-style: solid;"} - %thead - %tr - %th{:style =>"vertical-align:middle;"} - Compound - %th{:style =>"vertical-align:middle;"} - Measured Activity - %th{:style =>"vertical-align:middle;"} - Similarity - %th{:style =>"vertical-align:middle;"} - Supporting Information - %info - %tr - %td - %td{:style=>"font-size:x-small;padding:0px;"} - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Measured Activity", data: {toggle:"popover", placement:"auto", html:"true", content:"Experimental result(s) from the training dataset."}, :style=>"z-index:auto+10;"} - %td{:style=>"font-size:x-small;padding:0px;"} - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Similarity", data: {toggle:"popover", placement:"auto", html:"true", content:"LAZAR calculates activity specific similarities based on the presence of statistically significant fragments. This procedure will <ul><li>consider only those parts of a chemical structure that are relevant for a particular endpoint</li><li>ignore inert parts of the structure</li><li>lead to different similarities, depending on the toxic endpoint Similarities of 1 may be encountered even for structurally dissimilar compounds, because inert parts are ignored.</li></ul>"}, :style=>"z-index:auto+10;"} - %tbody - - count = 0 - - p.compounds.each do |neighbor_compound| - / prevent conversion of nil - - c = p.data_entries[count][2] != nil ? p.data_entries[count][2] : '' - - case c - - when /(false|true|inactive|active)/i - - c = c - - else - /- c = Array.new - - c = p.data_entries[count][2].to_f.round(3) - %tr - %td{:style =>"vertical-align:middle;padding-left:1em;"} - %a.btn.btn-link{:href => "#details#{count_rs}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(neighbor_compound.uri)}/details"), :id=>"link#{count_rs}#{count}"}} - %img.blind{:src=>"#{neighbor_compound.uri}/image", :alt=>"no image", :onError=>"this.onerror=null;", :title=>"#{neighbor_compound.smiles}", :width=>"150px"} - %td{:style =>"vertical-align:middle;padding-left:1em;"} - - if c.class == String - = c - - else - = c - %td{:style =>"vertical-align:middle;padding-left:1em;"} - = p.data_entries[count][3] != nil ? p.data_entries[count][3].round(3) : "Not enough similar compounds in training dataset." - %td{:style =>"vertical-align:middle;padding-left:1em;"} - - if @type =~ /classification/i - - if p.data_entries[count][3] != nil - %a.btn.btn-default{:href => "#details#{count_rs}", :id=>"link#{count_rs}#{count}sf", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@type}/#{CGI.escape(neighbor_compound.uri)}/significant_fragments")}} Significant Fragments - - if @type =~ /regression/i - - if p.data_entries[count][3] != nil - %a.btn.btn-default{:href => "#details#{count_rs}", :id=>"link#{count_rs}#{count}sf", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@type}/#{CGI.escape(neighbor_compound.uri)}/significant_fragments")}} Descriptors - - count += 1 - - else - %span.btn.btn-default.disabled Not enough similar compounds in training dataset + }); + - if prediction[:neighbors].size > 0 + + %div.table-responsive + %table.tablesorter{:id=>"#{j+1}", :style=>"border-style: solid;"} + %thead + %tr + %th{:style =>"vertical-align:middle;"} + Compound + %th{:style =>"vertical-align:middle;"} + Measured Activity + %th{:style =>"vertical-align:middle;"} + Similarity + / %th{:style =>"vertical-align:middle;"} + / Supporting Information + %info + %tr + %td + %td{:style=>"font-size:x-small;padding:0px;"} + %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Measured Activity", data: {toggle:"popover", placement:"auto", html:"true", content:"Experimental result(s) from the training dataset."}, :style=>"z-index:auto+10;"} + %td{:style=>"font-size:x-small;padding:0px;"} + %a.btn.glyphicon.glyphicon-info-sign{:href=>"#neighbors", :title=>"Similarity", data: {toggle:"popover", placement:"auto", html:"true", content:"LAZAR calculates activity specific similarities based on the presence of statistically significant fragments. This procedure will <ul><li>consider only those parts of a chemical structure that are relevant for a particular endpoint</li><li>ignore inert parts of the structure</li><li>lead to different similarities, depending on the toxic endpoint Similarities of 1 may be encountered even for structurally dissimilar compounds, because inert parts are ignored.</li></ul>"}, :style=>"z-index:auto+10;"} + / %td + %tbody + - prediction[:neighbors].each_with_index do |neighbor,count| + %tr + %td{:style =>"vertical-align:middle;padding-left:1em;"} + %a.btn.btn-link{:href => "#details#{j+1}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(neighbor[0].to_s)}/details"), :id=>"link#{j+1}#{count}"}} + = Compound.find(neighbor[0]).svg + %td{:style =>"vertical-align:middle;padding-left:1em;"} + = neighbor[2].collect{|n| '%.2e' % n}.join ", " + %td{:style =>"vertical-align:middle;padding-left:1em;"} + / TODO differentiate between no neighbors found and compound found in dataset, display neighbors for compounds in dataset? + = neighbor[1] != nil ? neighbor[1] : "Not enough similar compounds in training dataset." - %div.modal.fade{:id=>"details#{count_rs}", :role=>"dialog"} + - else + %span.btn.btn-default.disabled Not enough similar compounds in training dataset + + %div.modal.fade{:id=>"details#{j+1}", :role=>"dialog"} %div.modal-dialog.modal-lg %div.modal-content diff --git a/views/predict.haml b/views/predict.haml index bd430a6..118c4d4 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -1,35 +1,6 @@ %link{ :href=>"/jsme/jsa.css", :rel=>"stylesheet"} %script{:src=>"/jsme/jsme.nocache.js"} :javascript - function callTask(url) { - var result=""; - $.ajax({ - url: url, - async: false, - success:function(data) { - var response = data.match(/Completed\s.*\./)[0]; - var arr = response.split(" "); - result = arr[1].replace(/"/g, ""); - } - }); - return result; - }; - // form function - function progress($element, url) { - $element.width("2%"); - $element.show(); - var timer = setInterval(function(){ - var percent = callTask(url); - if(percent == 100.0){ - var next = percent; - clearInterval(timer); - } - else { - var next = percent; - } - $element.width(next+"%"); - }, 3000); - }; function checksmiles () { if (document.form.identifier.value == "") { alert("Please draw or insert a chemical structure."); @@ -48,7 +19,6 @@ }); if (checked == false){ alert("Please select an endpoint."); - $('.progress-bar').hide(); return false; }; return true; @@ -67,8 +37,6 @@ }; // init task for progress -- task_uri = OpenTox::Task.task_uri -- OpenTox::Task.run("Predict compound.", "#{$lazar[:uri]}", task_uri)do;end // whole site content needs to be in one form. Input and checkboxes are proofed by js functions. %form{:name => "form", :action => to('/predict'), :method => "post", :enctype => "multipart/form-data", :onsubmit => "return !!(checksmiles() & checkboxes())" } @@ -102,74 +70,14 @@ }); #models - - @detail_count = 0 - @endpoints.each do |endpoint| %div - %b= endpoint[0].split("#").last.gsub("_", " ").gsub(/\"|\]/, "")+" :" - - @models.each do |model| - - if endpoint == model.type.select{|e| e =~ /Endpoint/} - - model_title = model.title.split("_").last(2)[0] - - model_t = model.title.gsub("_", " ") - - @detail_count +=1 - %div{:id => model_title} - %input{:type => "checkbox", :name => "selection[#{model.uri}]", :id => "selection[#{model_title}]", :value => true, :disabled => false} - %label{:for => "selection[#{model_title}]"} - = model_t - %a.btn.btn-default.btn-xs{:href=>"#details", :id => "linkDetails#{model_title}", :title=>"#{model_title} details", :style=>"font-size:small;"} - Details | Validation - - :javascript - $("a#linkDetails#{model_title}").click(function () { - $("#details_#{@detail_count}").toggle(); - //document.location = document.location + "#" + "details"; - }); - #details{:id => "#{@detail_count}", :style => "display:none;"} - %div.panel{:style=>"padding:0.5em;"} - %div.row - %div.col-md-6 - %h3 Model Details: - %p - Algorithm: LAZAR - - model.type.to_s =~ /regression/i ? type = "regression" : type = "classification" - - @model_type = type - %p - = "Type: "+type - - training_dataset = OpenTox::Dataset.new "#{model[RDF::OT.trainingDataset]}" - - training_compounds = training_dataset.compounds.size.to_s - %p - Training compounds: - = training_compounds - %p - Descriptors: - - if type == "regression" - %a{:href=>"https://services.in-silico.ch/algorithm/descriptor/physchem/list", :title=>"link opens in new window.", :target=>"_blank"} Physico-chemical (PC) properties - - else - %a{:href=>"http://www.maunz.de/libfminer2-bbrc-doc/", :title=>"link opens in new window.", :target=>"_blank"} Fminer backbone refinement classes - %p - Model: - %a.btn{:href=>"#{to("/predict/#{CGI.escape(model.uri)}")}", :title=>"download"} - rdf - %span.glyphicon.glyphicon-download-alt - %p - Feature Dataset: - %a.btn{:href=>"#{to("/predict/#{CGI.escape(model[RDF::OT.featureDataset])}")}", :title=>"download"} - rdf - %span.glyphicon.glyphicon-download-alt - -#%a{:href=>"#{to("/predict/#{CGI.escape(model[RDF::OT.featureDataset])}")}/sdf", :title=>"download"} sdf - %p - Training Dataset: - %a.btn{:href=>"#{to("/predict/#{CGI.escape(model[RDF::OT.trainingDataset])}")}", :title=>"link opens in new window."} - rdf - %span.glyphicon.glyphicon-download-alt - -#%a{:href=>"#{to("/predict/#{CGI.escape(model[RDF::OT.trainingDataset])}/sdf")}", :title=>"link opens in new window."} sdf - - unless model.metadata[RDF::OT.crossValidation].nil? - %div.col-md-6 - %h3 Validation: - %a.btn.btn-info.btn-xs{:href => "#{model.metadata[RDF::OT.crossValidation][0]}", :title=>"link opens in new window.", :target=>"_blank"} - Detailed report link - %p - - @cv = OpenTox::Validation.find "#{model.metadata[RDF::OT.crossValidation][0]+"/statistics"}" - = haml :validation, :layout => false, :validation => @cv, :model_type => @model_type + %b= endpoint + - @models.select{|m| m.endpoint == endpoint}.each do |model| + %div{:id => model.id} + %input{:type => "checkbox", :name => "selection[#{model.id}]", :id => "selection[#{model.id}]", :value => true, :disabled => false} + %label{:for => "selection[#{model.id}]"} + = model.species %p @@ -179,9 +87,4 @@ %h2 3. Predict %div.col-md-10 - %input.btn.btn-warning.h2{ :type => "submit", :id => "submit", :value=>">>", :onclick => "(progress($('.progress-bar'),'#{task_uri}') & getsmiles())"} - %input{:type => "hidden", :name => "task_uri", :value => "#{task_uri}"} - %div.row - %div.col-md-12 - %div.progress - %div.progress-bar.progress-bar-striped.active{:role=>"progressbar", aria: { valuemin: 0, valuemax: 100}, :style=>"width:0;"} + %input.btn.btn-warning.h2{ :type => "submit", :id => "submit", :value=>">>", :onclick => "getsmiles()"} diff --git a/views/prediction.haml b/views/prediction.haml index dfc11fc..91f7024 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -18,89 +18,58 @@ %tbody %tr %td{:id=>"compound", :style=>"vertical-align:top;"} - %a.btn.btn-link{:href => "#detailsTop", :id=>"linkCompound", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@compound.uri)}/details")}} - %img.img-responsive{:src=>"#{@compound.uri}/image", :alt=>"no image", :title=>"#{@compound.smiles}", :width=>"150", :height=>"150"} - - count=0 - - @predictions.each do |pa| - / unpack to single array/prediction - / if p.data_entries array[0].size == 3 -> database hit - / change 'result' if database hit - / change 'confidence' if database hit - - pa.each do |p| - / prevent conversion of nil - /- $logger.debug "data entries in prediction array:\t#{p.data_entries}\n" - - database_hit = 0 - - if p.data_entries[0].size == 3 - - database_hit = 1 - - c = p.data_entries[0][0] != nil ? p.data_entries[0][0] : '' - - case c - - when /(false|true|inactive|active)/i - - c = c - - else - /- c = Array.new - - c = (p.data_entries[0][0].class == Float) ? p.data_entries[0][0].round(3) : (p.data_entries[0][0] != nil ? p.data_entries[0][0] : "no prediction") - %td{:style=>"vertical-align:top;"} - %b{:class => "title"} - = @prediction_models[count].title.gsub("_", " ") - - @model_uri = @prediction_models[count].uri + %a.btn.btn-link{:href => "#detailsTop", :id=>"linkCompound", data: { toggle: "modal", remote: to("/prediction/#{@compound.id.to_s}/details")}} + / %img.img-responsive{:src=>"#{@compound.id}/image", :alt=>"no image", :title=>"#{@compound.smiles}", :width=>"150", :height=>"150"} + = @compound.svg + - @predictions.each_with_index do |prediction,i| + %td{:style=>"vertical-align:top;"} + %b{:class => "title"} + = "#{@models[i].endpoint.gsub('_', ' ')} (#{@models[i].species})" + %p + - if prediction[:confidence] == "measured" + %p + / TODO fix scientific notation from database + %b Measured activity: + = prediction[:value].numeric? ? "#{prediction[:value].round(3)} (#{@models[i].unit})" : prediction[:value] + %p Compound is part of the training dataset + - elsif prediction[:neighbors].size > 0 %p / model type (classification|regression) %b Type: - = @model_type[count] + = @models[i].model.class.to_s.match("Classification") ? "Classification" : "Regression" + %br + %b Prediction: + / TODO scientific notation + = prediction[:value].numeric? ? "#{'%.2e' % prediction[:value]} #{@models[i].unit}" : prediction[:value] + / TODO update description + %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction", data: {toggle:"popover", placement:"left", html:"true", content:"LAZAR calculates searches the training dataset for similar compounds (neighbors) and calculates the prediction from their measured activities. LAZAR calculates predictions using <ul><li>a majority vote (weighted by compound similarity) for<br /><b>classification</b> (<a href='http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract', target='_blank'>original publication</a>) </li><li>a local QSAR model based on neighbors for<br /><b>regression</b> (<a href='http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract', target='_blank'</h>original publication</a>) </li></ul>Please keep in mind that predictions are based on the measured activities of neighbors."}} + %br + / TODO probability + %b Confidence: + = prediction[:confidence].round(3) + %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Confidence", data: {toggle:"popover", placement:"left", html:"true", content:"Indicates the applicability domain of a model. Predictions with a high confidence can be expected to be more reliable than predictions with low confidence. Confidence values may take any value between 0 and 1. For most models confidence > 0.025 is a sensible (hard) cutoff to distinguish between reliable and unreliable predictions."}} + %p + /TODO add tooltip for significant ftagments and descriptors + / - if @model_type[i] =~ /classification/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0) + / Significant fragments: + / %a.btn.btn-default.btn-sm{:id=>"linkSigFragments", :href => "#detailsTop", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[i]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Significant fragments + / - if @model_type[i] =~ /regression/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0) + / Descriptors + / %a.btn.btn-default.btn-sm{:id=>"linkDescriptors", :href => "#detailsTop", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[i]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Descriptors + / %p + %a.btn.btn-default.btn-sm{:href=> "#tabs", :id=>"link#{i+1}"} + Neighbors + :javascript + $("a#link#{i}").click(function () { + $(".results").show(); + //document.getElementById('tabs').focus(); + $('#neighborTabs a[href="#results_#{i+1}"]').tab('show'); + //$("#tabs").tabs({ active: "#{i}" }); + }); + %p + - else %p - - unless database_hit > 0 - %b Result: - %b - - if c.class == String - - result = (c != '' ? c : "No prediction result.") - = result - - else - - result = (c != '' ? c.round(3) : "No prediction result.") - = result - - confidence = (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0) ? p.data_entries[0][1].round(2) : "--" - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Result", data: {toggle:"popover", placement:"left", html:"true", content:"LAZAR calculates searches the training dataset for similar compounds (neighbors) and calculates the prediction from their measured activities. LAZAR calculates predictions using <ul><li>a majority vote (weighted by compound similarity) for<br /><b>classification</b> (<a href='http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract', target='_blank'>original publication</a>) </li><li>a local QSAR model based on neighbors for<br /><b>regression</b> (<a href='http://www.frontiersin.org/Journal/10.3389/fphar.2013.00038/abstract', target='_blank'</h>original publication</a>) </li></ul>Please keep in mind that predictions are based on the measured activities of neighbors."}} - - @cv = OpenTox::Validation.find @prediction_models[count].metadata[RDF::OT.crossValidation][0]+"/statistics" #unless @prediction_models[count].title.include?("Mutagenicity") - - unless @model_type[count] == "regression" - %br - %b - = "Probability: " - - unless result == "No prediction result." or confidence == "--" - - prob = @cv.probabilities( confidence, result )[:probs][result]*100 - = "#{prob.round(1)} %" - %p - %b Confidence: - = confidence - %a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Confidence", data: {toggle:"popover", placement:"left", html:"true", content:"Indicates the applicability domain of a model. Predictions with a high confidence can be expected to be more reliable than predictions with low confidence. Confidence values may take any value between 0 and 1. For most models confidence > 0.025 is a sensible (hard) cutoff to distinguish between reliable and unreliable predictions."}} - %p - /TODO add tooltip for significant ftagments and descriptors - - if @model_type[count] =~ /classification/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0) - / Significant fragments: - %a.btn.btn-default.btn-sm{:id=>"linkSigFragments", :href => "#detailsTop", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[count]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Significant fragments - - if @model_type[count] =~ /regression/i && (p.data_entries[0][1] != nil && p.data_entries[0][1] != 0.0) - / Descriptors - %a.btn.btn-default.btn-sm{:id=>"linkDescriptors", :href => "#detailsTop", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@model_uri)}/#{@model_type[count]}/#{CGI.escape(@compound.uri)}/fingerprints")}} Descriptors - %p - - if c != '' - %a.btn.btn-default.btn-sm{:href=> "#tabs", :id=>"link#{count}"} - Neighbors - :javascript - $("a#link#{count}").click(function () { - $(".results").show(); - //document.getElementById('tabs').focus(); - $('#neighborTabs a[href="#results_#{count+1}"]').tab('show'); - //$("#tabs").tabs({ active: "#{count}" }); - }); - %p - - count+=1 - - else # database hit - %b Database hit: - %br Compound found in training dataset - %p - %b Measured activity: - = p.data_entries[0][2] - %p - - - count+=1 + Not enough similar compounds in training dataset. / always show the neighbors table, message is given there = haml :neighbors, :layout => false, :model_type => @model_type |