summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Helma <helma@in-silico.de>2009-07-24 12:40:54 +0200
committerChristoph Helma <helma@in-silico.de>2009-07-24 12:40:54 +0200
commitd0836c7afa9007bb44d11e8f4b632eb66f7bb5ba (patch)
tree22aeecac379be9338840936409a1938e6ccb11cf
Initial import of lazar-webservice-gui
-rw-r--r--.gitignore2
-rw-r--r--config.ru5
-rw-r--r--lazar.rb100
-rw-r--r--public/opentox-rgb-72.pngbin0 -> 570 bytes
-rw-r--r--views/create.haml30
-rw-r--r--views/delete.haml22
-rw-r--r--views/index.haml16
-rw-r--r--views/layout.haml20
-rw-r--r--views/neighbors.haml34
-rw-r--r--views/prediction.haml29
-rw-r--r--views/show.haml17
-rw-r--r--views/style.sass18
-rw-r--r--views/tmp.haml3
-rw-r--r--views/validation.haml264
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
new file mode 100644
index 0000000..ab53b01
--- /dev/null
+++ b/public/opentox-rgb-72.png
Binary files differ
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 @@
+&rarr; 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
+ &copy;
+ %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 @@
+&rarr;
+%a{ :href => "/#{params[:id]}" } Enter structure
+&rarr; 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 @@
+&rarr;
+%a{ :href => "/#{params[:id]}" } Enter structure
+&rarr; 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 @@
+&rarr; 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