diff options
author | Christoph Helma <helma@in-silico.de> | 2009-07-24 12:40:54 +0200 |
---|---|---|
committer | Christoph Helma <helma@in-silico.de> | 2009-07-24 12:40:54 +0200 |
commit | d0836c7afa9007bb44d11e8f4b632eb66f7bb5ba (patch) | |
tree | 22aeecac379be9338840936409a1938e6ccb11cf |
Initial import of lazar-webservice-gui
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | config.ru | 5 | ||||
-rw-r--r-- | lazar.rb | 100 | ||||
-rw-r--r-- | public/opentox-rgb-72.png | bin | 0 -> 570 bytes | |||
-rw-r--r-- | views/create.haml | 30 | ||||
-rw-r--r-- | views/delete.haml | 22 | ||||
-rw-r--r-- | views/index.haml | 16 | ||||
-rw-r--r-- | views/layout.haml | 20 | ||||
-rw-r--r-- | views/neighbors.haml | 34 | ||||
-rw-r--r-- | views/prediction.haml | 29 | ||||
-rw-r--r-- | views/show.haml | 17 | ||||
-rw-r--r-- | views/style.sass | 18 | ||||
-rw-r--r-- | views/tmp.haml | 3 | ||||
-rw-r--r-- | views/validation.haml | 264 |
14 files changed, 560 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56f8130 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tmp/* +TODO diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..f6b9cf3 --- /dev/null +++ b/config.ru @@ -0,0 +1,5 @@ +require 'rubygems' +require 'sinatra' +require 'lazar.rb' + +run Sinatra::Application diff --git a/lazar.rb b/lazar.rb new file mode 100644 index 0000000..27e3792 --- /dev/null +++ b/lazar.rb @@ -0,0 +1,100 @@ +['rubygems', 'sinatra', 'rest_client', 'sinatra/url_for', 'haml', 'sass', 'crack/xml'].each do |lib| + require lib +end + +LAZAR_URI = 'http://webservices.in-silico.ch/lazar/models/' +#LAZAR_URI = 'http://localhost:3000/models/' +COMPOUNDS_URI = 'http://webservices.in-silico.ch/compounds/' + +get '/' do + @models = [] + (RestClient.get LAZAR_URI).chomp.each_line do |uri| + puts uri + xml = RestClient.get uri + @models << Crack::XML.parse(xml)['model'] + name = Crack::XML.parse(xml)['model']['name'] + end + haml :index +end + +get '/create' do + haml :create +end + +get '/neighbors' do + #@lazar = params[:lazar] + #haml :neighbors + "Sorry, display of neighbors is not (yet) implemented." +end + +get '/:id' do # input form for predictions + begin + xml = RestClient.get "#{LAZAR_URI}#{params[:id]}" + @model = Crack::XML.parse(xml)['model'] + YAML.load(RestClient.get "#{@model['validation']['details_uri']}") # check if model creation is finished + haml :show + rescue + redirect "/tmp/#{params[:id]}" + end +end + +get '/validation/:id' do + begin + xml = RestClient.get "#{LAZAR_URI}#{params[:id]}" + @model = Crack::XML.parse(xml)['model'] + @summary = YAML.load(RestClient.get "#{@model['validation']['summary_uri']}") + haml :validation + rescue + redirect "/tmp/#{params[:id]}" + end +end + +get '/delete/:id' do + xml = RestClient.get "#{LAZAR_URI}#{params[:id]}" + @model = Crack::XML.parse(xml)['model'] + haml :delete +end + +get '/tmp/:id' do + haml :tmp +end + +post '/' do # create a new model + # create dataset + # validate lazar on the dataset + sanitized_name = params[:name].gsub(/\s+/,'_').gsub(/[^[:alnum:]]/, '') + uri = `curl -F name=#{sanitized_name} -F file=@#{params[:file][:tempfile].path} -F username=#{params[:username]} -F password=#{params[:password]} #{LAZAR_URI}` + id = uri.chomp.gsub(/^.*\/(\d+)$/,'\1') + redirect "/#{id}" +end + +post '/:id' do # post chemical name to model + begin + smiles = RestClient.get "#{COMPOUNDS_URI}#{URI.encode(params[:name])}.smiles" + rescue + @message = "Can not retrieve Smiles from #{params[:name]}. Please try again." + redirect "/#{params[:id]}" + end + begin + xml = RestClient.get "#{LAZAR_URI}#{params[:id]}?smiles=#{URI.encode(smiles)}" + @lazar = Crack::XML.parse(xml)['lazar'] + haml :prediction + rescue + "Prediction for #{params[:name]} (SMILES #{smiles}) failed." + end +end + +delete '/:id' do + begin + RestClient.delete "#{LAZAR_URI}#{params[:id]}", :username => params[:username], :password => params[:password] + redirect '/' + rescue + "Deletion of model with ID #{params[:id]} failed. Please check your username and password." + end +end + +# SASS stylesheet +get '/stylesheets/style.css' do + headers 'Content-Type' => 'text/css; charset=utf-8' + sass :style +end diff --git a/public/opentox-rgb-72.png b/public/opentox-rgb-72.png Binary files differnew file mode 100644 index 0000000..ab53b01 --- /dev/null +++ b/public/opentox-rgb-72.png diff --git a/views/create.haml b/views/create.haml new file mode 100644 index 0000000..c89aa27 --- /dev/null +++ b/views/create.haml @@ -0,0 +1,30 @@ +→ Create + +%h1 + Create and validate a + %code lazar + model + +%form{ :action => '/', :method => "post", :enctype => "multipart/form-data" } + %table + %tr + %th Username: + %td + %input{:type => "text", :name => "username"} + %tr + %th Password: + %td + %input{:type => "text", :name => "password"} + %tr + %th Endpoint: + %td + %input{:type => "text", :name => "name"} + %tr + %th Training data: + %td + %input{:type => 'file', :name => 'file'} + %tr + %td + %input{ :type => "submit", :value => "Submit"} + + diff --git a/views/delete.haml b/views/delete.haml new file mode 100644 index 0000000..dc72eff --- /dev/null +++ b/views/delete.haml @@ -0,0 +1,22 @@ +%p + You are going to remove the + = @model['name'] + model permanently! +%p Enter your username/password if you are sure or cancel the operation. + +%form{ :action => "/#{params[:id]}", :method => "delete" } + %table + %tr + %th Username: + %td + %input{:type => "text", :name => "username"} + %tr + %th Password: + %td + %input{:type => "text", :name => "password"} + + %tr + %td + %input{:type => "submit", :value => "Delete"} + %td + %a{:href => '/'} Cancel diff --git a/views/index.haml b/views/index.haml new file mode 100644 index 0000000..3580f7d --- /dev/null +++ b/views/index.haml @@ -0,0 +1,16 @@ +%h1 + %code lazar + prediction models + +%a{ :href => '/create' } Create a model + +%ul + - @models.each do |model| + %li + %a{:href => "/#{model['id']}"} + = model['name'].capitalize.gsub(/_/,' ') + from + = model['user'] + ( + %a{:href => "/validation/#{model['id']}"} Validation + ) diff --git a/views/layout.haml b/views/layout.haml new file mode 100644 index 0000000..720c801 --- /dev/null +++ b/views/layout.haml @@ -0,0 +1,20 @@ +!!! +%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"} + + %head + %meta{'http-equiv' => 'Content-Type', :content => 'text/html'} + %title Lazar + %link{:rel=>'stylesheet', :href=>'/stylesheets/style.css', :type => "text/css"} + + %body + + %a{ :href => "/" } Home + + = yield + + %hr + © + %a{:href => 'http://www.in-silico.ch'} in silico toxicology + 2009, powered by + %a{:href => 'http://www.opentox.org'} OpenTox + diff --git a/views/neighbors.haml b/views/neighbors.haml new file mode 100644 index 0000000..5bf5aba --- /dev/null +++ b/views/neighbors.haml @@ -0,0 +1,34 @@ +→ +%a{ :href => "/#{params[:id]}" } Enter structure +→ Prediction + +%h1= @lazar['endpoint'].gsub(/\"|\'/,'') + +%table + %tr + %th Structure + %th Prediction + %th Measured activity + %tr + %td + %img{:src => "http://cactus.nci.nih.gov/chemical/structure/#{URI.encode(@lazar['smiles'])}/image", :alt => "#{@lazar['smiles']}"} + %td + %p= @lazar['prediction'] + %p + ( + = @lazar['confidence'] + ) + %td= @lazar['database_activity'] + %tr + %td{:colspan => 4} Neighbors + %tr + %th Structure + %th Similarity + %th Measured activity + + - @lazar['neighbors']['neighbor'].each do |neighbor| + %tr + %td + %img{:src => "http://cactus.nci.nih.gov/chemical/structure/#{URI.encode(neighbor['smiles'])}/image", :alt => "#{neighbor['smiles']}"} + %td= neighbor['similarity'] + %td= neighbor['activity'] diff --git a/views/prediction.haml b/views/prediction.haml new file mode 100644 index 0000000..5842dfc --- /dev/null +++ b/views/prediction.haml @@ -0,0 +1,29 @@ +→ +%a{ :href => "/#{params[:id]}" } Enter structure +→ Prediction + +%h1 + = @lazar['endpoint'].gsub(/\"|\'/,'').capitalize.gsub(/_/,' ') + of + = params[:name] + +.prediction + %table + %tr + %th Structure + %th + %p Prediction + %p (Confidence) + %th Measured activity + %tr + %td + %img{:src => "http://cactus.nci.nih.gov/chemical/structure/#{URI.encode(@lazar['smiles'])}/image", :alt => "#{@lazar['smiles']}"} + %td + %br= @lazar['prediction'] + %br + ( + = @lazar['confidence'] + ) + %td= @lazar['database_activity'] + +%a{:href => "/neighbors", :lazar => @lazar } Show neighbors diff --git a/views/show.haml b/views/show.haml new file mode 100644 index 0000000..2660f5e --- /dev/null +++ b/views/show.haml @@ -0,0 +1,17 @@ +→ Enter structure + +%h1 + = @model['name'].capitalize.gsub(/_/,' ') + prediction + +%a{ :href => "/validation/#{params[:id]}" } Validation results + +%a{:href => "/delete/#{params[:id]}"} Delete model + +%p= @message if @message + +%form{ :action => "/#{params[:id]}", :method => "post" } + + %p Enter a chemical identifier (e.g. name, CAS number, Smiles, InChI, InChI key): + %input{:type => "text", :name => "name"} + %input{ :type => "submit", :value => "Predict"} diff --git a/views/style.sass b/views/style.sass new file mode 100644 index 0000000..2b9d7ce --- /dev/null +++ b/views/style.sass @@ -0,0 +1,18 @@ +form + th + :text-align right + +.prediction + :text-align center + table + :border-spacing 0 + :border-collapse collapse + :margin 0 + :border 1px solid + + th + :border 1px solid + :margin 2% + td + :border 1px solid + :margin 2% diff --git a/views/tmp.haml b/views/tmp.haml new file mode 100644 index 0000000..31589f2 --- /dev/null +++ b/views/tmp.haml @@ -0,0 +1,3 @@ +%p Model not (yet) available - it is likely that model creation and validation is still running. +%a{ :href => "/#{params[:id]}" } Reload this page +to see if the process has finished. diff --git a/views/validation.haml b/views/validation.haml new file mode 100644 index 0000000..d1af379 --- /dev/null +++ b/views/validation.haml @@ -0,0 +1,264 @@ += "-> " +%a{ :href => "/validation/#{params[:id]}" } Validation + +%h1 + = @model['name'].capitalize.gsub(/_/,' ') + validation + +Created on += @model['created_at'] +by += @model['user'] +( +%a{ :href => @model['validation']['details_uri'] } Prediction details +) + +%h3 Predictions weighted by confidence index +%p + %em Best indication of the overall performance + +%table + %tr + %th + True positive predictions + %td + tp + %td + = sprintf("%0.2f",@summary[:weighted][:tp].to_f) + %tr + %th + True negative predictions + %td + tn + %td + = sprintf("%0.2f",@summary[:weighted][:tn].to_f) + %tr + %th + False positive predictions + %td + fp + %td + = sprintf("%0.2f",@summary[:weighted][:fp].to_f) + %tr + %th + False negative predictions + %td + fn + %td + = sprintf("%0.2f",@summary[:weighted][:fn].to_f) + %tr + %th + Sensitivity (true positive rate) + %td + tp/(tp+fn) + %td + = (100*@summary[:weighted][:tp].to_f/(@summary[:weighted][:tp].to_f+@summary[:weighted][:fn].to_f)).round/100.00 + %tr + %th + Specificity (true negative rate) + %td + tn/(tn+fp) + %td + = (100*@summary[:weighted][:tn].to_f/(@summary[:weighted][:tn].to_f+@summary[:weighted][:fp].to_f).to_f).round/100.00 + %tr + %th + Positive predictivity + %td + tp/(tp+fp) + %td + = (100*@summary[:weighted][:tp].to_f/(@summary[:weighted][:tp].to_f+@summary[:weighted][:fp].to_f).to_f).round/100.00 + %tr + %th + Negative predictivity + %td + tn/(tn+fn) + %td + = (100*@summary[:weighted][:tn].to_f/(@summary[:weighted][:tn].to_f+@summary[:weighted][:fn].to_f).to_f).round/100.00 + %tr + %th + False positive rate + %td + fp/(tp+fn) + %td + = (100*@summary[:weighted][:fp].to_f/(@summary[:weighted][:tp].to_f+@summary[:weighted][:fn].to_f).to_f).round/100.00 + %tr + %th + False negative rate + %td + fn/(tn+fp) + %td + = (100*@summary[:weighted][:fn].to_f/(@summary[:weighted][:tn].to_f+@summary[:weighted][:fp].to_f).to_f).round/100.00 + %tr + %th + Accuracy (concordance) + %td + (tp+tn)/(tp+fp+tn+fn) + %th + = (100*(@summary[:weighted][:tp].to_f+@summary[:weighted][:tn].to_f)/(@summary[:weighted][:tp].to_f+@summary[:weighted][:tn].to_f+@summary[:weighted][:fn].to_f+@summary[:weighted][:fp].to_f).to_f).round/100.00 + + +%h3 Predictions within the applicability domain +%p + %em Hard cutoff at confidence > 0.025 + +%table + %tr + %th + True positive predictions + %td + tp + %td + = @summary[:within_ad][:tp].to_i + %tr + %th + True negative predictions + %td + tn + %td + = @summary[:within_ad][:tn].to_i + %tr + %th + False positive predictions + %td + fp + %td + = @summary[:within_ad][:fp].to_i + %tr + %th + False negative predictions + %td + fn + %td + = @summary[:within_ad][:fn].to_i + %tr + %th + Sensitivity (true positive rate) + %td + tp/(tp+fn) + %td + = (100*@summary[:within_ad][:tp].to_i/(@summary[:within_ad][:tp].to_i+@summary[:within_ad][:fn].to_i).to_f).round/100.00 + %tr + %th + Specificity (true negative rate) + %td + tn/(tn+fp) + %td + = (100*@summary[:within_ad][:tn].to_i/(@summary[:within_ad][:tn].to_i+@summary[:within_ad][:fp].to_i).to_f).round/100.00 + %tr + %th + Positive predictivity + %td + tp/(tp+fp) + %td + = (100*@summary[:within_ad][:tp].to_i/(@summary[:within_ad][:tp].to_i+@summary[:within_ad][:fp].to_i).to_f).round/100.00 + %tr + %th + Negative predictivity + %td + tn/(tn+fn) + %td + = (100*@summary[:within_ad][:tn].to_i/(@summary[:within_ad][:tn].to_i+@summary[:within_ad][:fn].to_i).to_f).round/100.00 + %tr + %th + False positive rate + %td + fp/(tp+fn) + %td + = (100*@summary[:within_ad][:fp].to_i/(@summary[:within_ad][:tp].to_i+@summary[:within_ad][:fn].to_i).to_f).round/100.00 + %tr + %th + False negative rate + %td + fn/(tn+fp) + %td + = (100*@summary[:within_ad][:fn].to_i/(@summary[:within_ad][:tn].to_i+@summary[:within_ad][:fp].to_i).to_f).round/100.00 + %tr + %th + Accuracy (concordance) + %td + (tp+tn)/(tp+fp+tn+fn) + %th + = (100*(@summary[:within_ad][:tp].to_i+@summary[:within_ad][:tn].to_i)/(@summary[:within_ad][:tp].to_i+@summary[:within_ad][:tn].to_i+@summary[:within_ad][:fn].to_i+@summary[:within_ad][:fp].to_i).to_f).round/100.00 + +%h3 All predictions +%p + %em Poor indication of the overall performance. Depends predominatly on the fraction of compounds within the applicability domain. + +%table + %tr + %th + True positive predictions + %td + tp + %td + = @summary[:all][:tp].to_i + %tr + %th + True negative predictions + %td + tn + %td + = @summary[:all][:tn].to_i + %tr + %th + False positive predictions + %td + fp + %td + = @summary[:all][:fp].to_i + %tr + %th + False negative predictions + %td + fn + %td + = @summary[:all][:fn].to_i + %tr + %th + Sensitivity (true positive rate) + %td + tp/(tp+fn) + %td + = (100*@summary[:all][:tp].to_i/(@summary[:all][:tp].to_i+@summary[:all][:fn].to_i).to_f).round/100.00 + %tr + %th + Specificity (true negative rate) + %td + tn/(tn+fp) + %td + = (100*@summary[:all][:tn].to_i/(@summary[:all][:tn].to_i+@summary[:all][:fp].to_i).to_f).round/100.00 + %tr + %th + Positive predictivity + %td + tp/(tp+fp) + %td + = (100*@summary[:all][:tp].to_i/(@summary[:all][:tp].to_i+@summary[:all][:fp].to_i).to_f).round/100.00 + %tr + %th + Negative predictivity + %td + tn/(tn+fn) + %td + = (100*@summary[:all][:tn].to_i/(@summary[:all][:tn].to_i+@summary[:all][:fn].to_i).to_f).round/100.00 + %tr + %th + False positive rate + %td + fp/(tp+fn) + %td + = (100*@summary[:all][:fp].to_i/(@summary[:all][:tp].to_i+@summary[:all][:fn].to_i).to_f).round/100.00 + %tr + %th + False negative rate + %td + fn/(tn+fp) + %td + = (100*@summary[:all][:fn].to_i/(@summary[:all][:tn].to_i+@summary[:all][:fp].to_i).to_f).round/100.00 + %tr + %th + Accuracy (concordance) + %td + (tp+tn)/(tp+fp+tn+fn) + %th + = (100*(@summary[:all][:tp].to_i+@summary[:all][:tn].to_i)/(@summary[:all][:tp].to_i+@summary[:all][:tn].to_i+@summary[:all][:fn].to_i+@summary[:all][:fp].to_i).to_f).round/100.00 |