From 55bf06381a42c9bb1e1e991e990f5d6e90c8e33e Mon Sep 17 00:00:00 2001 From: gebele Date: Wed, 7 Dec 2016 12:07:13 +0000 Subject: rebuild code for public release;prepared to work with lazar v1.0.0;reintroduced compound details --- VERSION | 2 +- application.rb | 27 ++++++- config.ru | 2 +- helper.rb | 215 -------------------------------------------------- views/details.haml | 6 +- views/layout.haml | 37 ++++++++- views/neighbors.haml | 4 +- views/predict.haml | 12 +-- views/prediction.haml | 22 +++--- 9 files changed, 82 insertions(+), 245 deletions(-) diff --git a/VERSION b/VERSION index ec63514..9084fa2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -9 +1.1.0 diff --git a/application.rb b/application.rb index eefd833..4eb4a36 100644 --- a/application.rb +++ b/application.rb @@ -24,19 +24,33 @@ get '/?' do end get '/predict/?' do - @models = OpenTox::Model::Prediction.all + @models = OpenTox::Model::Validation.all @models = @models.delete_if{|m| m.model.name =~ /\b(Net cell association)\b/} @endpoints = @models.collect{|m| m.endpoint}.sort.uniq @models.count <= 0 ? (haml :info) : (haml :predict) end get '/predict/modeldetails/:model' do - model = OpenTox::Model::Prediction.find params[:model] + model = OpenTox::Model::Validation.find params[:model] crossvalidations = OpenTox::Validation::RepeatedCrossValidation.find(model.repeated_crossvalidation_id).crossvalidations return haml :model_details, :layout=> false, :locals => {:model => model, :crossvalidations => crossvalidations} end +# get individual compound details +get '/prediction/:neighbor/details/?' do + @compound = OpenTox::Compound.find params[:neighbor] + @smiles = @compound.smiles + begin + @names = @compound.names.nil? ? "No names for this compound available." : @compound.names + rescue + @names = "No names for this compound available." + end + @inchi = @compound.inchi.gsub("InChI=", "") + + haml :details, :layout => false +end + get '/jme_help/?' do File.read(File.join('views','jme_help.html')) end @@ -121,7 +135,7 @@ post '/predict/?' do @compounds.each do |compound| @batch[compound] = [] params[:selection].keys.each do |model_id| - model = Model::Prediction.find model_id + model = OpenTox::Model::Validation.find model_id prediction = model.predict(compound) @batch[compound] << [model, prediction] end @@ -148,7 +162,7 @@ post '/predict/?' do @models = [] @predictions = [] params[:selection].keys.each do |model_id| - model = Model::Prediction.find model_id + model = OpenTox::Model::Validation.find model_id @models << model @predictions << model.predict(@compound) end @@ -156,6 +170,11 @@ post '/predict/?' do end end +get '/license' do + @license = RDiscount.new(File.read("LICENSE.md")).to_html + haml :license, :layout => false +end + get '/style.css' do headers 'Content-Type' => 'text/css; charset=utf-8' scss :style diff --git a/config.ru b/config.ru index 8f9daf5..ad609be 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,4 @@ -ENV["LAZAR_ENV"] = "production" +ENV["LAZAR_ENV"] = "development"#"production" require 'bundler' Bundler.require require File.expand_path './application.rb' diff --git a/helper.rb b/helper.rb index caa1923..54dbd5e 100644 --- a/helper.rb +++ b/helper.rb @@ -1,218 +1,3 @@ helpers do - - def is_authorized(uri, action) - if OpenTox::Authorization.server && session[:subjectid] != nil - return OpenTox::Authorization.authorized?(uri, action, session[:subjectid]) - else - return true - end - return false - end - - def is_aluist - OpenTox::Authorization.list_user_groups(session[:username], session[:subjectid]).include?("aluist") - end - - def hide_link(destination) - @link_id = 0 unless @link_id - @link_id += 1 - haml :js_link, :locals => {:name => "hide", :destination => destination, :method => "hide"}, :layout => false - end - - def toggle_link(destination,name) - @link_id = 0 unless @link_id - @link_id += 1 - haml :js_link, :locals => {:name => name, :destination => destination, :method => "toggle"}, :layout => false - end - - def sort(descriptors,value_map) - features = {:activating => [], :deactivating => [], :pc_features => []} - if descriptors.kind_of?(Array) - descriptors.each do |d| - if !value_map.empty? - features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 2 - features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 1 - else - if d[OT.effect] =~ TRUE_REGEXP - features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} - elsif d[OT.effect] =~ FALSE_REGEXP - features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} - end - end - end - else - descriptors.each do |d,v| - features[:pc_features] << {:feature => d, :value => v} - end - end - features - end - - def compound_image(compound,descriptors,value_map) - haml :compound_image, :locals => {:compound => compound, :features => sort(descriptors,value_map)}, :layout => false - end - def activity_markup(activity,value_map) - if value_map and !value_map.empty? - if value_map.size == 2 - activity = value_map.index(activity) if value_map.has_value? activity - if activity.to_i == 2 - haml ".active #{value_map[activity]}", :layout => false - elsif activity.to_i == 1 - haml ".inactive #{value_map[activity]}", :layout => false - else - haml ".other #{activity.to_s}", :layout => false - end - else - haml ".other #{activity.to_s}", :layout => false - end - elsif OpenTox::Algorithm::numeric? activity - haml ".other #{sprintf('%.03g', activity.to_f)}", :layout => false - else - haml ".other #{activity.to_s}", :layout => false - end -=begin - case activity.class.to_s - when /Float/ - haml ".other #{sprintf('%.03g', activity)}", :layout => false - when /String/ - case activity - when "true" - haml ".active active", :layout => false - when "false" - haml ".inactive inactive", :layout => false - else - haml ".other #{activity.to_s}", :layout => false - end - else - if activity #true - haml ".active active", :layout => false - elsif !activity # false - haml ".inactive inactive", :layout => false - else - haml ".other #{activity.to_s}", :layout => false - end - end -=end - end - - def neighbors_navigation - @page = 0 unless @page - haml :neighbors_navigation, :layout => false - end - - def models_navigation - @page = 0 unless @page - haml :models_navigation, :layout => false - end - - def models_navigation_bottom - @page = 0 unless @page - haml :models_navigation_bottom, :layout => false - end - - def endpoint_option_list(max_time=3600) - out = "" - tmpfile = File.join(TMP_DIR, 'endpoint_option_list') - if File.exists? tmpfile - if Time.now-File.mtime(tmpfile) <= max_time - f = File.open(tmpfile, 'r+') - f.each{|line| out << line} - return out - else - File.unlink(tmpfile) - end - end - result = endpoint_selection() - if result.lines.count > 3 - f = File.new(tmpfile,'w') - f.print result - f.close - end - result - end - - def endpoint_level(endpoint="Endpoints", level=1) - results = OpenTox::Ontology::Echa.echa_endpoints(endpoint) rescue results = [] - out = "" - out += "\n" if results.size > 0 - return out - end - - def endpoint_selection() - out = " \n -
\n" - out += "Please select:\n" - out += endpoint_level - js = "" - out += "
\n" - return out - end - - def logmmol_to_mg(value ,mw) - mg = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4) - return mg - end - - def logmg_to_mg(value) - mg = round_to(10**round_to(value.to_f, 2),4) - return mg - end - - def ptd50_to_td50(value ,mw) - td50 = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4) - return td50 - end - - def round_to(value, deci) - rounded = (value.to_f*(10**deci)).round / (10**deci).to_f - return rounded - end - - def calc_mw(compound_uri) - ds = OpenTox::Dataset.new() - ds.save(@subjectid) - ds.add_compound(compound_uri) - ds.save(@subjectid) - mw_algorithm_uri = File.join(CONFIG[:services]["opentox-algorithm"],"pc/MW") - mw_uri = OpenTox::RestClientWrapper.post(mw_algorithm_uri, {:dataset_uri=>ds.uri}) - ds.delete(@subjectid) - mw_ds = OpenTox::Dataset.find(mw_uri, @subjectid) - mw = mw_ds.data_entries[compound_uri][mw_uri.to_s + "/feature/MW"].first.to_f - mw_ds.delete(@subjectid) - return mw - end - - def transform(value, compound_uri, name, haml) - prediction_trans = nil - model_name = name.to_s.downcase - if model_name.include? "ptd50" - mw = calc_mw(compound_uri) - td50 = ptd50_to_td50(value, mw) - prediction_trans = "TD50: #{td50}" - elsif model_name.include? "loael" - if model_name.include? "mol" - mw = calc_mw(compound_uri) - mg = logmmol_to_mg(value, mw) - prediction_trans = "mg/kg bw/day: #{mg}" - elsif model_name.include? "mg" - mg = logmg_to_mg(value) - prediction_trans = "mg/kg bw/day: #{mg}" - end - end - if haml == true - haml ".other #{prediction_trans.to_s}", :layout => false - else - return prediction_trans - end - end end diff --git a/views/details.haml b/views/details.haml index bb8250d..be4948a 100644 --- a/views/details.haml +++ b/views/details.haml @@ -1,8 +1,12 @@ +:javascript + $(document).ready(function(){ + addExternalLinks(); + }); %div.modal-body{:style=>"padding:10px;"} %button.close{ :type=>" button", data: { dismiss:"modal"}} × %h3 Names and synonyms: - %img.img-responsive{:src=>"#{@compound.uri}/image", :alt=>"Compound image not available", :width=>"300px", :heigth=>"300px", :style=>"float:left;"} + %p= @compound.svg %p %b="SMILES:" %p= @smiles diff --git a/views/layout.haml b/views/layout.haml index 5ed63e8..62a224b 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -29,11 +29,30 @@ %h1.media-heading lazar toxicity predictions %div.col-md-2 - %h5 + %h1.media-heading %small - [version: #{@version}] + %a{:href=>"https://nano-lazar.in-silico.ch", :rel=>"external"} nano-lazar %div.container-fluid + %topline + %div.row + %div.col-md-8 + Problems, bugs, ideas for improvements ? Please report at our + %a{:href => 'https://github.com/opentox/lazar-gui/issues', :rel => "external"} issue tracker + or send us an email. + %a{ :href=>"mailto:info@in-silico.ch", :target=>"_top"} + %img.share{:src=>"/images/Email.png"} + [version: #{@version}] + %div.col-md-2 + %div.col-md-2 + %a{:href=>"https://twitter.com/intent/tweet?source=http%3A%2F%2Flazar.in-silico.ch&text=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Tweet"} + %img.share{:src=>"/images/Twitter.png"} + %a{:href=>"https://plus.google.com/share?url=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Share on Google+"} + %img.share{:src=>"/images/Google+.png"} + %a{:href=>"http://www.linkedin.com/shareArticle?mini=true&url=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Share on LinkedIn"} + %img.share{:src=>"/images/LinkedIn.png"} + %a{:href=>"https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Flazar.in-silico.ch&title=&summary=&source=http%3A%2F%2Flazar.in-silico.ch", :rel=>"external", :title=>"Share on Facebook"} + %img.share{:src=>"/images/Facebook.png"} :javascript $(document).ready(function(){ $("#back-top").hide(); @@ -57,7 +76,19 @@ %p.text-muted © %a{:href => 'http://www.in-silico.ch', :rel => "external"} in silico toxicology gmbh 2004 - #{Time.now.year.to_s} - + | + %a{:href => to("/license"), :rel => "external"} GPL3 License + %supporters.col-md-12 + %p Financial support by + %a{:href=>"http://www.bfr.bund.de/de/start.html", :rel=>"external"} + %img{:src=>"/images/bfr_logo.gif"} + %a{:href=>"http://www.opentox.org/", :rel=>"external"} + %img{:src=>"/images/ot_logo.png"} + %a{:href=>"https://enanomapper.net/", :rel=>"external"} + %img{:src=>"/images/enm_logo.png"} + %a{:href=>"https://www.researchgate.net/institution/Nestle_SA/department/Nestle_Research_Center", :rel=>"external"} + %img{:src=>"/images/nestec.jpg"} + #back-top{:style => "z-index:100;position:fixed;bottom:1%;right:1%;"} %a{:href => "", :style=>"text:decoration:none;color:#ccc;"} diff --git a/views/neighbors.haml b/views/neighbors.haml index 32b8389..a608c4d 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -81,8 +81,8 @@ / Compound - c = Compound.find(neighbor) %td{:style =>"vertical-align:middle;padding-left:1em;width:50%;"} - /%a.btn.btn-link{:href => "#details#{j+1}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(neighbor["_id"])}/details"), :id=>"link#{j+1}#{count}"}} - %p= c.svg + %a.btn.btn-link{:href => "#details#{j+1}", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(c.id.to_s)}/details"), :id=>"link#{j+1}#{count}"}} + = c.svg %p= c.smiles / Measured Activity diff --git a/views/predict.haml b/views/predict.haml index 9a7d0d4..b7a4087 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -125,12 +125,12 @@ %br %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'} %p - %label{:for=>"fileselect"} - or upload a CSV file for batch predictions - %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"File format", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"One column with compounds and keyword SMILES or InChI in the first row."}} - %br - %span.btn.btn-default.btn-file - %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv"} + -#%label{:for=>"fileselect"} + or upload a CSV file for batch predictions (disabled in public version) + -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"File format", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"One column with compounds and keyword SMILES or InChI in the first row."}} + -#%br + -#%span.btn.btn-default.btn-file + %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :accept=>"text/csv", :disabled=>"disabled"} %fieldset#middle.well %h2 2. Select one or more endpoints diff --git a/views/prediction.haml b/views/prediction.haml index b090be5..362f006 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -1,10 +1,3 @@ -:javascript - $(document).ready(function(){ - $('[data-toggle="popover"]').popover(); - $('.modal').on('hidden.bs.modal', function () { - $(this).removeData('bs.modal'); - }); - }); %div.well %a.btn.btn-warning{:href => to('/predict')} %i.glyphicon.glyphicon-menu-left @@ -16,7 +9,8 @@ %tbody %tr %td{:id=>"compound", :style=>"vertical-align:top;"} - %p= @compound.svg + %a.btn.btn-link{:href => "#details0", data: { toggle: "modal", remote: to("/prediction/#{CGI.escape(@compound.id.to_s)}/details"), :id=>"link01"}} + = @compound.svg %p= @compound.smiles - @model_types = {} - @dbhit = {} @@ -57,7 +51,7 @@ %p %b Prediction: / prediction popover - -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"

lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.

Classification:
Majority vote of neighbor activities weighted by similarity.

Regression:
Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.

Original publication."}} + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Prediction", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"

lazar searches the training dataset for similar compounds (neighbors) and calculates the prediction from their experimental activities.

Classification:
Majority vote of neighbor activities weighted by similarity.

Regression:
Prediction from a local partial least squares regression model with neighbor activities weighted by similarity.

Original publication."}} %br = (type == "Regression") ? "#{prediction[:value].delog10} (#{unit})
#{@compound.mmol_to_mg(prediction[:value].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : prediction[:value] @@ -67,20 +61,20 @@ %b 95% Prediction interval: - interval = (prediction[:prediction_interval].nil? ? nil : prediction[:prediction_interval]) / prediction interval popover - -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Prediction intervall", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"An estimate of prediction uncertainty. The \"real\" value should be with 95% probability within the prediction interval."}} + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Prediction intervall", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"left", html:"true", content:"An estimate of prediction uncertainty. The \"real\" value should be with 95% probability within the prediction interval."}} %br = interval.nil? ? "--" : "#{interval[1].delog10} - #{interval[0].delog10} (#{unit})" %br = "#{@compound.mmol_to_mg(interval[1].delog10)} - #{@compound.mmol_to_mg(interval[0].delog10)} #{(unit =~ /\b(mol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" if !prediction[:prediction_interval].nil? - else %b Probability: + / probability popover + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"Confidence", :tabindex=>"0", data: {trigger:"focus", 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."}} - unless prediction[:probabilities].nil? %br = "#{prediction[:probabilities].keys[0]}: #{prediction[:probabilities].values[0]}" %br = "#{prediction[:probabilities].keys[1]}: #{prediction[:probabilities].values[1]}" - / probability popover - -#%a.btn.glyphicon.glyphicon-info-sign{:href=>"#", :title=>"Confidence", :tabindex=>"0", data: {trigger:"focus", 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."}} / show warnings %p @@ -94,4 +88,8 @@ / always show the neighbors table, message is given there = haml :neighbors, :layout => false, :model_type => @model_types, :dbhit => @dbhit + +%div.modal.fade{:id=>"details0", :role=>"dialog"} + %div.modal-dialog.modal-lg + %div.modal-content -- cgit v1.2.3