From e769f0d2c2b5eb866b039f0b7857955d9e436e78 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 2 Feb 2010 14:43:42 +0100 Subject: gem version updated to 1.2.7 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 11115ff..ff9b964 100644 --- a/application.rb +++ b/application.rb @@ -3,7 +3,7 @@ end require 'rack-flash' #require 'benchmark' -gem 'opentox-ruby-api-wrapper', '= 1.2.6' +gem 'opentox-ruby-api-wrapper', '= 1.2.7' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 33cdbcf4f3e3a33ef9f297ae1b8a540beb0acc62 Mon Sep 17 00:00:00 2001 From: mr Date: Wed, 3 Feb 2010 15:32:12 +0100 Subject: fix config and add Authentication --- application.rb | 3 ++- config.ru | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 11115ff..47a7d60 100644 --- a/application.rb +++ b/application.rb @@ -82,7 +82,8 @@ post '/predict/?' do # post chemical name to model prediction = nil confidence = nil title = nil - prediction = RestClient.post uri, :compound_uri => @compound.uri, :accept => "application/x-yaml" + resource = RestClient::Resource.new(uri, :user => @@users[:users].keys[0], :password => @@users[:users].values[0]) + prediction = resource.post :compound_uri => @compound.uri, :accept => "application/x-yaml" model = Redland::Model.new Redland::MemoryStore.new parser = Redland::Parser.new parser.parse_string_into_model(model,prediction,'/') diff --git a/config.ru b/config.ru index efe0004..0ada150 100644 --- a/config.ru +++ b/config.ru @@ -1,5 +1,9 @@ require 'rubygems' require 'opentox-ruby-api-wrapper' require 'tasks/config' +require 'rack/flash' +use Rack::Session::Cookie +use Rack::Flash + set :app_file, __FILE__ # to get the view path right run Sinatra::Application -- cgit v1.2.3 From 5b533272dfcc81e5f01cbab6249a08f8606d56b5 Mon Sep 17 00:00:00 2001 From: chief Date: Thu, 4 Feb 2010 10:18:23 +0100 Subject: first layout with font-family "arial" and added opentox_logo --- config.ru | 4 ++++ public/opentox-rgb-72.png | Bin 570 -> 0 bytes views/layout.haml | 6 ++++-- views/style.sass | 23 ++++++++++++++++++++--- 4 files changed, 28 insertions(+), 5 deletions(-) delete mode 100644 public/opentox-rgb-72.png diff --git a/config.ru b/config.ru index f3b57d3..bf22dcf 100644 --- a/config.ru +++ b/config.ru @@ -20,4 +20,8 @@ elsif ENV['RACK_ENV'] == 'development' use Rack::ShowExceptions end +require 'rack/flash' +use Rack::Session::Cookie +use Rack::Flash + run Sinatra::Application diff --git a/public/opentox-rgb-72.png b/public/opentox-rgb-72.png deleted file mode 100644 index ab53b01..0000000 Binary files a/public/opentox-rgb-72.png and /dev/null differ diff --git a/views/layout.haml b/views/layout.haml index 2eb43c5..47699b6 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -7,8 +7,10 @@ %link{:rel=>'stylesheet', :href=>'/stylesheets/style.css', :type => "text/css"} %body - %h1 ToxModel - + .headline + %h1 ToxModel + %img{:src => "/opentox_logo.png", :alt => "OpenTox"} + .index %ul %li{:class => ("selected" if /create/ =~ request.path )} diff --git a/views/style.sass b/views/style.sass index b4db904..8f5a1d3 100644 --- a/views/style.sass +++ b/views/style.sass @@ -4,13 +4,28 @@ !text_color = black body + min-width: 30em + font-family: arial background-color = !body_color color = !text_color height: 100% padding: 1em - h1 - text-align: right + .headline + + h1 + color = !fg_color + margin: 0 + padding: 0 + background-color = !body_color + padding-left: 0.5em + padding-bottom: 0.5em + + img + margin: 0 + position: absolute + top: 0.7em + left: 40em .index @@ -36,7 +51,7 @@ body text-decoration: none color = !bg_color &:hover - color = !bg_color + color = #5D308A li.selected font-weight: bolder @@ -82,3 +97,5 @@ body :padding 2% .footer + margin: 0.5em + padding: 0.5em -- cgit v1.2.3 From 425a202ab54fbeb1d664584356b5d84c14ca516b Mon Sep 17 00:00:00 2001 From: chief Date: Thu, 4 Feb 2010 10:35:46 +0100 Subject: public folder --- public/opentox_logo.png | Bin 0 -> 4274 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/opentox_logo.png diff --git a/public/opentox_logo.png b/public/opentox_logo.png new file mode 100644 index 0000000..139250f Binary files /dev/null and b/public/opentox_logo.png differ -- cgit v1.2.3 From 6171a5a7879c0465f0eaea8f2451554882af4b92 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 4 Feb 2010 19:41:23 +0100 Subject: tasks as trees, prediction of database structures, improved error checking --- application.rb | 33 +++++++++++++++++++++------------ config.ru | 2 +- views/create.haml | 28 +++++++++++++--------------- views/predict.haml | 37 ++++++++++++++++--------------------- views/prediction.haml | 26 +++++++++++++++++++++----- views/style.sass | 22 ++++++++++++++++------ 6 files changed, 88 insertions(+), 60 deletions(-) diff --git a/application.rb b/application.rb index ff9b964..a649b82 100644 --- a/application.rb +++ b/application.rb @@ -2,7 +2,6 @@ require lib end require 'rack-flash' -#require 'benchmark' gem 'opentox-ruby-api-wrapper', '= 1.2.7' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' @@ -11,6 +10,20 @@ require 'sinatra/static_assets' use Rack::Flash set :sessions, true +helpers do + def activity(a) + case a.to_s + when "true" + act = "active" + when "false" + act = "inactive" + else + act = "not available" + end + act + end +end + get '/?' do redirect url_for('/create') end @@ -75,14 +88,15 @@ post '/predict/?' do # post chemical name to model @compound = OpenTox::Compound.new(:name => params[:identifier]) rescue flash[:notice] = "Could not find a structure for #{@identifier}. Please try again." - redirect '/predict' + redirect url_for('/predict') end @predictions = [] params[:selection].keys.each do |uri| prediction = nil confidence = nil title = nil - prediction = RestClient.post uri, :compound_uri => @compound.uri, :accept => "application/x-yaml" + db_activities = [] + prediction = RestClient.post uri, :compound_uri => @compound.uri#, :accept => "application/x-yaml" model = Redland::Model.new Redland::MemoryStore.new parser = Redland::Parser.new parser.parse_string_into_model(model,prediction,'/') @@ -93,18 +107,13 @@ post '/predict/?' do # post chemical name to model feature_name = model.object(feature,DC['title']).to_s prediction = model.object(v,OT['value']).to_s if feature_name.match(/classification/) confidence = model.object(v,OT['value']).to_s if feature_name.match(/confidence/) + db_activities << model.object(v,OT['value']).to_s if feature_name.match(/#{title}/) end - case prediction.to_s - when "true" - prediction = "active" - when "false" - prediction = "inactive" - else - prediction = "not available" - end - @predictions << {:title => title, :prediction => prediction, :confidence => confidence} + @predictions << {:title => title, :prediction => prediction, :confidence => confidence, :measured_activities => db_activities} + LOGGER.debug db_activities.to_yaml end + LOGGER.debug @predictions.to_yaml haml :prediction #@predictions.to_yaml end diff --git a/config.ru b/config.ru index efe0004..78b1144 100644 --- a/config.ru +++ b/config.ru @@ -1,5 +1,5 @@ require 'rubygems' require 'opentox-ruby-api-wrapper' -require 'tasks/config' +require 'config/config_ru' set :app_file, __FILE__ # to get the view path right run Sinatra::Application diff --git a/views/create.haml b/views/create.haml index 9477210..5527d70 100644 --- a/views/create.haml +++ b/views/create.haml @@ -1,17 +1,15 @@ -.upload +.input %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } - %ol - %li - %label{:for => 'endpoint'}Enter endpoint name: - %input{:type => 'text', :name => 'endpoint', :id => 'endpoint'} - %li - %label{:for => 'file'} - Upload training data in CSV format: - %input{:type => 'file', :name => 'file', :id => 'file'} - ( - = link_to "formatting instructions ", 'csv_format' - ) - %li - %input{ :type => "submit", :value => "Create model"} - = link_to "Cancel", 'create' + %fieldset + %legend Upload training data and create a prediction model + %label{:for => 'endpoint'} 1. Enter endpoint name: + %input{:type => 'text', :name => 'endpoint', :id => 'endpoint'} + %br + %label{:for => 'file'} 2. Select training data in CSV format: + %input{:type => 'file', :name => 'file', :id => 'file'} + ( + = link_to "formatting instructions ", 'csv_format' + ) + %input{ :type => "submit", :value => "Create model"} + = link_to "Cancel", 'create' diff --git a/views/predict.haml b/views/predict.haml index 7c4b980..f6ed6a3 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -1,25 +1,20 @@ -.upload +.input - unless @models.nil? %form{ :action => url_for('/predict'), :method => "post", :enctype => "multipart/form-data" } - %ol - %li - %label{:for => 'identifier'}Enter a compound identifier: - %input{:type => 'text', :name => 'identifier', :id => 'identifier'} - (Name, InChI, Smiles, CAS, ...) - %li - %label{:for => 'model'}Choose one or more prediction models: - %ul - - @models.each do |model| - - yaml = RestClient.get model, :accept => 'application/x-yaml' - - yaml = YAML.load yaml - %br - -# %input{:type => 'checkbox', :name => 'model_uri', :value => model} - -# %input{:type => 'checkbox', :name => "selection[#{model}]", :value => true} - %input{:type => 'checkbox', :name => "selection[#{model}]", :value => true, :id => 'model'} - = yaml[:endpoint].split(/#/).last + %fieldset + %legend Enter a compound identifier + %label{:for => 'identifier'} Name, InChI, Smiles, CAS, ... + %input{:type => 'text', :name => 'identifier', :id => 'identifier'} + %fieldset + %legend Choose one or more prediction models + - @models.each do |model| + - yaml = RestClient.get model, :accept => 'application/x-yaml' + - yaml = YAML.load yaml + %label{:for => model} + = yaml[:endpoint].split(/#/).last.gsub(/_/,' ') + %input{:type => 'checkbox', :name => "selection[#{model}]", :value => true, :id => model} + %br - %li - %p - %input{ :type => "submit", :value => "Predict"} - = link_to 'Cancel', '/' + %input{ :type => "submit", :value => "Predict"} + = link_to 'Cancel', '/' diff --git a/views/prediction.haml b/views/prediction.haml index aa84fee..74e0956 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -9,8 +9,24 @@ - @predictions.each do |p| %td %b - = p[:title] + ":" - = p[:prediction] - %br - Confidence: - = p[:confidence] + = p[:title].gsub(/_/,' ') + ":" + - if p[:measured_activities].size > 0 + %br + - p[:measured_activities].each do |a| + - if activity(a) == 'active' + .active + = activity(a) + - elsif activity(a) == 'inactive' + .inactive + = activity(a) + %br (training data) + - else + - if activity(p[:prediction]) == 'active' + .active + = activity(p[:prediction]) + - elsif activity(p[:prediction]) == 'inactive' + .inactive + = activity(p[:prediction]) + - if p[:confidence] + %br + = "(confidence: #{sprintf('%.03f', p[:confidence].to_f.abs)})" diff --git a/views/style.sass b/views/style.sass index 4d29ddd..c509c3b 100644 --- a/views/style.sass +++ b/views/style.sass @@ -62,16 +62,20 @@ body padding: 1% border: 1px solid red - .upload + .input text-align: left form - li - clear: left + fieldset + border: 0 + legend + font-weight: bold + color = !fg_color label - width: 20em - float: left - margin-right: 0.5em + width: 25em display: block + float: left + br + clear: both .predictions :text-align center @@ -89,4 +93,10 @@ body :border 1px solid :padding 2% +.active + color: red + +.inactive + color: green + .footer -- cgit v1.2.3 From e5c015a88f922eb5c8b48587f45c8eaf987d9ef0 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 8 Feb 2010 10:27:19 +0100 Subject: Modifications of Denis included --- views/layout.haml | 7 +++---- views/style.sass | 33 +++++++++++++-------------------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/views/layout.haml b/views/layout.haml index c46638c..f72ce1e 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -7,9 +7,7 @@ %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body - .headline - %h1 ToxModel - %img{:src => "/opentox_logo.png", :alt => "OpenTox"} + %h1 ToxModel .index %ul @@ -34,5 +32,6 @@ © %a{:href => 'http://www.in-silico.ch'} in silico toxicology 2009, powered by - %a{:href => 'http://www.opentox.org'} OpenTox + %a{:href => 'http://www..opentox.org'} OpenTox + -# image_tag("/opentox_logo.png", :alt => "OpenTox") diff --git a/views/style.sass b/views/style.sass index e8d670c..f8abea5 100644 --- a/views/style.sass +++ b/views/style.sass @@ -5,28 +5,19 @@ body min-width: 30em - font-family: arial + font-family: Verdana background-color = !body_color color = !text_color height: 100% padding: 1em - .headline - - h1 - color = !fg_color - margin: 0 - padding: 0 - background-color = !body_color - padding-left: 0.5em - padding-bottom: 0.5em + h1 + text-align: right + color = !fg_color + margin: 0 + padding: 0 + background-color = !body_color - img - margin: 0 - position: absolute - top: 0.7em - left: 40em - .index ul @@ -108,12 +99,14 @@ body :border 1px solid :padding 2% + .footer + margin: 0.5em + padding: 0.5em + img + height: 24px + .active color: red .inactive color: green - - .footer - margin: 0.5em - padding: 0.5em -- cgit v1.2.3 From 04f39a56fdb10361a32583e74554332b3eb8bc32 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 8 Feb 2010 12:30:23 +0100 Subject: tasks bar removed, link to issue tracker added --- application.rb | 2 +- views/layout.haml | 6 +++++- views/predict.haml | 3 ++- views/style.sass | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/application.rb b/application.rb index a649b82..2e5e26e 100644 --- a/application.rb +++ b/application.rb @@ -77,7 +77,7 @@ post '/upload' do # create a new model end dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) - flash[:notice] = "Model creation started - this may take some time. You can view and manage the status of current tasks at the #{link_to("Tasks page", "/tasks")}. #{link_to("Reload this page", "/predict")} to use the new model." + flash[:notice] = "Model creation started - this may take some time. As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." session[:task_uri] = task_uri redirect url_for('/predict') end diff --git a/views/layout.haml b/views/layout.haml index f72ce1e..2e0e575 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -15,13 +15,17 @@ = link_to "Create", "/create" %li{:class => ("selected" if /predict/ =~ request.path )} = link_to "Predict", "/predict" - %li{:class => ("selected" if /tasks/ =~ request.path )} + -#%li{:class => ("selected" if /tasks/ =~ request.path )} = link_to "Tasks", "/tasks" %li{:class => ("selected" if /about/ =~ request.path )} = link_to "About", "/about" .content + .notice + This service is for testing purposes only - once a week all models will be deleted. Please send bug reports and feature requests to our + %a{:href => 'http://github.com/helma/opentox-toxmodel/issues'} issue tracker. + - if flash[:notice] .notice = flash[:notice] diff --git a/views/predict.haml b/views/predict.haml index f6ed6a3..5cbb1d2 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -1,4 +1,5 @@ .input + = link_to 'Reload', '/predict' - unless @models.nil? %form{ :action => url_for('/predict'), :method => "post", :enctype => "multipart/form-data" } %fieldset @@ -16,5 +17,5 @@ %br %input{ :type => "submit", :value => "Predict"} - = link_to 'Cancel', '/' + = link_to 'Cancel', '/predict' diff --git a/views/style.sass b/views/style.sass index f8abea5..9de3d11 100644 --- a/views/style.sass +++ b/views/style.sass @@ -42,7 +42,7 @@ body text-decoration: none color = !bg_color &:hover - color = #5D308A + color = !body_color li.selected font-weight: bolder -- cgit v1.2.3 From df3767a3d1fb3b7ba2844b2c29008b657ca0c650 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 8 Feb 2010 14:41:35 +0100 Subject: reload link moved --- views/predict.haml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/views/predict.haml b/views/predict.haml index 5cbb1d2..5c93e46 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -1,5 +1,4 @@ .input - = link_to 'Reload', '/predict' - unless @models.nil? %form{ :action => url_for('/predict'), :method => "post", :enctype => "multipart/form-data" } %fieldset @@ -7,7 +6,11 @@ %label{:for => 'identifier'} Name, InChI, Smiles, CAS, ... %input{:type => 'text', :name => 'identifier', :id => 'identifier'} %fieldset - %legend Choose one or more prediction models + %legend + Choose one or more prediction models + ( + = link_to 'Reload', '/predict' + ) - @models.each do |model| - yaml = RestClient.get model, :accept => 'application/x-yaml' - yaml = YAML.load yaml -- cgit v1.2.3 From 98d5f6baac6faa4463b91c69921b5ad7795d3f3c Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 9 Feb 2010 12:09:30 +0100 Subject: Dataset service with tasks --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 2e5e26e..01e80d3 100644 --- a/application.rb +++ b/application.rb @@ -75,7 +75,7 @@ post '/upload' do # create a new model flash[:notice] = "Irregular activity '#{items[1]}' for SMILES #{smiles}. Please use 1 for active and 0 for inactive compounds" end end - dataset_uri = dataset.save + dataset_uri = dataset.save #fails task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) flash[:notice] = "Model creation started - this may take some time. As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." session[:task_uri] = task_uri -- cgit v1.2.3 From 00aef9b6afceeb33d00b79bb7fceb65521c5f983 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 11 Feb 2010 11:15:26 +0100 Subject: more informative instructions added --- application.rb | 2 +- views/create.haml | 1 + views/prediction.haml | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 01e80d3..2558703 100644 --- a/application.rb +++ b/application.rb @@ -77,7 +77,7 @@ post '/upload' do # create a new model end dataset_uri = dataset.save #fails task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) - flash[:notice] = "Model creation started - this may take some time. As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." + flash[:notice] = "Model creation started - this may take some time (up to several hours for large datasets). As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." session[:task_uri] = task_uri redirect url_for('/predict') end diff --git a/views/create.haml b/views/create.haml index 5527d70..0ba4737 100644 --- a/views/create.haml +++ b/views/create.haml @@ -4,6 +4,7 @@ %legend Upload training data and create a prediction model %label{:for => 'endpoint'} 1. Enter endpoint name: %input{:type => 'text', :name => 'endpoint', :id => 'endpoint'} + %em (please use only letters, numbers and spaces - this will be fixed soon) %br %label{:for => 'file'} 2. Select training data in CSV format: %input{:type => 'file', :name => 'file', :id => 'file'} diff --git a/views/prediction.haml b/views/prediction.haml index 74e0956..241b01c 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -27,6 +27,9 @@ - elsif activity(p[:prediction]) == 'inactive' .inactive = activity(p[:prediction]) + - else + %br + %em not available - if p[:confidence] %br = "(confidence: #{sprintf('%.03f', p[:confidence].to_f.abs)})" -- cgit v1.2.3 From d915b89943b2aaa9d252bf75cfae872ee1544cf4 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 11 Feb 2010 12:16:59 +0100 Subject: Redirect back to model selection, if no endpoint selected. --- application.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 2558703..f4e4450 100644 --- a/application.rb +++ b/application.rb @@ -87,7 +87,11 @@ post '/predict/?' do # post chemical name to model begin @compound = OpenTox::Compound.new(:name => params[:identifier]) rescue - flash[:notice] = "Could not find a structure for #{@identifier}. Please try again." + flash[:notice] = "Could not find a structure for '#{@identifier}'. Please try again." + redirect url_for('/predict') + end + unless params[:selection] + flash[:notice] = "Please select an endpoint from the list!" redirect url_for('/predict') end @predictions = [] -- cgit v1.2.3 From 2c822c9d9da50866d26eac5e1debcaba5e35a451 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 15 Feb 2010 10:10:06 +0100 Subject: lazar model specified --- views/create.haml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/views/create.haml b/views/create.haml index 0ba4737..1193499 100644 --- a/views/create.haml +++ b/views/create.haml @@ -1,7 +1,10 @@ .input %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } %fieldset - %legend Upload training data and create a prediction model + %legend + Upload training data and create a + %a{:href => 'http://lazar.in-silico.de'} lazar + model %label{:for => 'endpoint'} 1. Enter endpoint name: %input{:type => 'text', :name => 'endpoint', :id => 'endpoint'} %em (please use only letters, numbers and spaces - this will be fixed soon) -- cgit v1.2.3 From 6a1cf5b3504a7ffad02f61b43ae258ef38d7c415 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 15 Feb 2010 10:16:20 +0100 Subject: title URI encoded --- application.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 01e80d3..8d00d39 100644 --- a/application.rb +++ b/application.rb @@ -56,8 +56,12 @@ get '/task' do end post '/upload' do # create a new model + unless params[:endpoint] and params[:file] and params[:file][:tempfile] + flash[:notice] = "Please enter an endpoint name and upload a CSV file." + redirect url_for('/create') + end dataset = OpenTox::Dataset.new - title = params[:endpoint].sub(/\s+/,'_') + title = URI.encode params[:endpoint]#.gsub(/\s+/,'_') dataset.title = title feature_uri = url_for("/feature#"+title, :full) feature = dataset.find_or_create_feature(feature_uri) -- cgit v1.2.3 From 13abba6497199238464fa5d7f94931c65de37ba9 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 16 Feb 2010 18:59:13 +0100 Subject: improved error handling of input structures --- application.rb | 96 +++++++++++++++++++++++++++++++++++++++++++-------- views/create.haml | 19 ++++++---- views/csv_format.haml | 2 +- views/layout.haml | 6 +++- views/model.haml | 4 +++ views/predict.haml | 3 +- views/prediction.haml | 3 +- 7 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 views/model.haml diff --git a/application.rb b/application.rb index ca6714c..3617026 100644 --- a/application.rb +++ b/application.rb @@ -10,6 +10,19 @@ require 'sinatra/static_assets' use Rack::Flash set :sessions, true +#class ToxPredictModel +# include DataMapper::Resource +# property :id, Serial +# property :name, String +# property :uri, String, :length => 255 +# property :task_uri, String, :length => 255 +# property :status, String, :length => 255 +# property :messages, Text, :length => 2**32-1 +# property :created_at, DateTime +#end + +#DataMapper.auto_upgrade! + helpers do def activity(a) case a.to_s @@ -28,7 +41,14 @@ get '/?' do redirect url_for('/create') end +get '/model/:id/?' do + #@model = ToxPredictModel.get(params[:id]) + @model = YAML.load(RestClient.get params[:uri], :accept => "application/x-yaml") + haml :model +end + get '/predict/?' do + #@models = ToxPredictModel.all @models = OpenTox::Model::Lazar.find_all haml :predict end @@ -60,30 +80,73 @@ post '/upload' do # create a new model flash[:notice] = "Please enter an endpoint name and upload a CSV file." redirect url_for('/create') end - dataset = OpenTox::Dataset.new + unless params[:file][:type] == "text/csv" + flash[:notice] = "Please upload a CSV file - at present we cannot handle other file types." + redirect url_for('/create') + end + #@model = ToxPredictModel.new + #@model.name = params[:endpoint] + #@model.status = "started" + #@model.save title = URI.encode params[:endpoint]#.gsub(/\s+/,'_') + dataset = OpenTox::Dataset.new dataset.title = title feature_uri = url_for("/feature#"+title, :full) feature = dataset.find_or_create_feature(feature_uri) + smiles_errors = [] + activity_errors = [] + duplicates = {} + nr_compounds = 0 + line_nr = 1 params[:file][:tempfile].each_line do |line| items = line.chomp.split(/\s*,\s*/) smiles = items[0] - compound_uri = OpenTox::Compound.new(:smiles => smiles).uri - compound = dataset.find_or_create_compound(compound_uri) - case items[1].to_s - when '1' - dataset.add(compound,feature,true) - when '0' - dataset.add(compound,feature,false) + c = OpenTox::Compound.new(:smiles => smiles) + if c.inchi != "" + duplicates[c.inchi] = [] unless duplicates[c.inchi] + duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp + compound_uri = c.uri + compound = dataset.find_or_create_compound(compound_uri) + case items[1].to_s + when '1' + dataset.add(compound,feature,true) + nr_compounds += 1 + when '0' + dataset.add(compound,feature,false) + nr_compounds += 1 + else + activity_errors << "Line #{line_nr}: " + line.chomp + end else - flash[:notice] = "Irregular activity '#{items[1]}' for SMILES #{smiles}. Please use 1 for active and 0 for inactive compounds" + smiles_errors << "Line #{line_nr}: " + line.chomp end + line_nr += 1 end - dataset_uri = dataset.save #fails + dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) - flash[:notice] = "Model creation started - this may take some time (up to several hours for large datasets). As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." + + @notice = "Model creation for #{params[:endpoint]}i (#{nr_compounds} compounds) started - this may take some time (up to several hours for large datasets). As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." + + if smiles_errors.size > 0 + @notice += "

The following Smiles structures were not readable and have been ignored:

" + @notice += smiles_errors.join("
") + end + if activity_errors.size > 0 + @notice += "

The following structures had irregular activities and have been ignored (please use 1 for active and 0 for inactive compounds):

" + @notice += activity_errors.join("
") + end + duplicate_warnings = '' + duplicates.each {|inchi,lines| duplicate_warnings += "

#{lines.join('
')}

" if lines.size > 1 } + LOGGER.debug duplicate_warnings + unless duplicate_warnings == '' + @notice += "

The following structures were duplicated in the dataset (this is not a problem for the algorithm, but you should make sure, that the results were obtained from independent experiments):

" + @notice += duplicate_warnings + end session[:task_uri] = task_uri - redirect url_for('/predict') + #redirect url_for('/predict') + @models = OpenTox::Model::Lazar.find_all + haml :predict + end post '/predict/?' do # post chemical name to model @@ -108,8 +171,12 @@ post '/predict/?' do # post chemical name to model model = Redland::Model.new Redland::MemoryStore.new parser = Redland::Parser.new parser.parse_string_into_model(model,prediction,'/') - f = model.subject(RDF['type'],OT['Feature']) # this can be dangerous if OWL is not properly sorted - title = model.object(f,DC['title']).to_s + yaml = RestClient.get uri, :accept => 'application/x-yaml' + yaml = YAML.load yaml + title = URI.decode yaml[:endpoint].split(/#/).last + #f = model.subject(RDF['type'],OT['Feature']) # this can be dangerous if OWL is not properly sorted + #title = RestClient.get(File.join(uri,"name")).to_s + #title = model.object(f,DC['title']).to_s model.subjects(RDF['type'], OT['FeatureValue']).each do |v| feature = model.object(v,OT['feature']) feature_name = model.object(feature,DC['title']).to_s @@ -118,7 +185,6 @@ post '/predict/?' do # post chemical name to model db_activities << model.object(v,OT['value']).to_s if feature_name.match(/#{title}/) end @predictions << {:title => title, :prediction => prediction, :confidence => confidence, :measured_activities => db_activities} - LOGGER.debug db_activities.to_yaml end LOGGER.debug @predictions.to_yaml diff --git a/views/create.haml b/views/create.haml index 1193499..448526f 100644 --- a/views/create.haml +++ b/views/create.haml @@ -1,19 +1,26 @@ .input + + %p + This service creates + %a{:href => 'http://lazar.in-silico.de'} lazar + prediction models (more model building algorithms will follow) from your uploaded datasets. Here are + = link_to "instructions", '/csv_format' + , how to create training datasets in Excel. + %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } %fieldset %legend Upload training data and create a %a{:href => 'http://lazar.in-silico.de'} lazar model - %label{:for => 'endpoint'} 1. Enter endpoint name: + %label{:for => 'endpoint'} 1. Enter a name for your endpoint: %input{:type => 'text', :name => 'endpoint', :id => 'endpoint'} - %em (please use only letters, numbers and spaces - this will be fixed soon) %br - %label{:for => 'file'} 2. Select training data in CSV format: + %label{:for => 'file'} + 2. Upload training data in + = link_to "CSV", '/csv_format' + format: %input{:type => 'file', :name => 'file', :id => 'file'} - ( - = link_to "formatting instructions ", 'csv_format' - ) %input{ :type => "submit", :value => "Create model"} = link_to "Cancel", 'create' diff --git a/views/csv_format.haml b/views/csv_format.haml index 0943c2f..b093499 100644 --- a/views/csv_format.haml +++ b/views/csv_format.haml @@ -1,4 +1,4 @@ -= link_to "Back to model creation", 'create' += link_to "Back to model creation", '/create' %p The input file should contain two columns, separated by a comma. Enter in the first column the chemical structure in = link_to "SMILES", "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification" diff --git a/views/layout.haml b/views/layout.haml index 2e0e575..4bec328 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -7,7 +7,7 @@ %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body - %h1 ToxModel + %h1 ToxCreate .index %ul @@ -30,6 +30,10 @@ .notice = flash[:notice] + - if @notice + .notice + = @notice + = yield .footer diff --git a/views/model.haml b/views/model.haml new file mode 100644 index 0000000..70c3b4a --- /dev/null +++ b/views/model.haml @@ -0,0 +1,4 @@ +%h2= @model.name +%dl + %dt Status: + %dd @model.status diff --git a/views/predict.haml b/views/predict.haml index 5c93e46..8c4317d 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -15,7 +15,8 @@ - yaml = RestClient.get model, :accept => 'application/x-yaml' - yaml = YAML.load yaml %label{:for => model} - = yaml[:endpoint].split(/#/).last.gsub(/_/,' ') + = URI.decode yaml[:endpoint].split(/#/).last + =# link_to RestClient.get(File.join(model,'name')).to_s, "/model?uri=#{URI.encode model}" %input{:type => 'checkbox', :name => "selection[#{model}]", :value => true, :id => model} %br diff --git a/views/prediction.haml b/views/prediction.haml index 241b01c..8e63f0f 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -9,7 +9,8 @@ - @predictions.each do |p| %td %b - = p[:title].gsub(/_/,' ') + ":" + =# p[:title].gsub(/_/,' ') + ":" + = p[:title] + ":" - if p[:measured_activities].size > 0 %br - p[:measured_activities].each do |a| -- cgit v1.2.3 From ff9366f454c909e525d6ae41635a7320235a3d74 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 16 Feb 2010 20:02:14 +0100 Subject: typo fixed in flash[:notice] --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 3617026..114e4d9 100644 --- a/application.rb +++ b/application.rb @@ -125,7 +125,7 @@ post '/upload' do # create a new model dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) - @notice = "Model creation for #{params[:endpoint]}i (#{nr_compounds} compounds) started - this may take some time (up to several hours for large datasets). As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." + @notice = "Model creation for #{params[:endpoint]} (#{nr_compounds} compounds) started - this may take some time (up to several hours for large datasets). As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." if smiles_errors.size > 0 @notice += "

The following Smiles structures were not readable and have been ignored:

" -- cgit v1.2.3 From 1b9f0c10b6ad1c38be1fa384bc1b6af9beea477b Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 17 Feb 2010 20:50:59 +0100 Subject: new styling, csv format check, logo --- application.rb | 16 +++++++++----- views/create.haml | 6 +++--- views/csv_format.haml | 12 +++++++---- views/layout.haml | 5 +++-- views/predict.haml | 2 ++ views/prediction.haml | 4 +++- views/style.sass | 59 +++++++++++++++++++++++++++++++++++++++------------ 7 files changed, 75 insertions(+), 29 deletions(-) diff --git a/application.rb b/application.rb index 114e4d9..f5833fd 100644 --- a/application.rb +++ b/application.rb @@ -80,10 +80,12 @@ post '/upload' do # create a new model flash[:notice] = "Please enter an endpoint name and upload a CSV file." redirect url_for('/create') end +=begin unless params[:file][:type] == "text/csv" flash[:notice] = "Please upload a CSV file - at present we cannot handle other file types." redirect url_for('/create') end +=end #@model = ToxPredictModel.new #@model.name = params[:endpoint] #@model.status = "started" @@ -99,6 +101,10 @@ post '/upload' do # create a new model nr_compounds = 0 line_nr = 1 params[:file][:tempfile].each_line do |line| + unless line.chomp.match(/^.+,.+$/) # check CSV format - not all browsers provide correct content-type + flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." + redirect url_for('/create') + end items = line.chomp.split(/\s*,\s*/) smiles = items[0] c = OpenTox::Compound.new(:smiles => smiles) @@ -125,7 +131,7 @@ post '/upload' do # create a new model dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) - @notice = "Model creation for #{params[:endpoint]} (#{nr_compounds} compounds) started - this may take some time (up to several hours for large datasets). As soon as the has been finished it will appear in the list below, if you #{link_to("reload this page", "/predict")}." + @notice = "Model creation for #{params[:endpoint]} (#{nr_compounds} compounds) started - this may take some time (up to several hours for large datasets). As soon as the model is ready it will appear in the list below, if you #{link_to("reload this page", "/predict")}." if smiles_errors.size > 0 @notice += "

The following Smiles structures were not readable and have been ignored:

" @@ -151,16 +157,16 @@ end post '/predict/?' do # post chemical name to model @identifier = params[:identifier] + unless params[:selection] and params[:identifier] != '' + flash[:notice] = "Please enter a compound identifier and select an endpoint from the list." + redirect url_for('/predict') + end begin @compound = OpenTox::Compound.new(:name => params[:identifier]) rescue flash[:notice] = "Could not find a structure for '#{@identifier}'. Please try again." redirect url_for('/predict') end - unless params[:selection] - flash[:notice] = "Please select an endpoint from the list!" - redirect url_for('/predict') - end @predictions = [] params[:selection].keys.each do |uri| prediction = nil diff --git a/views/create.haml b/views/create.haml index 448526f..dcb512a 100644 --- a/views/create.haml +++ b/views/create.haml @@ -3,13 +3,13 @@ %p This service creates %a{:href => 'http://lazar.in-silico.de'} lazar - prediction models (more model building algorithms will follow) from your uploaded datasets. Here are + classification models (more model building algorithms will follow) from your uploaded datasets. Here are = link_to "instructions", '/csv_format' - , how to create training datasets in Excel. + , for creating training datasets in Excel. %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } %fieldset - %legend + -#%legend Upload training data and create a %a{:href => 'http://lazar.in-silico.de'} lazar model diff --git a/views/csv_format.haml b/views/csv_format.haml index b093499..70ea50f 100644 --- a/views/csv_format.haml +++ b/views/csv_format.haml @@ -2,9 +2,9 @@ %p The input file should contain two columns, separated by a comma. Enter in the first column the chemical structure in = link_to "SMILES", "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification" - format, in the second column the activity classification (1: active, 0: inactive). -%p Example: -%p + format, in the second column the activity classification (1: active, 0: inactive), e.g. + +.code %code %br CC(=O)Nc1ccc(O)cc1, 1 %br O=c1[nH]cnc2[nH]ncc12, 1 @@ -16,4 +16,8 @@ %br CC(C)(C)NCC(O)COc1cccc2CC(O)C(O)Cc12, 0 %br CN1CCCC1c2cccnc2, 0 -%p You can create input files in Excel and export them as CSV files with the "Save As" option from the menu, selecting the CSV (comma delimited) format. +%p + Here is an example for download: + = link_to "hamster_carcinogenicity.csv", "/hamster_carcinogenicity.csv" + +%p You can create input files in Excel: Create a sheet with two columns and export them as CSV file with the "Save As" option from the menu, selecting the CSV (comma delimited) format. diff --git a/views/layout.haml b/views/layout.haml index 4bec328..223ab85 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -3,11 +3,12 @@ %head %meta{'http-equiv' => 'Content-Type', :content => 'text/html'} - %title ToxModel + %title ToxCreate %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body - %h1 ToxCreate + -# %h1 ToxCreate + = image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate' .index %ul diff --git a/views/predict.haml b/views/predict.haml index 8c4317d..9e5af79 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -1,4 +1,6 @@ .input + %p This service makes predictions with OpenTox models. + %p Click on a model to obtain detailed model information (training data, validation results, ...). - unless @models.nil? %form{ :action => url_for('/predict'), :method => "post", :enctype => "multipart/form-data" } %fieldset diff --git a/views/prediction.haml b/views/prediction.haml index 8e63f0f..7912ada 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -2,10 +2,12 @@ = link_to "New prediction", "/predict" .predictions %table + %tr + %th{:colspan => @predictions.size+1} + = @identifier %tr %th %img{:src => @compound.image_uri, :alt => @compound.smiles} - %br= @identifier - @predictions.each do |p| %td %b diff --git a/views/style.sass b/views/style.sass index 9de3d11..1952ca1 100644 --- a/views/style.sass +++ b/views/style.sass @@ -1,24 +1,38 @@ -!bg_color = #FFFFF3 -!fg_color = #36648B -!body_color = #ECF1EF +/* + !bg_color = #FFFFF3 + !fg_color = #36648B + !body_color = #ECF1EF + !text_color = black + +!bg_color = #DDFFFF +//#97FFFF +//#ECF1EF +!fg_color = #5D308A +!body_color = white !text_color = black body min-width: 30em font-family: Verdana + //font-family: Helvetica + font-size: 14px background-color = !body_color color = !text_color - height: 100% + //height: 100% padding: 1em - h1 + //h1 text-align: right color = !fg_color margin: 0 padding: 0 background-color = !body_color + img + float: right + height: 4em .index + clear: both ul margin: 0 @@ -31,9 +45,9 @@ body padding: 0 display: inline border-right: 1px solid - color = !bg_color + color = !body_color border-top: 1px solid - color = !bg_color + color = !body_color background-color = !fg_color padding-left: 0.5em padding-right: 0.5em @@ -58,20 +72,28 @@ body .content background-color = !bg_color height: 100% - padding: 0.5em + //padding: 0.5em + //margin: 1% + padding: 1em border: 1px solid color = !fg_color .notice - background-color = !body_color - margin: 2% - padding: 1% + //background-color = !body_color + padding: 1em + background-color: #F4F4F4 border: 1px solid red .input text-align: left form + padding: 1em + background-color: #F4F4F4 + border: 1px solid + color = !fg_color fieldset + margin: 0 + padding: 0 border: 0 legend font-weight: bold @@ -83,21 +105,30 @@ body br clear: both + .code + border: 1px solid black + padding: 1% + background-color: white + .predictions :text-align center table - background-color: white :border-spacing 0 :border-collapse collapse :margin 0 - :border 1px solid th - :border 0 + color = !body_color + background-color = !fg_color + border: 1px solid :margin 2% td :border 1px solid + background-color: #F4F4F4 :padding 2% + img + padding: 0 + height: 100% .footer margin: 0.5em -- cgit v1.2.3 From 757ac0ba1fed803ecfc0c9a1ef632e615484a91a Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 17 Feb 2010 20:55:53 +0100 Subject: ToxCreate logo added --- public/ToxCreate_rgb_72.png | Bin 0 -> 5978 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/ToxCreate_rgb_72.png diff --git a/public/ToxCreate_rgb_72.png b/public/ToxCreate_rgb_72.png new file mode 100644 index 0000000..4b96882 Binary files /dev/null and b/public/ToxCreate_rgb_72.png differ -- cgit v1.2.3 From 53af6c563627bdb69eeceefecf2dc9ca62bd052e Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 18 Feb 2010 15:44:10 +0100 Subject: model information added --- application.rb | 131 ++++++++++++++++++++++++----------------------------- views/layout.haml | 14 ++---- views/model.haml | 4 -- views/models.haml | 20 ++++++++ views/predict.haml | 17 ++----- views/style.sass | 35 +++++++------- 6 files changed, 105 insertions(+), 116 deletions(-) delete mode 100644 views/model.haml create mode 100644 views/models.haml diff --git a/application.rb b/application.rb index f5833fd..229a352 100644 --- a/application.rb +++ b/application.rb @@ -10,18 +10,21 @@ require 'sinatra/static_assets' use Rack::Flash set :sessions, true -#class ToxPredictModel -# include DataMapper::Resource -# property :id, Serial -# property :name, String -# property :uri, String, :length => 255 -# property :task_uri, String, :length => 255 -# property :status, String, :length => 255 -# property :messages, Text, :length => 2**32-1 -# property :created_at, DateTime -#end - -#DataMapper.auto_upgrade! +class ToxCreateModel + include DataMapper::Resource + property :id, Serial + property :name, String + property :uri, String, :length => 255 + property :task_uri, String, :length => 255 + property :messages, Text, :length => 2**32-1 + property :created_at, DateTime + + def status + RestClient.get File.join(self.task_uri, 'status') + end +end + +DataMapper.auto_upgrade! helpers do def activity(a) @@ -41,15 +44,23 @@ get '/?' do redirect url_for('/create') end -get '/model/:id/?' do - #@model = ToxPredictModel.get(params[:id]) - @model = YAML.load(RestClient.get params[:uri], :accept => "application/x-yaml") - haml :model +get '/models/?' do + @models = ToxCreateModel.all(:order => [ :created_at.desc ]) + @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) + haml :models +end + +get '/model/:id/delete/?' do + model = ToxCreateModel.get(params[:id]) + RestClient.delete model.uri if model.uri + RestClient.delete model.task_uri if model.task_uri + model.destroy! + redirect url_for('/predict') end get '/predict/?' do - #@models = ToxPredictModel.all - @models = OpenTox::Model::Lazar.find_all + @models = ToxCreateModel.all + @models = @models.collect{|m| m if m.status == 'completed'}.compact haml :predict end @@ -80,16 +91,8 @@ post '/upload' do # create a new model flash[:notice] = "Please enter an endpoint name and upload a CSV file." redirect url_for('/create') end -=begin - unless params[:file][:type] == "text/csv" - flash[:notice] = "Please upload a CSV file - at present we cannot handle other file types." - redirect url_for('/create') - end -=end - #@model = ToxPredictModel.new - #@model.name = params[:endpoint] - #@model.status = "started" - #@model.save + @model = ToxCreateModel.new + @model.name = params[:endpoint] title = URI.encode params[:endpoint]#.gsub(/\s+/,'_') dataset = OpenTox::Dataset.new dataset.title = title @@ -130,28 +133,27 @@ post '/upload' do # create a new model end dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) + @model.task_uri = task_uri - @notice = "Model creation for #{params[:endpoint]} (#{nr_compounds} compounds) started - this may take some time (up to several hours for large datasets). As soon as the model is ready it will appear in the list below, if you #{link_to("reload this page", "/predict")}." + @model.messages = "#{nr_compounds} compounds" if smiles_errors.size > 0 - @notice += "

The following Smiles structures were not readable and have been ignored:

" - @notice += smiles_errors.join("
") + @model.messages += "

Incorrect Smiles structures (ignored):

" + @model.messages += smiles_errors.join("
") end if activity_errors.size > 0 - @notice += "

The following structures had irregular activities and have been ignored (please use 1 for active and 0 for inactive compounds):

" - @notice += activity_errors.join("
") + @model.messages += "

Irregular activities (ignored - please use 1 for active and 0 for inactive compounds):

" + @model.messages += activity_errors.join("
") end duplicate_warnings = '' duplicates.each {|inchi,lines| duplicate_warnings += "

#{lines.join('
')}

" if lines.size > 1 } LOGGER.debug duplicate_warnings unless duplicate_warnings == '' - @notice += "

The following structures were duplicated in the dataset (this is not a problem for the algorithm, but you should make sure, that the results were obtained from independent experiments):

" - @notice += duplicate_warnings + @model.messages += "

Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):

" + @model.messages += duplicate_warnings end - session[:task_uri] = task_uri - #redirect url_for('/predict') - @models = OpenTox::Model::Lazar.find_all - haml :predict + @model.save + redirect url_for('/models') end @@ -168,50 +170,35 @@ post '/predict/?' do # post chemical name to model redirect url_for('/predict') end @predictions = [] - params[:selection].keys.each do |uri| + LOGGER.debug params[:selection].to_yaml + params[:selection].keys.each do |id| + model = ToxCreateModel.get(id.to_i) + unless model.uri + model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s + model.save + end + LOGGER.debug model.to_yaml prediction = nil confidence = nil title = nil db_activities = [] - prediction = RestClient.post uri, :compound_uri => @compound.uri#, :accept => "application/x-yaml" - model = Redland::Model.new Redland::MemoryStore.new + prediction = RestClient.post model.uri, :compound_uri => @compound.uri#, :accept => "application/x-yaml" + redland_model = Redland::Model.new Redland::MemoryStore.new parser = Redland::Parser.new - parser.parse_string_into_model(model,prediction,'/') - yaml = RestClient.get uri, :accept => 'application/x-yaml' - yaml = YAML.load yaml - title = URI.decode yaml[:endpoint].split(/#/).last - #f = model.subject(RDF['type'],OT['Feature']) # this can be dangerous if OWL is not properly sorted - #title = RestClient.get(File.join(uri,"name")).to_s - #title = model.object(f,DC['title']).to_s - model.subjects(RDF['type'], OT['FeatureValue']).each do |v| - feature = model.object(v,OT['feature']) - feature_name = model.object(feature,DC['title']).to_s - prediction = model.object(v,OT['value']).to_s if feature_name.match(/classification/) - confidence = model.object(v,OT['value']).to_s if feature_name.match(/confidence/) - db_activities << model.object(v,OT['value']).to_s if feature_name.match(/#{title}/) + parser.parse_string_into_model(redland_model,prediction,'/') + title = model.name + redland_model.subjects(RDF['type'], OT['FeatureValue']).each do |v| + feature = redland_model.object(v,OT['feature']) + feature_name = redland_model.object(feature,DC['title']).to_s + prediction = redland_model.object(v,OT['value']).to_s if feature_name.match(/classification/) + confidence = redland_model.object(v,OT['value']).to_s if feature_name.match(/confidence/) + db_activities << redland_model.object(v,OT['value']).to_s if feature_name.match(/#{title}/) end @predictions << {:title => title, :prediction => prediction, :confidence => confidence, :measured_activities => db_activities} end LOGGER.debug @predictions.to_yaml haml :prediction - #@predictions.to_yaml -end - -post '/task/cancel' do - puts params[:task_uri] - task = OpenTox::Task.find(params[:task_uri]) - task.cancel - redirect url_for('/tasks') -end - -delete '/:id' do - #begin - OpenTox::Model::LazarClassification.delete(params[:id]) - haml :index - #rescue - #"Deletion of model with ID #{params[:id]} failed. Please check your username and password." - #end end # SASS stylesheet diff --git a/views/layout.haml b/views/layout.haml index 223ab85..32b7853 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -3,21 +3,22 @@ %head %meta{'http-equiv' => 'Content-Type', :content => 'text/html'} + - if @refresh + %meta{'http-equiv' => "refresh", :content => "15"} %title ToxCreate %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body - -# %h1 ToxCreate = image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate' .index %ul %li{:class => ("selected" if /create/ =~ request.path )} = link_to "Create", "/create" + %li{:class => ("selected" if /models/ =~ request.path )} + = link_to "Inspect", "/models" %li{:class => ("selected" if /predict/ =~ request.path )} = link_to "Predict", "/predict" - -#%li{:class => ("selected" if /tasks/ =~ request.path )} - = link_to "Tasks", "/tasks" %li{:class => ("selected" if /about/ =~ request.path )} = link_to "About", "/about" @@ -28,13 +29,10 @@ %a{:href => 'http://github.com/helma/opentox-toxmodel/issues'} issue tracker. - if flash[:notice] + %p .notice = flash[:notice] - - if @notice - .notice - = @notice - = yield .footer @@ -42,5 +40,3 @@ %a{:href => 'http://www.in-silico.ch'} in silico toxicology 2009, powered by %a{:href => 'http://www..opentox.org'} OpenTox - -# image_tag("/opentox_logo.png", :alt => "OpenTox") - diff --git a/views/model.haml b/views/model.haml deleted file mode 100644 index 70c3b4a..0000000 --- a/views/model.haml +++ /dev/null @@ -1,4 +0,0 @@ -%h2= @model.name -%dl - %dt Status: - %dd @model.status diff --git a/views/models.haml b/views/models.haml new file mode 100644 index 0000000..9cf2bd6 --- /dev/null +++ b/views/models.haml @@ -0,0 +1,20 @@ +%p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. +- @models.each do |model| + %h2 + = model.name + %dl + %dt Status: + %dd + = model.status + ( + = link_to "delete", "/model/#{model.id}/delete" + ) + %dt Started: + %dd= model.created_at + %dt Details: + %dd= model.messages + %dt Validation: + %dd + %em + to be added + diff --git a/views/predict.haml b/views/predict.haml index 9e5af79..ae8a167 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -1,7 +1,6 @@ .input - %p This service makes predictions with OpenTox models. - %p Click on a model to obtain detailed model information (training data, validation results, ...). - - unless @models.nil? + %p Use this service to obtain predictions from OpenTox models. + - unless @models.empty? %form{ :action => url_for('/predict'), :method => "post", :enctype => "multipart/form-data" } %fieldset %legend Enter a compound identifier @@ -10,16 +9,10 @@ %fieldset %legend Choose one or more prediction models - ( - = link_to 'Reload', '/predict' - ) - @models.each do |model| - - yaml = RestClient.get model, :accept => 'application/x-yaml' - - yaml = YAML.load yaml - %label{:for => model} - = URI.decode yaml[:endpoint].split(/#/).last - =# link_to RestClient.get(File.join(model,'name')).to_s, "/model?uri=#{URI.encode model}" - %input{:type => 'checkbox', :name => "selection[#{model}]", :value => true, :id => model} + %label{:for => model.id} + = model.name + %input{:type => 'checkbox', :name => "selection[#{model.id}]", :value => true, :id => model.id} %br %input{ :type => "submit", :value => "Predict"} diff --git a/views/style.sass b/views/style.sass index 1952ca1..3c62eab 100644 --- a/views/style.sass +++ b/views/style.sass @@ -1,12 +1,5 @@ -/* - !bg_color = #FFFFF3 - !fg_color = #36648B - !body_color = #ECF1EF - !text_color = black - !bg_color = #DDFFFF -//#97FFFF -//#ECF1EF +!bg_color2 = #F4F4F4 !fg_color = #5D308A !body_color = white !text_color = black @@ -14,19 +7,11 @@ body min-width: 30em font-family: Verdana - //font-family: Helvetica font-size: 14px background-color = !body_color color = !text_color - //height: 100% padding: 1em - //h1 - text-align: right - color = !fg_color - margin: 0 - padding: 0 - background-color = !body_color img float: right height: 4em @@ -81,14 +66,14 @@ body .notice //background-color = !body_color padding: 1em - background-color: #F4F4F4 + background-color = !bg_color2 border: 1px solid red .input text-align: left form padding: 1em - background-color: #F4F4F4 + background-color = !bg_color2 border: 1px solid color = !fg_color fieldset @@ -124,12 +109,24 @@ body :margin 2% td :border 1px solid - background-color: #F4F4F4 + background-color = !bg_color2 :padding 2% img padding: 0 height: 100% + dl + padding: 1em + background-color = !bg_color2 + border: 1px solid + dt + width: 10em + font-weight: bold + float: left + clear: left + dd + //padding-left: 2em + .footer margin: 0.5em padding: 0.5em -- cgit v1.2.3 From 479680eeec4ffc1a5d2a39359995949704393064 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 19 Feb 2010 11:39:35 +0100 Subject: example csv added --- public/hamster_carcinogenicity.csv | 85 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 public/hamster_carcinogenicity.csv diff --git a/public/hamster_carcinogenicity.csv b/public/hamster_carcinogenicity.csv new file mode 100644 index 0000000..e9ca269 --- /dev/null +++ b/public/hamster_carcinogenicity.csv @@ -0,0 +1,85 @@ +CC=O,1 +C12C3=C(C=CC=C3)CC1=CC(=CC=2)NC(C)=O,1 +O=C(N)\C(C2=CC=CO2)=C/C1=CC=C([N+]([O-])=O)O1,1 +C1(N=CNN=1)N,0 +Br(=O)(=O)[O-].[K+],1 +[Cl-].[Cd+2].[Cl-],0 +O=S(=O)([O-])[O-].[Cd+2],0 +ClC1=CC(=NC(=N1)SCC(=O)O)NC2=CC=CC(=C2C)C,0 +ClCOC,1 +C=C(Cl)C=C,0 +Clc1ccc(cc1)c2ccc(COC(C)(C)C(O)=O)cc2,0 +O=C1OC2=C(C=CC=C2)C=C1,0 +ClC(=C(C1=CC=C(C=C1)Cl)C2=CC=C(C=C2)Cl)Cl,1 +ClC(C(C1=CC=C(C=C1)Cl)C2=CC=C(C=C2)Cl)(Cl)Cl,0 +C=CCN(CC=C)N=O,1 +Cl\C2=C(/Cl)C3(Cl)C1C4CC(C1C2(Cl)C3(Cl)Cl)C5OC45,0 +O=C(N(C)C)Cl,1 +CN(C)N,1 +N(NC)C.[H]Cl.[H]Cl,1 +CCO,0 +O=C(N(CC)N=O)NCCO,1 +O=C(N(CC)N=O)NCC(=O)C,1 +C=O,0 +[O-][N+](=O)C1=CC=C(O1)C2=CSC(=N2)NNC=O,1 +O=CC1=CC=CO1,0 +OCC1CO1,1 +O=C2C1=C(OC)C=C(OC)C(Cl)=C1O[C@]32C(OC)=CC(C[C@@](C)3[H])=O,0 +ClC1=C(C(=C(C(=C1Cl)Cl)Cl)Cl)Cl,1 +NN,1 +OS(=O)(=O)O.NN,1 +CC(=O)N(O)C1=CC2=C(C=C1)C3=CC=CC=C3C2,1 +OCCNN,0 +O=C(C1=CC=NC=C1)NN,0 +OC(=O)C1=CC=NC=C1,0 +O=C(NC1=CC=CC(=C1)Cl)OC(C)C,0 +O=C(NC1=CC=CC=C1)OC(C)C,0 +[O-]C(C)=O.[O-]C(C)=O.[Pb+2].[OH-].[OH-].[Pb+2].[OH-].[OH-].[Pb+2],0 +CN(C)CCN(CC2=CC=CS2)C1=NC=CC=C1.Cl,0 +NC1=C2C(=NC(=N1)N)N=CC(=N2)CN(C3=CC=C(C=C3)C(=O)N[C@@H](CCC(=O)O)C(=O)O)C,0 +CN(N)C=O,1 +O=C(C(=C)C)OC,0 +CNN,1 +O=C(C1=CC=CN=C1)CCCN(N=O)C,0 +CC1=CC(=O)NC(=S)N1,1 +CC(C(O)=O)(OC1=CC=C(C=C1)C2CCCC3=C2C=CC=C3)C,0 +O=N[O-].[Na+],0 +[O-][N+](C1=CC=C(C2=CSC(NC(C)=O)=N2)O1)=O,1 +[O-][N+](=O)C1=CC=C(O1)C2=CSC(=N2)NC=O,1 +O=[N+](C1=CC=C2C3=C1C=CC=C3CC2)[O-],0 +N(CC(CO)O)(CC(O)C)N=O,1 +N(CC(CO)O)(CC(C)=O)N=O,1 +N(CC(CO)O)(CCO)N=O,0 +O=C(C)CN(N=O)CCO,1 +C1C(N(C(CN1N=O)C)C)C,1 +N(CC(C)=O)(CC=C)N=O,1 +N(CC(CO)O)(C)N=O,1 +O=NN1CCOCC1,1 +N1C=CC=C(C=1)C2N(N=O)CCC2,1 +C1=CC=C(C=[N+]1[O-])C2CCCN2N=O,0 +O=NN1CCCCC1,1 +O=NN1CCCC1,1 +O=C(N(CC(C)=O)N=O)NCCCl,1 +N(C(=O)N)(N=O)CC(C)=O,1 +C1(CCN=C=S)=CC=CC=C1,0 +O=C1C(C2=CC=CC=C2)(C(=O)NC(=O)N1)CC,0 +C1=C2C(=CC=C1NC3=CC=CC=C3)C=CC=C2,0 +O=C1N2C(C3=C(C=CC=C3)CC2)CN(C1)C(=O)C4CCCCC4,0 +C1(=CC(=C(O)C=C1)O)C(O)=O,0 +O=C1C2=C(C=C(C=C2O)O)O/C(=C\1O)C3=CC(=C(C=C3)O)O.O.O,0 +C1=C(C=CC(=C1)C(C2=CC=C(N)C(=C2)C)=C3C=CC(=N)C=C3)N.[H]Cl,0 +C(C1=CC=C(C=C1)N)(C2=CC=C(C=C2)N)=C3C=CC(C=C3)=N.[H]Cl,0 +OC2=CC1=C(C(O)=C2)C(C(O[C@@H]4O[C@@H]([C@H]([C@H](O)[C@H]4O)O)CO[C@H]3[C@H](O)[C@H](O)[C@H]([C@H](C)O3)O)=C(C5=CC(O)=C(C=C5)O)O1)=O,0 +ClC(=CCl)Cl,0 +NC(=O)OCC,1 +C=CCl,1 +N#[N+]C1=CC=CC=C1.F[B-](F)(F)F,0 +C1(CN(CC(N1N=O)C)N=O)C,1 +N(CCN(C)C)(C)N=O,1 +C1(CN(N=O)CC(O1)C)C,1 +O1C(N(CC1C)N=O)=O,1 +CCOC(=O)N(C)N=O,1 +C1N(COC1)N=O,1 +O=C(N(CCC1=CC=CC=C1)N=O)N,1 +O=NN1CCC1,1 +F[B-](F)(F)F.[Na+],0 -- cgit v1.2.3 From 038f3bce2ea08481d8311fddf9150741dd308f74 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 19 Feb 2010 14:31:40 +0100 Subject: mime types added to response header --- views/models.haml | 5 ++++- views/style.sass | 11 +++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/views/models.haml b/views/models.haml index 9cf2bd6..cb24f86 100644 --- a/views/models.haml +++ b/views/models.haml @@ -7,12 +7,15 @@ %dd = model.status ( - = link_to "delete", "/model/#{model.id}/delete" + %a{:href => url_for("/model/#{model.id}/delete"), :onclick => 'return confirm("Are you sure?");'} delete ) %dt Started: %dd= model.created_at %dt Details: %dd= model.messages + %dt URI: + %dd + %a{:href => model.uri, :accept => "application/rdf+xml"} #{model.uri} %dt Validation: %dd %em diff --git a/views/style.sass b/views/style.sass index 3c62eab..f2698a7 100644 --- a/views/style.sass +++ b/views/style.sass @@ -1,9 +1,16 @@ -!bg_color = #DDFFFF -!bg_color2 = #F4F4F4 +!bg_color = #B7FEFA +!bg_color2 = #DDDDDD !fg_color = #5D308A !body_color = white !text_color = black +/* + !bg_color = #DDFFFF + !bg_color2 = #F4F4F4 + !fg_color = #5D308A + !body_color = white + !text_color = black + body min-width: 30em font-family: Verdana -- cgit v1.2.3 From 5d1f8133e79d803a151a52fbc3fbc5aac1282758 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 22 Feb 2010 17:31:27 +0100 Subject: redirect for delete fixed --- application.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 229a352..7257f3f 100644 --- a/application.rb +++ b/application.rb @@ -51,11 +51,15 @@ get '/models/?' do end get '/model/:id/delete/?' do + redirect url_for("/model/#{params[:id]}") +end + +delete '/model/:id/?' do model = ToxCreateModel.get(params[:id]) RestClient.delete model.uri if model.uri RestClient.delete model.task_uri if model.task_uri model.destroy! - redirect url_for('/predict') + redirect url_for('/models') end get '/predict/?' do -- cgit v1.2.3 From 88e78774eb287f50c1a9faa52a53bda1cc112a7e Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 23 Feb 2010 17:48:53 +0100 Subject: some test issues resolved --- application.rb | 46 +++++++++++++++++++++++++--------------------- views/create.haml | 4 ++-- views/layout.haml | 4 ++-- views/models.haml | 17 ++++++++++++++++- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/application.rb b/application.rb index 720e8c4..2ee2209 100644 --- a/application.rb +++ b/application.rb @@ -46,24 +46,30 @@ end get '/models/?' do @models = ToxCreateModel.all(:order => [ :created_at.desc ]) + @models.each do |model| + if !model.uri and model.status == "completed" + model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s + model.save + end + end @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) haml :models end get '/model/:id/delete/?' do - redirect url_for("/model/#{params[:id]}") -end - -delete '/model/:id/?' do model = ToxCreateModel.get(params[:id]) - RestClient.delete model.uri if model.uri - RestClient.delete model.task_uri if model.task_uri + begin + RestClient.delete model.uri if model.uri + RestClient.delete model.task_uri if model.task_uri + rescue + end model.destroy! + flash[:notice] = "#{model.name} model deleted." redirect url_for('/models') end get '/predict/?' do - @models = ToxCreateModel.all + @models = ToxCreateModel.all(:order => [ :created_at.desc ]) @models = @models.collect{|m| m if m.status == 'completed'}.compact haml :predict end @@ -91,6 +97,11 @@ get '/task' do end post '/upload' do # create a new model + LOGGER.debug "ENDPOINT '#{params[:endpoint]}'" + if params[:endpoint] == '' + flash[:notice] = "Please enter an endpoint name." + redirect url_for('/create') + end unless params[:endpoint] and params[:file] and params[:file][:tempfile] flash[:notice] = "Please enter an endpoint name and upload a CSV file." redirect url_for('/create') @@ -108,7 +119,7 @@ post '/upload' do # create a new model nr_compounds = 0 line_nr = 1 params[:file][:tempfile].each_line do |line| - unless line.chomp.match(/^.+,.+$/) # check CSV format - not all browsers provide correct content-type + unless line.chomp.match(/^.+,.*$/) # check CSV format - not all browsers provide correct content-type flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." redirect url_for('/create') end @@ -120,6 +131,7 @@ post '/upload' do # create a new model duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp compound_uri = c.uri compound = dataset.find_or_create_compound(compound_uri) + #activity_errors << "Empty activity at line #{line_nr}: " + line.chomp unless items.size == 2 # empty activity value case items[1].to_s when '1' dataset.add(compound,feature,true) @@ -170,30 +182,22 @@ post '/predict/?' do # post chemical name to model begin @compound = OpenTox::Compound.new(:name => params[:identifier]) rescue - flash[:notice] = "Could not find a structure for '#{@identifier}'. Please try again." + flash[:notice] = "Could not find a structure for '#{URI.encode @identifier}'. Please try again." redirect url_for('/predict') end @predictions = [] LOGGER.debug params[:selection].to_yaml params[:selection].keys.each do |id| model = ToxCreateModel.get(id.to_i) - unless model.uri - model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s - model.save - end LOGGER.debug model.to_yaml prediction = nil confidence = nil title = nil -<<<<<<< HEAD db_activities = [] - prediction = RestClient.post model.uri, :compound_uri => @compound.uri#, :accept => "application/x-yaml" + #prediction = RestClient.post model.uri, :compound_uri => @compound.uri#, :accept => "application/x-yaml" + resource = RestClient::Resource.new(model.uri, :user => @@users[:users].keys[0], :password => @@users[:users].values[0]) + prediction = resource.post :compound_uri => @compound.uri#, :accept => "application/x-yaml" redland_model = Redland::Model.new Redland::MemoryStore.new -======= - resource = RestClient::Resource.new(uri, :user => @@users[:users].keys[0], :password => @@users[:users].values[0]) - prediction = resource.post :compound_uri => @compound.uri, :accept => "application/x-yaml" - model = Redland::Model.new Redland::MemoryStore.new ->>>>>>> micha/test parser = Redland::Parser.new parser.parse_string_into_model(redland_model,prediction,'/') title = model.name @@ -207,7 +211,7 @@ post '/predict/?' do # post chemical name to model @predictions << {:title => title, :prediction => prediction, :confidence => confidence, :measured_activities => db_activities} end - LOGGER.debug @predictions.to_yaml + LOGGER.debug @predictions.to_yaml haml :prediction end diff --git a/views/create.haml b/views/create.haml index dcb512a..99cffb3 100644 --- a/views/create.haml +++ b/views/create.haml @@ -14,13 +14,13 @@ %a{:href => 'http://lazar.in-silico.de'} lazar model %label{:for => 'endpoint'} 1. Enter a name for your endpoint: - %input{:type => 'text', :name => 'endpoint', :id => 'endpoint'} + %input{:type => 'text', :name => 'endpoint', :id => 'endpoint', :size => '50'} %br %label{:for => 'file'} 2. Upload training data in = link_to "CSV", '/csv_format' format: - %input{:type => 'file', :name => 'file', :id => 'file'} + %input{:type => 'file', :name => 'file', :id => 'file', :size => '41'} %input{ :type => "submit", :value => "Create model"} = link_to "Cancel", 'create' diff --git a/views/layout.haml b/views/layout.haml index 32b7853..9b748af 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -6,7 +6,7 @@ - if @refresh %meta{'http-equiv' => "refresh", :content => "15"} %title ToxCreate - %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} + %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body = image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate' @@ -38,5 +38,5 @@ .footer © %a{:href => 'http://www.in-silico.ch'} in silico toxicology - 2009, powered by + 2009-2010, powered by %a{:href => 'http://www..opentox.org'} OpenTox diff --git a/views/models.haml b/views/models.haml index cb24f86..e1c9404 100644 --- a/views/models.haml +++ b/views/models.haml @@ -1,7 +1,18 @@ +-# :javascript + function deletemodel(uri) { + var xmlhttp; + return confirm("Are you sure?"); + xmlhttp=new XMLHttpRequest(); + xmlhttp.open('DELETE',uri,false) + xmlhttp.send(null); + } + %p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. - @models.each do |model| + - uri = url_for("/model/#{model.id}", :full) %h2 = model.name + -#%button{:onclick => "deletemodel('#{uri}')"} delete %dl %dt Status: %dd @@ -15,7 +26,11 @@ %dd= model.messages %dt URI: %dd - %a{:href => model.uri, :accept => "application/rdf+xml"} #{model.uri} + - if model.uri + %a{:href => model.uri, :accept => "application/rdf+xml"} #{model.uri} + %em (model representation in OWL-DL - experts only) + - else + %em model under construction %dt Validation: %dd %em -- cgit v1.2.3 From b405040be177753523d16e7b919fba02bc26e61a Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 23 Feb 2010 17:56:41 +0100 Subject: name length set to 255 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 2ee2209..6a08059 100644 --- a/application.rb +++ b/application.rb @@ -13,7 +13,7 @@ set :sessions, true class ToxCreateModel include DataMapper::Resource property :id, Serial - property :name, String + property :name, String, :length => 255 property :uri, String, :length => 255 property :task_uri, String, :length => 255 property :messages, Text, :length => 2**32-1 -- cgit v1.2.3 From 4474b7c93ce24948903e0c303d8034cf4a0f4321 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 23 Feb 2010 18:08:30 +0100 Subject: input field for structure identifier expanded --- views/predict.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/predict.haml b/views/predict.haml index ae8a167..f69b583 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -5,7 +5,7 @@ %fieldset %legend Enter a compound identifier %label{:for => 'identifier'} Name, InChI, Smiles, CAS, ... - %input{:type => 'text', :name => 'identifier', :id => 'identifier'} + %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '50'} %fieldset %legend Choose one or more prediction models -- cgit v1.2.3 From 79da8456ea272ecc3076e5d0a115cb87fa4ef089 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 23 Feb 2010 18:37:31 +0100 Subject: warning for model name added --- views/create.haml | 3 +++ views/predict.haml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/views/create.haml b/views/create.haml index 99cffb3..cb7448f 100644 --- a/views/create.haml +++ b/views/create.haml @@ -15,6 +15,9 @@ model %label{:for => 'endpoint'} 1. Enter a name for your endpoint: %input{:type => 'text', :name => 'endpoint', :id => 'endpoint', :size => '50'} + %br + %em Please avoid whitespaces and special characters - this may lead to prediction errors. This limitation will be removed with one of the next updates, see + %a{:href => "http://github.com/helma/opentox-toxmodel/issues/#issue/16"} http://github.com/helma/opentox-toxmodel/issues/#issue/16 %br %label{:for => 'file'} 2. Upload training data in diff --git a/views/predict.haml b/views/predict.haml index f69b583..f6ddd76 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -6,7 +6,7 @@ %legend Enter a compound identifier %label{:for => 'identifier'} Name, InChI, Smiles, CAS, ... %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '50'} - %fieldset + %fieldset %legend Choose one or more prediction models - @models.each do |model| -- cgit v1.2.3 From 9d2b10c4e3301276d3cc9b53c1a0aaac9f1fd989 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 23 Feb 2010 18:41:26 +0100 Subject: fieldset identation fixed --- views/predict.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/predict.haml b/views/predict.haml index f6ddd76..f69b583 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -6,7 +6,7 @@ %legend Enter a compound identifier %label{:for => 'identifier'} Name, InChI, Smiles, CAS, ... %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '50'} - %fieldset + %fieldset %legend Choose one or more prediction models - @models.each do |model| -- cgit v1.2.3 From d1f5116ac7d67a99f5fe7b0882037f5f8af336f6 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 23 Feb 2010 19:16:11 +0100 Subject: URI encoding for endpoint name fixed to find training activities for endpoint names with special characters --- application.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/application.rb b/application.rb index 6a08059..c420398 100644 --- a/application.rb +++ b/application.rb @@ -182,14 +182,14 @@ post '/predict/?' do # post chemical name to model begin @compound = OpenTox::Compound.new(:name => params[:identifier]) rescue - flash[:notice] = "Could not find a structure for '#{URI.encode @identifier}'. Please try again." + flash[:notice] = "Could not find a structure for '#{@identifier}'. Please try again." redirect url_for('/predict') end @predictions = [] - LOGGER.debug params[:selection].to_yaml + #LOGGER.debug params[:selection].to_yaml params[:selection].keys.each do |id| model = ToxCreateModel.get(id.to_i) - LOGGER.debug model.to_yaml + #LOGGER.debug model.to_yaml prediction = nil confidence = nil title = nil @@ -197,6 +197,8 @@ post '/predict/?' do # post chemical name to model #prediction = RestClient.post model.uri, :compound_uri => @compound.uri#, :accept => "application/x-yaml" resource = RestClient::Resource.new(model.uri, :user => @@users[:users].keys[0], :password => @@users[:users].values[0]) prediction = resource.post :compound_uri => @compound.uri#, :accept => "application/x-yaml" + #LOGGER.debug "Prediction OWL-DL: " + #LOGGER.debug prediction redland_model = Redland::Model.new Redland::MemoryStore.new parser = Redland::Parser.new parser.parse_string_into_model(redland_model,prediction,'/') @@ -204,9 +206,10 @@ post '/predict/?' do # post chemical name to model redland_model.subjects(RDF['type'], OT['FeatureValue']).each do |v| feature = redland_model.object(v,OT['feature']) feature_name = redland_model.object(feature,DC['title']).to_s + #LOGGER.debug "DEBUG: #{feature_name}" prediction = redland_model.object(v,OT['value']).to_s if feature_name.match(/classification/) confidence = redland_model.object(v,OT['value']).to_s if feature_name.match(/confidence/) - db_activities << redland_model.object(v,OT['value']).to_s if feature_name.match(/#{title}/) + db_activities << redland_model.object(v,OT['value']).to_s if feature_name.match(/#{URI.encode title}/) end @predictions << {:title => title, :prediction => prediction, :confidence => confidence, :measured_activities => db_activities} end -- cgit v1.2.3 From b5be6ce52633fe3159a0daf1b13797c424aa4e38 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 23 Feb 2010 19:19:11 +0100 Subject: warning for endpoint name removed --- views/create.haml | 3 --- 1 file changed, 3 deletions(-) diff --git a/views/create.haml b/views/create.haml index cb7448f..99cffb3 100644 --- a/views/create.haml +++ b/views/create.haml @@ -15,9 +15,6 @@ model %label{:for => 'endpoint'} 1. Enter a name for your endpoint: %input{:type => 'text', :name => 'endpoint', :id => 'endpoint', :size => '50'} - %br - %em Please avoid whitespaces and special characters - this may lead to prediction errors. This limitation will be removed with one of the next updates, see - %a{:href => "http://github.com/helma/opentox-toxmodel/issues/#issue/16"} http://github.com/helma/opentox-toxmodel/issues/#issue/16 %br %label{:for => 'file'} 2. Upload training data in -- cgit v1.2.3 From 2ad8b8fa4581f32cf3732b67806094f2b634fc86 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 26 Feb 2010 00:29:44 +0100 Subject: iformation message for model building duration reinserted --- application.rb | 1 + views/layout.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index c420398..030694d 100644 --- a/application.rb +++ b/application.rb @@ -169,6 +169,7 @@ post '/upload' do # create a new model @model.messages += duplicate_warnings end @model.save + flash[:notice] = "Model creation started. Please be patient - model building may take up to several hours depending on the number and size of the input molecules." redirect url_for('/models') end diff --git a/views/layout.haml b/views/layout.haml index 9b748af..f68943b 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -39,4 +39,4 @@ © %a{:href => 'http://www.in-silico.ch'} in silico toxicology 2009-2010, powered by - %a{:href => 'http://www..opentox.org'} OpenTox + %a{:href => 'http://www.opentox.org'} OpenTox -- cgit v1.2.3 From 2f264679ea97a681160104b2fb309d240f0d0f76 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 26 Feb 2010 16:54:37 +0100 Subject: source file added to logger --- application.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/application.rb b/application.rb index 030694d..f2f2a3e 100644 --- a/application.rb +++ b/application.rb @@ -1,11 +1,11 @@ -['rubygems', "haml", "sass"].each do |lib| +['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -require 'rack-flash' gem 'opentox-ruby-api-wrapper', '= 1.2.7' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' +LOGGER.progname = File.expand_path __FILE__ use Rack::Flash set :sessions, true @@ -97,7 +97,7 @@ get '/task' do end post '/upload' do # create a new model - LOGGER.debug "ENDPOINT '#{params[:endpoint]}'" + #LOGGER.debug "ENDPOINT '#{params[:endpoint]}'" if params[:endpoint] == '' flash[:notice] = "Please enter an endpoint name." redirect url_for('/create') @@ -119,11 +119,11 @@ post '/upload' do # create a new model nr_compounds = 0 line_nr = 1 params[:file][:tempfile].each_line do |line| - unless line.chomp.match(/^.+,.*$/) # check CSV format - not all browsers provide correct content-type + unless line.chomp.match(/^.+[,;].*$/) # check CSV format - not all browsers provide correct content-type flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." redirect url_for('/create') end - items = line.chomp.split(/\s*,\s*/) + items = line.chomp.split(/\s*[,;]\s*/) smiles = items[0] c = OpenTox::Compound.new(:smiles => smiles) if c.inchi != "" @@ -163,7 +163,7 @@ post '/upload' do # create a new model end duplicate_warnings = '' duplicates.each {|inchi,lines| duplicate_warnings += "

#{lines.join('
')}

" if lines.size > 1 } - LOGGER.debug duplicate_warnings + #LOGGER.debug duplicate_warnings unless duplicate_warnings == '' @model.messages += "

Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):

" @model.messages += duplicate_warnings -- cgit v1.2.3 From 7977a6a2a2df973dadb3f0becd3c0022739a34fa Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 1 Mar 2010 10:19:34 +0100 Subject: initial intergration of validation services --- application.rb | 15 +++++++++++---- views/models.haml | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/application.rb b/application.rb index f2f2a3e..0687b51 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.2.7' +gem 'opentox-ruby-api-wrapper', '= 1.3.0' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' @@ -16,6 +16,7 @@ class ToxCreateModel property :name, String, :length => 255 property :uri, String, :length => 255 property :task_uri, String, :length => 255 + property :validation_task_uri, String, :length => 255 property :messages, Text, :length => 2**32-1 property :created_at, DateTime @@ -97,7 +98,6 @@ get '/task' do end post '/upload' do # create a new model - #LOGGER.debug "ENDPOINT '#{params[:endpoint]}'" if params[:endpoint] == '' flash[:notice] = "Please enter an endpoint name." redirect url_for('/create') @@ -108,7 +108,7 @@ post '/upload' do # create a new model end @model = ToxCreateModel.new @model.name = params[:endpoint] - title = URI.encode params[:endpoint]#.gsub(/\s+/,'_') + title = URI.encode params[:endpoint] dataset = OpenTox::Dataset.new dataset.title = title feature_uri = url_for("/feature#"+title, :full) @@ -131,7 +131,6 @@ post '/upload' do # create a new model duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp compound_uri = c.uri compound = dataset.find_or_create_compound(compound_uri) - #activity_errors << "Empty activity at line #{line_nr}: " + line.chomp unless items.size == 2 # empty activity value case items[1].to_s when '1' dataset.add(compound,feature,true) @@ -149,7 +148,15 @@ post '/upload' do # create a new model end dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) + validation_task_uri = OpenTox::Validation.crossvalidation( + :algorithm_uri => OpenTox::Algorithm::Lazar.uri, + :dataset_uri => dataset_uri, + :prediction_feature => feature_uri, + :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" + ).uri + LOGGER.debug "Validation task: " + validation_task_uri @model.task_uri = task_uri + @model.validation_task_uri = validation_task_uri @model.messages = "#{nr_compounds} compounds" diff --git a/views/models.haml b/views/models.haml index e1c9404..bdcaf8e 100644 --- a/views/models.haml +++ b/views/models.haml @@ -34,5 +34,5 @@ %dt Validation: %dd %em - to be added + = model.validation_task_uri -- cgit v1.2.3 From 03fcb5bdb1c4ce979fa5e026ef5943e6785e2500 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 1 Mar 2010 16:26:00 +0100 Subject: validation integrated --- application.rb | 12 ++++++++++++ views/models.haml | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 0687b51..ee0538d 100644 --- a/application.rb +++ b/application.rb @@ -17,12 +17,17 @@ class ToxCreateModel property :uri, String, :length => 255 property :task_uri, String, :length => 255 property :validation_task_uri, String, :length => 255 + property :validation_uri, String, :length => 255 property :messages, Text, :length => 2**32-1 property :created_at, DateTime def status RestClient.get File.join(self.task_uri, 'status') end + + def validation_status + RestClient.get File.join(self.validation_task_uri, 'status') + end end DataMapper.auto_upgrade! @@ -52,6 +57,13 @@ get '/models/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s model.save end + if !model.validation_uri and model.validation_status == "completed" + validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s + LOGGER.debug "Validation URI: #{validation_uri}" + model.validation_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s + LOGGER.debug "Validation Report URI: #{model.validation_uri}" + model.save + end end @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) haml :models diff --git a/views/models.haml b/views/models.haml index bdcaf8e..7b87f34 100644 --- a/views/models.haml +++ b/views/models.haml @@ -33,6 +33,10 @@ %em model under construction %dt Validation: %dd - %em + - if model.validation_uri + %a{:href => model.validation_uri, :accept => "text/html"} Details + - else + %em under construction = model.validation_task_uri + -- cgit v1.2.3 From 10d386896c55e5c608857324173cbb494d5b78b1 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 1 Mar 2010 16:44:37 +0100 Subject: REST DELETE added, validation task URI removed --- application.rb | 6 ++++++ views/models.haml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index ee0538d..19e4c94 100644 --- a/application.rb +++ b/application.rb @@ -238,6 +238,12 @@ post '/predict/?' do # post chemical name to model haml :prediction end +delete '/?' do + ToxCreateModel.auto_migrate! + response['Content-Type'] = 'text/plain' + "All Models deleted." +end + # SASS stylesheet get '/stylesheets/style.css' do headers 'Content-Type' => 'text/css; charset=utf-8' diff --git a/views/models.haml b/views/models.haml index 7b87f34..bd19ba8 100644 --- a/views/models.haml +++ b/views/models.haml @@ -37,6 +37,6 @@ %a{:href => model.validation_uri, :accept => "text/html"} Details - else %em under construction - = model.validation_task_uri + =# model.validation_task_uri -- cgit v1.2.3 From 1a75cab62bb941c106252a39efb350822dd49e38 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 2 Mar 2010 11:18:51 +0100 Subject: version bumped to 1.3.1 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 19e4c94..3b4d9fb 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.3.0' +gem 'opentox-ruby-api-wrapper', '= 1.3.1' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 741da4d314ed0277f3777b5254269b51e1419f10 Mon Sep 17 00:00:00 2001 From: chief Date: Wed, 10 Mar 2010 08:47:29 +0100 Subject: new opentox logo as text --- public/opentox_logo.png | Bin 4274 -> 0 bytes views/layout.haml | 4 +++- views/style.sass | 23 +++++++++++++++++++---- 3 files changed, 22 insertions(+), 5 deletions(-) delete mode 100644 public/opentox_logo.png diff --git a/public/opentox_logo.png b/public/opentox_logo.png deleted file mode 100644 index 139250f..0000000 Binary files a/public/opentox_logo.png and /dev/null differ diff --git a/views/layout.haml b/views/layout.haml index 47699b6..437a587 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -9,7 +9,9 @@ %body .headline %h1 ToxModel - %img{:src => "/opentox_logo.png", :alt => "OpenTox"} + %logo + %span1="Open" + %span2="Tox" .index %ul diff --git a/views/style.sass b/views/style.sass index 8f5a1d3..a6f8701 100644 --- a/views/style.sass +++ b/views/style.sass @@ -21,11 +21,26 @@ body padding-left: 0.5em padding-bottom: 0.5em - img - margin: 0 + logo position: absolute - top: 0.7em - left: 40em + top: 0.8em + left: 20em + display: inline + font-family: arial + font-size: 2em + word-spacing: -2px + + span1 + color: #5D308A + font-weight: 500 + + span2 + position: relative + left: -10px + color: black + font-weight: bolder + letter-spacing: -3px + .index -- cgit v1.2.3 From 7dccdd50be2a9215befe9018f9e5cf5a401f69a6 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 10 Mar 2010 12:00:48 +0100 Subject: newline added to end of uri-lists --- application.rb | 8 ++++---- views/create.haml | 2 +- views/csv_format.haml | 2 +- views/layout.haml | 2 +- views/models.haml | 12 ++++++++++-- views/style.sass | 27 +++++++++++++++++++++++---- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/application.rb b/application.rb index 3b4d9fb..2084be4 100644 --- a/application.rb +++ b/application.rb @@ -58,10 +58,10 @@ get '/models/?' do model.save end if !model.validation_uri and model.validation_status == "completed" - validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s - LOGGER.debug "Validation URI: #{validation_uri}" - model.validation_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s - LOGGER.debug "Validation Report URI: #{model.validation_uri}" + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s + LOGGER.debug "Validation URI: #{model.validation_uri}" + #model.validation_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s + #LOGGER.debug "Validation Report URI: #{model.validation_uri}" model.save end end diff --git a/views/create.haml b/views/create.haml index 99cffb3..f754770 100644 --- a/views/create.haml +++ b/views/create.haml @@ -22,5 +22,5 @@ format: %input{:type => 'file', :name => 'file', :id => 'file', :size => '41'} %input{ :type => "submit", :value => "Create model"} - = link_to "Cancel", 'create' + = link_to "Cancel", '/create' diff --git a/views/csv_format.haml b/views/csv_format.haml index 70ea50f..999bb68 100644 --- a/views/csv_format.haml +++ b/views/csv_format.haml @@ -1,7 +1,7 @@ = link_to "Back to model creation", '/create' %p The input file should contain two columns, separated by a comma. Enter in the first column the chemical structure in - = link_to "SMILES", "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification" + %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification"} SMILES format, in the second column the activity classification (1: active, 0: inactive), e.g. .code diff --git a/views/layout.haml b/views/layout.haml index f68943b..0c388a7 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -9,7 +9,7 @@ %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body - = image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate' + .logo= image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate' .index %ul diff --git a/views/models.haml b/views/models.haml index bd19ba8..7f4841f 100644 --- a/views/models.haml +++ b/views/models.haml @@ -12,7 +12,6 @@ - uri = url_for("/model/#{model.id}", :full) %h2 = model.name - -#%button{:onclick => "deletemodel('#{uri}')"} delete %dl %dt Status: %dd @@ -31,12 +30,21 @@ %em (model representation in OWL-DL - experts only) - else %em model under construction + = image_tag("/snake_transparent.gif") %dt Validation: %dd - if model.validation_uri - %a{:href => model.validation_uri, :accept => "text/html"} Details + - uri = File.join(model.validation_uri, 'statistics') + - yaml = RestClient.get(uri).to_s + - v = YAML.load(yaml) + %dl + %dt Correct predictions: + %dd + = v[:classification_statistics][:percent_correct].to_s + = '%' - else %em under construction + = image_tag("/snake_transparent.gif") =# model.validation_task_uri diff --git a/views/style.sass b/views/style.sass index f2698a7..9b3a8ab 100644 --- a/views/style.sass +++ b/views/style.sass @@ -19,9 +19,10 @@ body color = !text_color padding: 1em - img - float: right - height: 4em + .logo + img + float: right + height: 4em .index clear: both @@ -123,6 +124,7 @@ body height: 100% dl + //display: block padding: 1em background-color = !bg_color2 border: 1px solid @@ -131,8 +133,25 @@ body font-weight: bold float: left clear: left + //display: block dd - //padding-left: 2em + clear: right + //display: block + + dl + //display: block + clear: both + padding: 1em + background-color = !bg_color2 + border: 0 + dt + white-space: nowrap + width: 15em + font-weight: bold + float: left + clear: right + dd + //padding-left: 2em .footer margin: 0.5em -- cgit v1.2.3 From 810cf25356be37e9b26708aa0fa1210c50c07325 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 10 Mar 2010 19:17:46 +0100 Subject: owl-dl (temporarily) removed, switched to YAML representation --- application.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/application.rb b/application.rb index 2084be4..4edcaef 100644 --- a/application.rb +++ b/application.rb @@ -124,7 +124,8 @@ post '/upload' do # create a new model dataset = OpenTox::Dataset.new dataset.title = title feature_uri = url_for("/feature#"+title, :full) - feature = dataset.find_or_create_feature(feature_uri) + dataset.features << feature_uri + #feature = dataset.find_or_create_feature(feature_uri) smiles_errors = [] activity_errors = [] duplicates = {} @@ -142,13 +143,18 @@ post '/upload' do # create a new model duplicates[c.inchi] = [] unless duplicates[c.inchi] duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp compound_uri = c.uri - compound = dataset.find_or_create_compound(compound_uri) + #compound = dataset.find_or_create_compound(compound_uri) + dataset.compounds << compound_uri + dataset.data[compound_uri] = {} unless dataset.data[compound_uri] + dataset.data[compound_uri][feature_uri] = [] unless dataset.data[compound_uri][feature_uri] case items[1].to_s when '1' - dataset.add(compound,feature,true) + dataset.data[compound_uri][feature_uri] << true + #dataset.add(compound,feature,true) nr_compounds += 1 when '0' - dataset.add(compound,feature,false) + dataset.data[compound_uri][feature_uri] << false + #dataset.add(compound,feature,false) nr_compounds += 1 else activity_errors << "Line #{line_nr}: " + line.chomp -- cgit v1.2.3 From abee4c335778247b290a343730e76e6676b9dac4 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 15 Mar 2010 13:41:05 +0100 Subject: small modification to internal yaml representation --- application.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application.rb b/application.rb index 4edcaef..7b5ef7e 100644 --- a/application.rb +++ b/application.rb @@ -145,15 +145,15 @@ post '/upload' do # create a new model compound_uri = c.uri #compound = dataset.find_or_create_compound(compound_uri) dataset.compounds << compound_uri - dataset.data[compound_uri] = {} unless dataset.data[compound_uri] - dataset.data[compound_uri][feature_uri] = [] unless dataset.data[compound_uri][feature_uri] + dataset.data[compound_uri] = [] unless dataset.data[compound_uri] + #dataset.data[compound_uri][feature_uri] = [] unless dataset.data[compound_uri][feature_uri] case items[1].to_s when '1' - dataset.data[compound_uri][feature_uri] << true + dataset.data[compound_uri] << {feature_uri => true } #dataset.add(compound,feature,true) nr_compounds += 1 when '0' - dataset.data[compound_uri][feature_uri] << false + dataset.data[compound_uri] << {feature_uri => false } #dataset.add(compound,feature,false) nr_compounds += 1 else -- cgit v1.2.3 From 0c83e4ad2990075384788eb959bb799c49a098fe Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 16 Mar 2010 11:05:40 +0100 Subject: toxcreate adapted for new representation --- application.rb | 70 +++++++++++++++++++++++++-------------------------- views/prediction.haml | 5 ++-- 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/application.rb b/application.rb index 7b5ef7e..c29e132 100644 --- a/application.rb +++ b/application.rb @@ -22,11 +22,11 @@ class ToxCreateModel property :created_at, DateTime def status - RestClient.get File.join(self.task_uri, 'status') + RestClient.get(File.join(@task_uri, 'status')).to_s end def validation_status - RestClient.get File.join(self.validation_task_uri, 'status') + RestClient.get File.join(@validation_task_uri, 'status') end end @@ -57,12 +57,14 @@ get '/models/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s model.save end - if !model.validation_uri and model.validation_status == "completed" - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s - LOGGER.debug "Validation URI: #{model.validation_uri}" - #model.validation_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s - #LOGGER.debug "Validation Report URI: #{model.validation_uri}" - model.save + unless @@config[:services]["opentox-model"].match(/localhost/) + if !model.validation_uri and model.validation_status == "completed" + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s + LOGGER.debug "Validation URI: #{model.validation_uri}" + #model.validation_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s + #LOGGER.debug "Validation Report URI: #{model.validation_uri}" + model.save + end end end @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) @@ -166,15 +168,17 @@ post '/upload' do # create a new model end dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) - validation_task_uri = OpenTox::Validation.crossvalidation( - :algorithm_uri => OpenTox::Algorithm::Lazar.uri, - :dataset_uri => dataset_uri, - :prediction_feature => feature_uri, - :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" - ).uri - LOGGER.debug "Validation task: " + validation_task_uri @model.task_uri = task_uri - @model.validation_task_uri = validation_task_uri + unless @@config[:services]["opentox-model"].match(/localhost/) + validation_task_uri = OpenTox::Validation.crossvalidation( + :algorithm_uri => OpenTox::Algorithm::Lazar.uri, + :dataset_uri => dataset_uri, + :prediction_feature => feature_uri, + :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" + ).uri + LOGGER.debug "Validation task: " + validation_task_uri + @model.validation_task_uri = validation_task_uri + end @model.messages = "#{nr_compounds} compounds" @@ -212,35 +216,29 @@ post '/predict/?' do # post chemical name to model redirect url_for('/predict') end @predictions = [] - #LOGGER.debug params[:selection].to_yaml params[:selection].keys.each do |id| model = ToxCreateModel.get(id.to_i) - #LOGGER.debug model.to_yaml prediction = nil confidence = nil title = nil db_activities = [] - #prediction = RestClient.post model.uri, :compound_uri => @compound.uri#, :accept => "application/x-yaml" - resource = RestClient::Resource.new(model.uri, :user => @@users[:users].keys[0], :password => @@users[:users].values[0]) - prediction = resource.post :compound_uri => @compound.uri#, :accept => "application/x-yaml" - #LOGGER.debug "Prediction OWL-DL: " - #LOGGER.debug prediction - redland_model = Redland::Model.new Redland::MemoryStore.new - parser = Redland::Parser.new - parser.parse_string_into_model(redland_model,prediction,'/') - title = model.name - redland_model.subjects(RDF['type'], OT['FeatureValue']).each do |v| - feature = redland_model.object(v,OT['feature']) - feature_name = redland_model.object(feature,DC['title']).to_s - #LOGGER.debug "DEBUG: #{feature_name}" - prediction = redland_model.object(v,OT['value']).to_s if feature_name.match(/classification/) - confidence = redland_model.object(v,OT['value']).to_s if feature_name.match(/confidence/) - db_activities << redland_model.object(v,OT['value']).to_s if feature_name.match(/#{URI.encode title}/) + prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) + source = prediction.source + LOGGER.debug source + LOGGER.debug prediction.to_yaml + if prediction.data[@compound.uri] + if source.to_s.match(/model/) + prediction = prediction.data[@compound.uri].first.values.first + @predictions << {:title => model.name, :prediction => prediction[:classification], :confidence => prediction[:confidence]} + else + prediction = prediction.data[@compound.uri].first.values + @predictions << {:title => model.name, :measured_activities => prediction} + end + else + @predictions << {:title => model.name, :prediction => "not available (no similar compounds in the training dataset)"} end - @predictions << {:title => title, :prediction => prediction, :confidence => confidence, :measured_activities => db_activities} end - LOGGER.debug @predictions.to_yaml haml :prediction end diff --git a/views/prediction.haml b/views/prediction.haml index 7912ada..96fe54d 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -11,9 +11,8 @@ - @predictions.each do |p| %td %b - =# p[:title].gsub(/_/,' ') + ":" = p[:title] + ":" - - if p[:measured_activities].size > 0 + - if p[:measured_activities] %br - p[:measured_activities].each do |a| - if activity(a) == 'active' @@ -32,7 +31,7 @@ = activity(p[:prediction]) - else %br - %em not available + %em= p[:prediction] - if p[:confidence] %br = "(confidence: #{sprintf('%.03f', p[:confidence].to_f.abs)})" -- cgit v1.2.3 From b2b9497fa107a82242f1a8982161b7301a585f8f Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 16 Mar 2010 17:35:34 +0100 Subject: OWL-DL export added --- application.rb | 5 ----- views/models.haml | 7 ++++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/application.rb b/application.rb index c29e132..679065e 100644 --- a/application.rb +++ b/application.rb @@ -127,7 +127,6 @@ post '/upload' do # create a new model dataset.title = title feature_uri = url_for("/feature#"+title, :full) dataset.features << feature_uri - #feature = dataset.find_or_create_feature(feature_uri) smiles_errors = [] activity_errors = [] duplicates = {} @@ -145,18 +144,14 @@ post '/upload' do # create a new model duplicates[c.inchi] = [] unless duplicates[c.inchi] duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp compound_uri = c.uri - #compound = dataset.find_or_create_compound(compound_uri) dataset.compounds << compound_uri dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - #dataset.data[compound_uri][feature_uri] = [] unless dataset.data[compound_uri][feature_uri] case items[1].to_s when '1' dataset.data[compound_uri] << {feature_uri => true } - #dataset.add(compound,feature,true) nr_compounds += 1 when '0' dataset.data[compound_uri] << {feature_uri => false } - #dataset.add(compound,feature,false) nr_compounds += 1 else activity_errors << "Line #{line_nr}: " + line.chomp diff --git a/views/models.haml b/views/models.haml index 7f4841f..e80695f 100644 --- a/views/models.haml +++ b/views/models.haml @@ -23,11 +23,12 @@ %dd= model.created_at %dt Details: %dd= model.messages - %dt URI: + %dt Download: %dd - if model.uri - %a{:href => model.uri, :accept => "application/rdf+xml"} #{model.uri} - %em (model representation in OWL-DL - experts only) + -# %a{:href => model.uri, :accept => "application/x-yaml"} yaml + %a{:href => model.uri, :accept => "application/rdf+xml"} OWL-DL model representation + %em (experts only) - else %em model under construction = image_tag("/snake_transparent.gif") -- cgit v1.2.3 From a8c0131741c26d5273ebe149cf6aec03245f8e8e Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 16 Mar 2010 19:45:49 +0100 Subject: some untracked files added --- public/snake_transparent.gif | Bin 0 -> 2209 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/snake_transparent.gif diff --git a/public/snake_transparent.gif b/public/snake_transparent.gif new file mode 100644 index 0000000..c1eb1c9 Binary files /dev/null and b/public/snake_transparent.gif differ -- cgit v1.2.3 From 67efa10bf4b739c911a5918e4e6008b18767de4a Mon Sep 17 00:00:00 2001 From: gebele Date: Wed, 17 Mar 2010 13:07:29 +0100 Subject: new font logos top and bottom --- views/layout.haml | 8 ++++---- views/style.sass | 33 ++++++++++++++------------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/views/layout.haml b/views/layout.haml index 437a587..6ef81db 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -8,10 +8,9 @@ %body .headline - %h1 ToxModel %logo - %span1="Open" - %span2="Tox" + %span1="Tox" + %span2="Create" .index %ul @@ -34,5 +33,6 @@ © %a{:href => 'http://www.in-silico.ch'} in silico toxicology 2009, powered by - %a{:href => 'http://www.opentox.org'} OpenTox + %a{:href => 'http://www.opentox.org'} OpenTox + diff --git a/views/style.sass b/views/style.sass index a6f8701..1a4fae8 100644 --- a/views/style.sass +++ b/views/style.sass @@ -12,34 +12,28 @@ body padding: 1em .headline - - h1 - color = !fg_color - margin: 0 - padding: 0 - background-color = !body_color - padding-left: 0.5em - padding-bottom: 0.5em logo - position: absolute - top: 0.8em - left: 20em + position: relative + left: 80% + top: 1% display: inline font-family: arial - font-size: 2em + font-size: 2.5em word-spacing: -2px - span1 - color: #5D308A - font-weight: 500 - - span2 - position: relative - left: -10px + span1 color: black font-weight: bolder letter-spacing: -3px + + span2 + color: #5D308A + font-weight: 500 + position: relative + left: -6px + + .index @@ -114,3 +108,4 @@ body .footer margin: 0.5em padding: 0.5em + -- cgit v1.2.3 From bea1c77a544b74abc9a77f5bea7db00f9ebdabe9 Mon Sep 17 00:00:00 2001 From: gebele Date: Wed, 17 Mar 2010 13:11:40 +0100 Subject: second try --- views/layout.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/layout.haml b/views/layout.haml index 6ef81db..3d8edcc 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -33,6 +33,6 @@ © %a{:href => 'http://www.in-silico.ch'} in silico toxicology 2009, powered by - %a{:href => 'http://www.opentox.org'} OpenTox + %a{:href => 'http://www.opentox.org'} OpenTox -- cgit v1.2.3 From d987683fe40e20cd93a8a5b95a742732c80b965d Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 18 Mar 2010 21:03:38 +0100 Subject: opentox-api-wrapper version bumped to 1.4.0 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 083a2f5..a300904 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.3.1' +gem 'opentox-ruby-api-wrapper', '= 1.4.0' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From a64f22ba742a55f1f181d32a265c4e4c2715c061 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 19 Mar 2010 11:52:32 +0100 Subject: validation temporarily disabled --- application.rb | 6 ++++++ views/models.haml | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/application.rb b/application.rb index a300904..8973b67 100644 --- a/application.rb +++ b/application.rb @@ -72,6 +72,7 @@ get '/models/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s model.save end +=begin unless @@config[:services]["opentox-model"].match(/localhost/) if !model.validation_uri and model.validation_status == "completed" model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s @@ -81,6 +82,7 @@ get '/models/?' do model.save end end +=end end @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) haml :models @@ -179,6 +181,8 @@ post '/upload' do # create a new model dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) @model.task_uri = task_uri + +=begin unless @@config[:services]["opentox-model"].match(/localhost/) validation_task_uri = OpenTox::Validation.crossvalidation( :algorithm_uri => OpenTox::Algorithm::Lazar.uri, @@ -189,8 +193,10 @@ post '/upload' do # create a new model LOGGER.debug "Validation task: " + validation_task_uri @model.validation_task_uri = validation_task_uri end +=end @model.nr_compounds = nr_compounds + @model.warnings = '' if smiles_errors.size > 0 @model.warnings += "

Incorrect Smiles structures (ignored):

" diff --git a/views/models.haml b/views/models.haml index 9d73c2c..79cb397 100644 --- a/views/models.haml +++ b/views/models.haml @@ -25,10 +25,10 @@ %dt Training compounds: %dd= model.nr_compounds %dt Warnings: - - if model.warnings - %dd= model.warnings - - else + - if model.warnings == '' %dd - + - else + %dd= model.warnings - if model.status == 'completed' %dt Algorithm: @@ -58,7 +58,8 @@ %em (more formats to be added) %dt Validation: %dd - - if model.validation_uri + %em temporarily disabled + -# if model.validation_uri - uri = File.join(model.validation_uri, 'statistics') - yaml = RestClient.get(uri).to_s - v = YAML.load(yaml) @@ -67,7 +68,7 @@ %dd = v[:classification_statistics][:percent_correct].to_s = '%' - - else + -# else %em under construction = image_tag("/snake_transparent.gif") =# model.validation_task_uri -- cgit v1.2.3 From 9d05281e77882b11d3f348976902f095f423f6c8 Mon Sep 17 00:00:00 2001 From: opentox Date: Thu, 15 Apr 2010 21:15:44 +0200 Subject: fixes for recent rest-client --- application.rb | 10 +++++----- views/layout.haml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application.rb b/application.rb index 8973b67..58123dc 100644 --- a/application.rb +++ b/application.rb @@ -24,23 +24,23 @@ class ToxCreateModel property :created_at, DateTime def status - RestClient.get(File.join(@task_uri, 'status')).to_s + RestClient.get(File.join(@task_uri, 'status')).body end def validation_status - RestClient.get File.join(@validation_task_uri, 'status') + RestClient.get(File.join(@validation_task_uri, 'status')).body end def algorithm - RestClient.get File.join(@uri, 'algorithm') + RestClient.get(File.join(@uri, 'algorithm')).body end def training_dataset - RestClient.get File.join(@uri, 'training_dataset') + RestClient.get(File.join(@uri, 'training_dataset')).body end def feature_dataset - RestClient.get File.join(@uri, 'feature_dataset') + RestClient.get(File.join(@uri, 'feature_dataset')).body end end diff --git a/views/layout.haml b/views/layout.haml index cb11296..07071d9 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -17,7 +17,7 @@ .index %ul - %li{:class => ("selected" if /create/ =~ request.path )} + %li{:class => ("selected" if /\/create/ =~ request.path )} = link_to "Create", "/create" %li{:class => ("selected" if /models/ =~ request.path )} = link_to "Inspect", "/models" -- cgit v1.2.3 From 1773ca0998bfc0731826ecde5db9ceca7588f4fd Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 20 Apr 2010 15:45:04 +0200 Subject: stylesheet changes --- views/style.sass | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/views/style.sass b/views/style.sass index a968bbf..185f02b 100644 --- a/views/style.sass +++ b/views/style.sass @@ -1,8 +1,10 @@ -!bg_color = #B7FEFA -!bg_color2 = #DDDDDD -!fg_color = #5D308A +!bg_color = #B9DCFF +!bg_color2 = #e5e7eb +!fg_color = #424345 +!ot_purple = #5D308A !body_color = white !text_color = black +!notice_border = #000000 /* !bg_color = #DDFFFF @@ -13,19 +15,27 @@ body min-width: 30em - font-family: Verdana + font-family: Verdana, sans font-size: 14px background-color = !body_color color = !text_color padding: 1em - + + a + text-decoration: none + font-weight: bold + color = !ot_purple + + a:hover + color = black + .headline logo top: 1% float: right display: inline - font-family: arial + font-family: arial, sans font-size: 2.5em word-spacing: -2px @@ -35,7 +45,7 @@ body letter-spacing: -3px span2 - color: #5D308A + color = !ot_purple font-weight: 500 position: relative left: -6px @@ -44,14 +54,14 @@ body clear: both ul - margin: 0 + margin: 0 0 2px 0 padding: 0 white-space: nowrap list-style-type: none li margin: 0 - padding: 0 + padding: 2px display: inline border-right: 1px solid color = !body_color @@ -60,6 +70,7 @@ body background-color = !fg_color padding-left: 0.5em padding-right: 0.5em + font-weight: bold a text-decoration: none @@ -68,14 +79,14 @@ body color = !body_color li.selected - font-weight: bolder + font-weight: bold background-color= !bg_color border: 1px solid color = !fg_color border-bottom: 1px solid color = !bg_color a - color = !fg_color + color = !text_color .content @@ -86,12 +97,16 @@ body padding: 1em border: 1px solid color = !fg_color - + + h2 + margin: 20px 3px 2px 3px + .notice //background-color = !body_color padding: 1em - background-color = !bg_color2 - border: 1px solid red + background-color = !body_color + border: 1px solid + border-color = !notice_border .input text-align: left @@ -144,6 +159,7 @@ body padding: 1em background-color = !bg_color2 border: 1px solid + margin-top: 0.6em dt width: 15em font-weight: bold @@ -161,7 +177,7 @@ body background-color = !bg_color2 border: 0 dt - white-space: nowrap + white-spaceborder-top: 2px solid: nowrap width: 15em font-weight: bold float: left -- cgit v1.2.3 From 9be3595a99e755679ba828ae81192fd808728823 Mon Sep 17 00:00:00 2001 From: gebele Date: Thu, 22 Apr 2010 18:15:10 +0200 Subject: new font-families --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index 1a4fae8..92cad5d 100644 --- a/views/style.sass +++ b/views/style.sass @@ -18,7 +18,7 @@ body left: 80% top: 1% display: inline - font-family: arial + font-family: arial,sans-serif,helvetica font-size: 2.5em word-spacing: -2px -- cgit v1.2.3 From dcab1061b909dba33b01a76a1fe3cd05412da991 Mon Sep 17 00:00:00 2001 From: gebele Date: Fri, 23 Apr 2010 09:03:40 +0200 Subject: better script for font-families --- views/layout.haml | 2 +- views/style.sass | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/views/layout.haml b/views/layout.haml index 3d8edcc..6d2920e 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -33,6 +33,6 @@ © %a{:href => 'http://www.in-silico.ch'} in silico toxicology 2009, powered by - %a{:href => 'http://www.opentox.org'} OpenTox + %a{:href => 'http://www.opentox.org'} OpenTox diff --git a/views/style.sass b/views/style.sass index 92cad5d..63eca85 100644 --- a/views/style.sass +++ b/views/style.sass @@ -5,7 +5,7 @@ body min-width: 30em - font-family: arial + font-family: arial,sans-serif,helvetica background-color = !body_color color = !text_color height: 100% @@ -18,7 +18,6 @@ body left: 80% top: 1% display: inline - font-family: arial,sans-serif,helvetica font-size: 2.5em word-spacing: -2px -- cgit v1.2.3 From 66ed931ecf53aa167edabe8993ae45b759685294 Mon Sep 17 00:00:00 2001 From: mr Date: Thu, 29 Apr 2010 13:08:34 +0200 Subject: view modifications and jquery scripts delete, checkstatus, toggleWarnings --- application.rb | 41 ++++++++++- public/javascripts/jquery.js | 154 +++++++++++++++++++++++++++++++++++++++ public/javascripts/toxcreate.js | 112 ++++++++++++++++++++++++++++ public/javascripts/toxcreate.js~ | 113 ++++++++++++++++++++++++++++ views/layout.haml | 6 +- views/model.haml | 77 ++++++++++++++++++++ views/model_status.haml | 3 + views/models.haml | 82 +++------------------ 8 files changed, 512 insertions(+), 76 deletions(-) mode change 100644 => 100755 application.rb create mode 100755 public/javascripts/jquery.js create mode 100755 public/javascripts/toxcreate.js create mode 100755 public/javascripts/toxcreate.js~ mode change 100644 => 100755 views/layout.haml create mode 100644 views/model.haml create mode 100755 views/model_status.haml mode change 100644 => 100755 views/models.haml diff --git a/application.rb b/application.rb old mode 100644 new mode 100755 index 58123dc..564687e --- a/application.rb +++ b/application.rb @@ -88,7 +88,7 @@ get '/models/?' do haml :models end -get '/model/:id/delete/?' do +delete '/model/:id/delete/?' do model = ToxCreateModel.get(params[:id]) begin RestClient.delete model.uri if model.uri @@ -100,6 +100,45 @@ get '/model/:id/delete/?' do redirect url_for('/models') end +get '/model/:id/status/?' do + response['Content-Type'] = 'text/plain' + model = ToxCreateModel.get(params[:id]) + begin + haml :model_status, :locals=>{:model=>model}, :layout => false + rescue + + end +end + +get '/model/:id/?' do + response['Content-Type'] = 'text/plain' + model = ToxCreateModel.get(params[:id]) + if !model.uri and model.status == "completed" + model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s + model.save + end +=begin + unless @@config[:services]["opentox-model"].match(/localhost/) + if !model.validation_uri and model.validation_status == "completed" + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s + LOGGER.debug "Validation URI: #{model.validation_uri}" + model.validation_report_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s + LOGGER.debug "Validation Report URI: #{model.validation_report_uri}" + model.save + end + end +=end + + @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) + + begin + haml :model, :locals=>{:model=>model}, :layout => false + rescue + return "unable to renderd model" + end +end + + get '/predict/?' do @models = ToxCreateModel.all(:order => [ :created_at.desc ]) @models = @models.collect{|m| m if m.status == 'completed'}.compact diff --git a/public/javascripts/jquery.js b/public/javascripts/jquery.js new file mode 100755 index 0000000..7c24308 --- /dev/null +++ b/public/javascripts/jquery.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js new file mode 100755 index 0000000..890f6d0 --- /dev/null +++ b/public/javascripts/toxcreate.js @@ -0,0 +1,112 @@ +$(function() { + + jQuery.fn.toggleWarnings = function(id) { + var id = id; + this.bind("click", function() { + if($("a#show_model_" + id + "_warnings").html()=="show") { + $("dd#model_" + id + "_warnings").slideDown("slow"); + $("a#show_model_" + id + "_warnings").html("hide"); + }else{ + $("dd#model_" + id + "_warnings").slideUp("slow"); + $("a#show_model_" + id + "_warnings").html("show"); + } + }); + return false; + }; + + checkStati = function(stati) { + stati = stati.split(", ") + $("body") + var newstati = new Array; + $.each(stati, function(){ + if(checkStatus(this) > 0) newstati.push(this); + }); + if (newstati.length > 0) var statusCheck = setTimeout('checkStati("' + newstati.join(", ") + '")',10000); + }; + + checkStatus = function(id) { + if(id == "") return -1; + var opts = {method: 'get', action: 'model/' + id + '/status', id: id}; + var status_changed = $.ajax({ + type: opts.method, + url: opts.action, + async: false, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + var erg = data.search(/started/); + status_changed = false; + if(erg < 0) status_changed = true; + $("span#model_" + id + "_status").animate({"opacity": "0.1"},1000); + $("span#model_" + id + "_status").animate({"opacity": "1"},1000); + if( status_changed ) { + $("span#model_" + id + "_status").html(data); + loadModel(id); + id = -1; + } + }, + error: function(data) { + alert("status check error"); + } + }); + return id; + }; + + loadModel = function(id) { + if(id == "") return -1; + var opts = {method: 'get', action: 'model/' + id }; + var out = id; + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + $("div#model_" + id).animate({"opacity": "0.1"},1000).delay(100); + $("div#model_" + id).html(data); + $("div#model_" + id).animate({"opacity": "1"},1000).delay(100); + }, + error: function(data) { + alert("loadModel error"); + } + }); + return false; + }; + + +}); + +jQuery.fn.deleteModel = function(type, options) { + var defaults = { + method: 'post', + action: this.attr('href'), + confirm_message: 'Are you sure?', + trigger_on: 'click' + }; + var opts = $.extend(defaults, options); + this.bind(opts.trigger_on, function() { + if(confirm(opts.confirm_message)) { + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'delete' + }, + success: function(data) { + $(opts.elem).fadeTo("slow",0).slideUp("slow"); + }, + error: function(data) { + alert("model delete error!"); + } + }); + } + return false; + }); +}; + + diff --git a/public/javascripts/toxcreate.js~ b/public/javascripts/toxcreate.js~ new file mode 100755 index 0000000..0d103b1 --- /dev/null +++ b/public/javascripts/toxcreate.js~ @@ -0,0 +1,113 @@ +$(function() { + + jQuery.fn.toggleWarnings = function(id) { + var id = id; + this.bind("click", function() { + if($("a#show_model_" + id + "_warnings").html()=="show") { + $("dd#model_" + id + "_warnings").slideDown("slow"); + $("a#show_model_" + id + "_warnings").html("hide"); + }else{ + $("dd#model_" + id + "_warnings").slideUp("slow"); + $("a#show_model_" + id + "_warnings").html("show"); + } + }); + return false; + }; + + checkStati = function(stati) { + stati = stati.split(", ") + $("body") + var newstati = new Array; + $.each(stati, function(){ + if(checkStatus(this) > 0) newstati.push(this); + }); + if (newstati.length > 0) var statusCheck = setTimeout('checkStati("' + newstati.join(", ") + '")',10000); + }; + + checkStatus = function(id) { + if(id == "") return -1; + var opts = {method: 'get', action: 'model/' + id + '/status', id: id}; + var status_changed = $.ajax({ + type: opts.method, + url: opts.action, + async: false, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + var erg = data.search(/started/); + status_changed = false; + if(erg < 0) status_changed = true; + $("span#model_" + id + "_status").animate({"opacity": "0.1"},1000); + $("span#model_" + id + "_status").animate({"opacity": "1"},1000); + if( status_changed ) { + $("span#model_" + id + "_status").html(data); + loadModel(id); + id = -1; + } + }, + error: function(data) { + alert("status check error"); + } + }); + return id; + }; + + loadModel = function(id) { + if(id == "") return -1; + var opts = {method: 'get', action: 'model/' + id }; + var out = id; + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + $("div#model_" + id).animate({"opacity": "0.1"},1000).delay(100); + $("div#model_" + id).html(data); + $("div#model_" + id).animate({"opacity": "1"},1000).delay(100); + }, + error: function(data) { + alert("loadModel error"); + } + }); + return false; + }; + + +}); + + +jQuery.fn.deleteModel = function(type, options) { + var defaults = { + method: 'post', + action: this.attr('href'), + confirm_message: 'Are you sure?', + trigger_on: 'click' + }; + var opts = $.extend(defaults, options); + this.bind(opts.trigger_on, function() { + if(confirm(opts.confirm_message)) { + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'delete' + }, + success: function(data) { + $(opts.elem).fadeTo("slow",0).slideUp("slow"); + }, + error: function(data) { + alert("model delete error!"); + } + }); + } + return false; + }); +}; + + diff --git a/views/layout.haml b/views/layout.haml old mode 100644 new mode 100755 index 07071d9..8b09fbd --- a/views/layout.haml +++ b/views/layout.haml @@ -4,8 +4,10 @@ %head %meta{'http-equiv' => 'Content-Type', :content => 'text/html'} - if @refresh - %meta{'http-equiv' => "refresh", :content => "15"} + - # %meta{'http-equiv' => "refresh", :content => "15"} %title ToxCreate + %script{:type => "text/javascript", :src => "javascripts/jquery.js"} + %script{:type => "text/javascript", :src => "javascripts/toxcreate.js"} %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body @@ -34,7 +36,7 @@ - if flash[:notice] %p - .notice + .notice#flashnotice = flash[:notice] = yield diff --git a/views/model.haml b/views/model.haml new file mode 100644 index 0000000..cfcf6f3 --- /dev/null +++ b/views/model.haml @@ -0,0 +1,77 @@ +- uri = url_for("/model/#{model.id}", :full) +- js = "$('#delete_#{model.id}').deleteModel('DELETE', {elem: '#model_#{model.id}'});\n " + "$('#show_model_#{model.id}_warnings').toggleWarnings('#{model.id}');" +:javascript + $(function() { + #{js} + }); + +%div{:id => "model_#{model.id}"} + %h2 + = model.name + %dl + %dt Status: + %dd + %span{:id => "model_#{model.id}_status", :class => model.status} + = haml :model_status, :locals=>{:model=>model}, :layout => false + ( + %a{:href => url_for("/model/#{model.id}/delete"), :id => "delete_#{model.id}", :class => 'delete'} delete + ) + %dt Started: + %dd= model.created_at + %dt Training compounds: + %dd= model.nr_compounds + %dt Warnings: + - if model.warnings == '' + %dd - + - else + %a{:href => "#", :id => "show_model_#{model.id}_warnings"} show + %dd{:id => "model_#{model.id}_warnings", :style => "display: none;"}= model.warnings + + - if model.status == 'completed' + %dt Algorithm: + %dd + - begin + %a{:href => model.algorithm} #{File.basename model.algorithm} + - rescue + %b - + + %dt Descriptors: + %dd + %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes + %dt Training dataset: + %dd + %a{:href => "#{model.training_dataset}.rdf"} RDF/XML + , + %a{:href => "#{model.training_dataset}.yaml"} YAML + , + %a{:href => "#{model.training_dataset}.html"} HTML + %em (more formats to be added) + %dt Feature dataset: + %dd + %a{:href => "#{model.feature_dataset}.rdf"} RDF/XML + , + %a{:href => "#{model.feature_dataset}.yaml"} YAML + %em (more formats to be added) + %dt Model: + %dd + -# %a{:href => model.uri, :accept => "application/x-yaml"} yaml + %a{:href => "#{model.uri}.rdf"} RDF/XML + , + %a{:href => "#{model.uri}.yaml"} YAML + %em (more formats to be added) + %dt Validation: + %dd + %em temporarily disabled + -# if model.validation_uri + - uri = File.join(model.validation_uri, 'statistics') + - yaml = RestClient.get(uri).to_s + - v = YAML.load(yaml) + %dl + %dt Correct predictions: + %dd + = v[:classification_statistics][:percent_correct].to_s + = '%' + -# else + %em under construction + = image_tag("/snake_transparent.gif") + =# model.validation_task_uri \ No newline at end of file diff --git a/views/model_status.haml b/views/model_status.haml new file mode 100755 index 0000000..91afb0d --- /dev/null +++ b/views/model_status.haml @@ -0,0 +1,3 @@ +- if model.status.match(/started|created/) + = image_tag("/snake_transparent.gif") += model.status \ No newline at end of file diff --git a/views/models.haml b/views/models.haml old mode 100644 new mode 100755 index 79cb397..3d17c36 --- a/views/models.haml +++ b/views/models.haml @@ -1,76 +1,12 @@ --# :javascript - function deletemodel(uri) { - var xmlhttp; - return confirm("Are you sure?"); - xmlhttp=new XMLHttpRequest(); - xmlhttp.open('DELETE',uri,false) - xmlhttp.send(null); - } +- stati = @models.map{|m| "#{m.id}" if m.status != "completed"}.compact +- stati_to_check = stati.length > 0 ? stati.join(", ") : stati = 0 +:javascript + $(function() { + if(#{stati != 0}) { + setTimeout('checkStati("#{stati_to_check}")',1500); + } + }); %p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. - @models.each do |model| - - uri = url_for("/model/#{model.id}", :full) - %h2 - = model.name - %dl - %dt Status: - %dd - = image_tag("/snake_transparent.gif") if model.status.match(/started|created/) - = model.status - ( - %a{:href => url_for("/model/#{model.id}/delete"), :onclick => 'return confirm("Are you sure?");'} delete - ) - %dt Started: - %dd= model.created_at - %dt Training compounds: - %dd= model.nr_compounds - %dt Warnings: - - if model.warnings == '' - %dd - - - else - %dd= model.warnings - - - if model.status == 'completed' - %dt Algorithm: - %dd - %a{:href => model.algorithm} #{File.basename model.algorithm} - %dt Descriptors: - %dd - %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes - %dt Training dataset: - %dd - %a{:href => "#{model.training_dataset}.rdf"} RDF/XML - , - %a{:href => "#{model.training_dataset}.yaml"} YAML - %em (more formats to be added) - %dt Feature dataset: - %dd - %a{:href => "#{model.feature_dataset}.rdf"} RDF/XML - , - %a{:href => "#{model.feature_dataset}.yaml"} YAML - %em (more formats to be added) - %dt Model: - %dd - -# %a{:href => model.uri, :accept => "application/x-yaml"} yaml - %a{:href => "#{model.uri}.rdf"} RDF/XML - , - %a{:href => "#{model.uri}.yaml"} YAML - %em (more formats to be added) - %dt Validation: - %dd - %em temporarily disabled - -# if model.validation_uri - - uri = File.join(model.validation_uri, 'statistics') - - yaml = RestClient.get(uri).to_s - - v = YAML.load(yaml) - %dl - %dt Correct predictions: - %dd - = v[:classification_statistics][:percent_correct].to_s - = '%' - -# else - %em under construction - = image_tag("/snake_transparent.gif") - =# model.validation_task_uri - - + = haml :model, :locals=>{:model=>model}, :layout => false -- cgit v1.2.3 From c3820c1c07532775f20f696dbca03f9f50067033 Mon Sep 17 00:00:00 2001 From: mr Date: Thu, 29 Apr 2010 13:13:39 +0200 Subject: rm public/javascripts/toxcreate.js~ --- public/javascripts/toxcreate.js~ | 113 --------------------------------------- 1 file changed, 113 deletions(-) delete mode 100755 public/javascripts/toxcreate.js~ diff --git a/public/javascripts/toxcreate.js~ b/public/javascripts/toxcreate.js~ deleted file mode 100755 index 0d103b1..0000000 --- a/public/javascripts/toxcreate.js~ +++ /dev/null @@ -1,113 +0,0 @@ -$(function() { - - jQuery.fn.toggleWarnings = function(id) { - var id = id; - this.bind("click", function() { - if($("a#show_model_" + id + "_warnings").html()=="show") { - $("dd#model_" + id + "_warnings").slideDown("slow"); - $("a#show_model_" + id + "_warnings").html("hide"); - }else{ - $("dd#model_" + id + "_warnings").slideUp("slow"); - $("a#show_model_" + id + "_warnings").html("show"); - } - }); - return false; - }; - - checkStati = function(stati) { - stati = stati.split(", ") - $("body") - var newstati = new Array; - $.each(stati, function(){ - if(checkStatus(this) > 0) newstati.push(this); - }); - if (newstati.length > 0) var statusCheck = setTimeout('checkStati("' + newstati.join(", ") + '")',10000); - }; - - checkStatus = function(id) { - if(id == "") return -1; - var opts = {method: 'get', action: 'model/' + id + '/status', id: id}; - var status_changed = $.ajax({ - type: opts.method, - url: opts.action, - async: false, - dataType: 'html', - data: { - '_method': 'get' - }, - success: function(data) { - var erg = data.search(/started/); - status_changed = false; - if(erg < 0) status_changed = true; - $("span#model_" + id + "_status").animate({"opacity": "0.1"},1000); - $("span#model_" + id + "_status").animate({"opacity": "1"},1000); - if( status_changed ) { - $("span#model_" + id + "_status").html(data); - loadModel(id); - id = -1; - } - }, - error: function(data) { - alert("status check error"); - } - }); - return id; - }; - - loadModel = function(id) { - if(id == "") return -1; - var opts = {method: 'get', action: 'model/' + id }; - var out = id; - $.ajax({ - type: opts.method, - url: opts.action, - dataType: 'html', - data: { - '_method': 'get' - }, - success: function(data) { - $("div#model_" + id).animate({"opacity": "0.1"},1000).delay(100); - $("div#model_" + id).html(data); - $("div#model_" + id).animate({"opacity": "1"},1000).delay(100); - }, - error: function(data) { - alert("loadModel error"); - } - }); - return false; - }; - - -}); - - -jQuery.fn.deleteModel = function(type, options) { - var defaults = { - method: 'post', - action: this.attr('href'), - confirm_message: 'Are you sure?', - trigger_on: 'click' - }; - var opts = $.extend(defaults, options); - this.bind(opts.trigger_on, function() { - if(confirm(opts.confirm_message)) { - $.ajax({ - type: opts.method, - url: opts.action, - dataType: 'html', - data: { - '_method': 'delete' - }, - success: function(data) { - $(opts.elem).fadeTo("slow",0).slideUp("slow"); - }, - error: function(data) { - alert("model delete error!"); - } - }); - } - return false; - }); -}; - - -- cgit v1.2.3 From 284f3b6c3803c796795bfe60693b6557726078d9 Mon Sep 17 00:00:00 2001 From: ch Date: Mon, 3 May 2010 13:10:43 +0200 Subject: validation enabled --- application.rb | 6 +----- views/models.haml | 8 ++++---- views/style.sass | 46 +++++++++++++++++++++++++++++++--------------- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/application.rb b/application.rb index 58123dc..62f4183 100644 --- a/application.rb +++ b/application.rb @@ -28,7 +28,7 @@ class ToxCreateModel end def validation_status - RestClient.get(File.join(@validation_task_uri, 'status')).body + #RestClient.get(File.join(@validation_task_uri, 'status')).body end def algorithm @@ -72,7 +72,6 @@ get '/models/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s model.save end -=begin unless @@config[:services]["opentox-model"].match(/localhost/) if !model.validation_uri and model.validation_status == "completed" model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s @@ -82,7 +81,6 @@ get '/models/?' do model.save end end -=end end @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) haml :models @@ -182,7 +180,6 @@ post '/upload' do # create a new model task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) @model.task_uri = task_uri -=begin unless @@config[:services]["opentox-model"].match(/localhost/) validation_task_uri = OpenTox::Validation.crossvalidation( :algorithm_uri => OpenTox::Algorithm::Lazar.uri, @@ -193,7 +190,6 @@ post '/upload' do # create a new model LOGGER.debug "Validation task: " + validation_task_uri @model.validation_task_uri = validation_task_uri end -=end @model.nr_compounds = nr_compounds @model.warnings = '' diff --git a/views/models.haml b/views/models.haml index 79cb397..5272c56 100644 --- a/views/models.haml +++ b/views/models.haml @@ -58,8 +58,8 @@ %em (more formats to be added) %dt Validation: %dd - %em temporarily disabled - -# if model.validation_uri + -# %em temporarily disabled + - if model.validation_uri - uri = File.join(model.validation_uri, 'statistics') - yaml = RestClient.get(uri).to_s - v = YAML.load(yaml) @@ -68,9 +68,9 @@ %dd = v[:classification_statistics][:percent_correct].to_s = '%' - -# else + - else %em under construction = image_tag("/snake_transparent.gif") - =# model.validation_task_uri + = model.validation_task_uri diff --git a/views/style.sass b/views/style.sass index a968bbf..185f02b 100644 --- a/views/style.sass +++ b/views/style.sass @@ -1,8 +1,10 @@ -!bg_color = #B7FEFA -!bg_color2 = #DDDDDD -!fg_color = #5D308A +!bg_color = #B9DCFF +!bg_color2 = #e5e7eb +!fg_color = #424345 +!ot_purple = #5D308A !body_color = white !text_color = black +!notice_border = #000000 /* !bg_color = #DDFFFF @@ -13,19 +15,27 @@ body min-width: 30em - font-family: Verdana + font-family: Verdana, sans font-size: 14px background-color = !body_color color = !text_color padding: 1em - + + a + text-decoration: none + font-weight: bold + color = !ot_purple + + a:hover + color = black + .headline logo top: 1% float: right display: inline - font-family: arial + font-family: arial, sans font-size: 2.5em word-spacing: -2px @@ -35,7 +45,7 @@ body letter-spacing: -3px span2 - color: #5D308A + color = !ot_purple font-weight: 500 position: relative left: -6px @@ -44,14 +54,14 @@ body clear: both ul - margin: 0 + margin: 0 0 2px 0 padding: 0 white-space: nowrap list-style-type: none li margin: 0 - padding: 0 + padding: 2px display: inline border-right: 1px solid color = !body_color @@ -60,6 +70,7 @@ body background-color = !fg_color padding-left: 0.5em padding-right: 0.5em + font-weight: bold a text-decoration: none @@ -68,14 +79,14 @@ body color = !body_color li.selected - font-weight: bolder + font-weight: bold background-color= !bg_color border: 1px solid color = !fg_color border-bottom: 1px solid color = !bg_color a - color = !fg_color + color = !text_color .content @@ -86,12 +97,16 @@ body padding: 1em border: 1px solid color = !fg_color - + + h2 + margin: 20px 3px 2px 3px + .notice //background-color = !body_color padding: 1em - background-color = !bg_color2 - border: 1px solid red + background-color = !body_color + border: 1px solid + border-color = !notice_border .input text-align: left @@ -144,6 +159,7 @@ body padding: 1em background-color = !bg_color2 border: 1px solid + margin-top: 0.6em dt width: 15em font-weight: bold @@ -161,7 +177,7 @@ body background-color = !bg_color2 border: 0 dt - white-space: nowrap + white-spaceborder-top: 2px solid: nowrap width: 15em font-weight: bold float: left -- cgit v1.2.3 From 931d6b1ccba68fc06bae15cc9b5dd0b31880e471 Mon Sep 17 00:00:00 2001 From: mr Date: Mon, 10 May 2010 12:00:52 +0200 Subject: delete models --- application.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/application.rb b/application.rb index 564687e..97b3f06 100755 --- a/application.rb +++ b/application.rb @@ -28,7 +28,7 @@ class ToxCreateModel end def validation_status - RestClient.get(File.join(@validation_task_uri, 'status')).body + #RestClient.get(File.join(@validation_task_uri, 'status')).body end def algorithm @@ -72,7 +72,6 @@ get '/models/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s model.save end -=begin unless @@config[:services]["opentox-model"].match(/localhost/) if !model.validation_uri and model.validation_status == "completed" model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s @@ -82,7 +81,6 @@ get '/models/?' do model.save end end -=end end @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) haml :models @@ -221,7 +219,6 @@ post '/upload' do # create a new model task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :feature_uri => feature_uri) @model.task_uri = task_uri -=begin unless @@config[:services]["opentox-model"].match(/localhost/) validation_task_uri = OpenTox::Validation.crossvalidation( :algorithm_uri => OpenTox::Algorithm::Lazar.uri, @@ -232,7 +229,6 @@ post '/upload' do # create a new model LOGGER.debug "Validation task: " + validation_task_uri @model.validation_task_uri = validation_task_uri end -=end @model.nr_compounds = nr_compounds @model.warnings = '' -- cgit v1.2.3 From 3f81d0d90b579f3bf17ff1c1fbbd56df77fee8c6 Mon Sep 17 00:00:00 2001 From: mr Date: Mon, 10 May 2010 14:49:22 +0200 Subject: some small changes / change delete uri / layout: opentox logo font --- application.rb | 5 +++-- public/javascripts/toxcreate.js | 7 ++----- views/layout.haml | 2 +- views/model.haml | 8 +++----- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/application.rb b/application.rb index 97b3f06..d36c04b 100755 --- a/application.rb +++ b/application.rb @@ -86,12 +86,13 @@ get '/models/?' do haml :models end -delete '/model/:id/delete/?' do +delete '/model/:id/?' do model = ToxCreateModel.get(params[:id]) begin RestClient.delete model.uri if model.uri RestClient.delete model.task_uri if model.task_uri rescue + flash[:notice] = "#{model.name} model delete error." end model.destroy! flash[:notice] = "#{model.name} model deleted." @@ -104,7 +105,7 @@ get '/model/:id/status/?' do begin haml :model_status, :locals=>{:model=>model}, :layout => false rescue - + return "unavailable" end end diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index 890f6d0..d341c4d 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -48,7 +48,8 @@ $(function() { } }, error: function(data) { - alert("status check error"); + //alert("status check error"); + id = -1; } }); return id; @@ -66,9 +67,7 @@ $(function() { '_method': 'get' }, success: function(data) { - $("div#model_" + id).animate({"opacity": "0.1"},1000).delay(100); $("div#model_" + id).html(data); - $("div#model_" + id).animate({"opacity": "1"},1000).delay(100); }, error: function(data) { alert("loadModel error"); @@ -108,5 +107,3 @@ jQuery.fn.deleteModel = function(type, options) { return false; }); }; - - diff --git a/views/layout.haml b/views/layout.haml index 8b09fbd..3c5dccc 100755 --- a/views/layout.haml +++ b/views/layout.haml @@ -46,4 +46,4 @@ %a{:href => 'http://www.in-silico.ch'} in silico toxicology -#%a{:href => 'http://www.opentox.org'} OpenTox 2009-2010, powered by - %a{:href => 'http://www.opentox.org'} OpenTox + %a{:href => 'http://www.opentox.org'} OpenTox diff --git a/views/model.haml b/views/model.haml index cfcf6f3..da7652e 100644 --- a/views/model.haml +++ b/views/model.haml @@ -14,10 +14,10 @@ %span{:id => "model_#{model.id}_status", :class => model.status} = haml :model_status, :locals=>{:model=>model}, :layout => false ( - %a{:href => url_for("/model/#{model.id}/delete"), :id => "delete_#{model.id}", :class => 'delete'} delete + %a{:href => url_for("/model/#{model.id}"), :id => "delete_#{model.id}", :class => 'delete'} delete ) %dt Started: - %dd= model.created_at + %dd= model.created_at.strftime("%m/%d/%Y - %I:%M:%S%p") %dt Training compounds: %dd= model.nr_compounds %dt Warnings: @@ -43,8 +43,6 @@ %a{:href => "#{model.training_dataset}.rdf"} RDF/XML , %a{:href => "#{model.training_dataset}.yaml"} YAML - , - %a{:href => "#{model.training_dataset}.html"} HTML %em (more formats to be added) %dt Feature dataset: %dd @@ -74,4 +72,4 @@ -# else %em under construction = image_tag("/snake_transparent.gif") - =# model.validation_task_uri \ No newline at end of file + =# model.validation_task_uri -- cgit v1.2.3 From 2c9c169642a7f3211066d7a5d759fe64fbe70e75 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 10 May 2010 18:45:22 +0200 Subject: Validation service integrated --- application.rb | 16 +++-- public/JME.class | Bin 0 -> 26321 bytes public/JME.jar | Bin 0 -> 38760 bytes public/jme-200606.jar | Bin 0 -> 37255 bytes public/jme.js | 11 +++ public/jme_help.html | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++ views/models.haml | 65 ++++++++++++++++- views/predict.haml | 24 +++++-- 8 files changed, 299 insertions(+), 12 deletions(-) create mode 100644 public/JME.class create mode 100644 public/JME.jar create mode 100644 public/jme-200606.jar create mode 100644 public/jme.js create mode 100644 public/jme_help.html diff --git a/application.rb b/application.rb index e06d1d3..cdc669b 100644 --- a/application.rb +++ b/application.rb @@ -18,6 +18,7 @@ class ToxCreateModel property :task_uri, String, :length => 255 property :validation_task_uri, String, :length => 255 property :validation_uri, String, :length => 255 + property :validation_report_task_uri, String, :length => 255 property :validation_report_uri, String, :length => 255 property :warnings, Text, :length => 2**32-1 property :nr_compounds, Integer @@ -31,6 +32,10 @@ class ToxCreateModel RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body end + def validation_report_status + RestClient.get(File.join(@validation_report_task_uri, 'hasStatus')).body + end + def algorithm RestClient.get(File.join(@uri, 'algorithm')).body end @@ -74,12 +79,15 @@ get '/models/?' do end unless @@config[:services]["opentox-model"].match(/localhost/) if !model.validation_uri and model.validation_status == "Completed" - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body.to_s + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s - LOGGER.debug "Validation Report URI: #{model.validation_report_uri}" + model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body + LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" model.save end + if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' + model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body + end end end @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) @@ -186,7 +194,7 @@ post '/upload' do # create a new model :prediction_feature => feature_uri, :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" ).uri - LOGGER.debug "Validation task: " + validation_task_uri + #LOGGER.debug "Validation task: " + validation_task_uri @model.validation_task_uri = validation_task_uri end diff --git a/public/JME.class b/public/JME.class new file mode 100644 index 0000000..9efda0e Binary files /dev/null and b/public/JME.class differ diff --git a/public/JME.jar b/public/JME.jar new file mode 100644 index 0000000..d571682 Binary files /dev/null and b/public/JME.jar differ diff --git a/public/jme-200606.jar b/public/jme-200606.jar new file mode 100644 index 0000000..9cae5e7 Binary files /dev/null and b/public/jme-200606.jar differ diff --git a/public/jme.js b/public/jme.js new file mode 100644 index 0000000..02a213f --- /dev/null +++ b/public/jme.js @@ -0,0 +1,11 @@ +function getsmiles() { + if (document.JME.smiles() != '') { + $('smiles').value = document.JME.smiles() ; + } +} + +function getsmarts() { + if (document.JME.smiles() != '') { + $('smarts').value = document.JME.smiles() ; + } +} diff --git a/public/jme_help.html b/public/jme_help.html new file mode 100644 index 0000000..ab4942a --- /dev/null +++ b/public/jme_help.html @@ -0,0 +1,195 @@ + + + + + + + + JME Help + + + + + + +

JME Molecular Editor

+ +

Written by Peter Ertl, Novartis Pharma + AG

+ +

Basic Instructions

+ +

This editor is intended to be used without any special + documentation or training, but there are some tricks which + can help you to work with it more efficiently.

+ +

Menu Buttons

+ +
    +
  • D-R deletes functional groups - choose this + option and then click on the bond connecting the group + with the main skeleton
  • + +
  • UDO undo last editing step
  • + +
  • QRY (if enabled in the param tag) allows easy + specification of atomic queries for substructure + searches
  • + +
  • Stereo bonds - the type of stereo bond (up, + down) may be changed by clicking on the already created + stereo bond; this cycles through two / four possible + stereo bond types
  • + +
  • Atomic charges may be changed by the + +/- button. Editor enables modification of charges + only in "reasonable" cases. If you are not satisfied with + the editor's inteligence (concerning charges and the + explicit number of hydrogens) you can force your will by + using the X button
  • + +
  • "Non-organic" atoms or atoms with nonstandard + valence may be entered with help of X button by + specifying atomic SMILES (without [ ] brackets, i.e. Si, + Fe++, NH3+).
  • +
+ +

Keyboard Shortcuts

+ +

Most of the commands may be accessed also by keyboard + shortcuts. It is possible to:

+ +
    +
  • change atom type by pressing C, + N, O, S, F, L (for Cl) + B (for Br) I, P, H, X, + R and clicking the respective atom
  • + +
  • choose bond order: - for single bond, + = for double bond, # for triple bond
  • + +
  • choose ring type by pressing 3, + 4, 5, 6, 7, 8, + 9 or 1 for phenyl, 0 for furyl
  • + +
  • start delete mode by pressing D or + Del and
  • + +
  • return to the standard state (carbon, single + bond) with Esc
  • +
+ +

common functional groups may also be added by + keyboard shortcuts. Use t for t-butyl, ft for + trifluoromethyl, lt for trichloromethyl, a + for COOH, z for SO2Me and y for nitro, and + then click the atom where the group should be + connected.

+ +

Moving and Rotation

+ +

You can move molecule by "dragging free space" with the + left mouse button and rotate it by using the left mouse + button and Shift key (or left and right mouse + buttons together).

+ +

Adding rings

+ +

When a ring template is selected and multivalent atom is + clicked, a new ring will be created connected by single + bond to this atom. When spiro ring is required, the + Shift key must be pressed when clicking on the atom. + Spiro ring may be added only to atom with 2 single + bonds.

+ +

Multivalent nitrogen groups

+ +

Multivalent nitrogen groups, such as nitro, azide, + N-oxide, nitrile etc, should be drawn with a pentavalent + nitrogen as shown below.

+ +

+

+ +

The program automatically converts polar form of these + groups into non-polar one with pentavalent nitrogen. If you + prefer polar nitro (and similar) groups, use keyword + "polarnitro" in the applet param tag.

+ +

Stereochemistry

+ +

Stereochemistry at C4 centers, double bonds and allenes + is supported. Use the up/down wedge bonds to indicate + stereochemistry at the C4 centers. Remember, that only + bonds with a "sharp point" towards the atom are considered. + When creating SMILES the editor tries to guess missing + stereo features, in unresolvable cases an error message is + issued and the SMILES without stereo information is + created.

+ +

When the autoez keyword is set, SMILES with E,Z + stereochemistry on all non-ring double bonds is generated + automatically. Without this keyword (or for ring double + bonds) you have to mark a double bond as stereo by clicking + on it with the stereo bond button selected. The bond color + will change to violet.

+ +

Stereochemistry may be completely disabled by the + "nostereo" option in the param tag.

+ +

Input of Multipart Structures

+ +

By default only non-disconnected structures are allowed. + This may be changed by a "multipart" option in the applet + param tag. A button NEW appears in the JME menu. + Creation of a new molecule may be started only after + clicking the NEW button, selecting a proper template + (atom, ring, bond) and clicking free space in the drawing + area. Without NEW button the click on the free space + has the same effect as in the standard mode (i.e moving or + rotation of the last touched molecule). In the multipart + mode CLR button deletes the last touched + molecule.

+ +

Atom Numbering

+ +

Atom numbering (marking) is enabled with the option + "number" in the applet param tag (for reaction input this + is default). Button 123 appears in the JME menu. To + mark an atom press the 123 button and then the atom. + You can mark more atoms with the same number when pressing + Shift while clicking the 2nd and further atoms. + Second click on the marked atom deletes the number.

+ +

Reaction Input

+ +

Reaction input is enabled with the option "reaction" in + the applet param tag. Button with an arrow, NEW + button and 123 button appear in the JME menu and + arrow appears also in the drawing area. Now simply draw + reactant(s), product(s) and modulator(s) (modulators have + to be above the arrow) as explained in the description of + input of multipart structures. The arrow button enables + simplified input of reactions. After clicking it, the + reactant will be copied to the product (including atom + numbering, if any). When the Shift is pressed during + this action all atoms will be automatically numbered.

+ +

Query Features

+ +

Query button (when enabled in the option tag) launches a + query window which allows creation of SMARTS atom queries + by combining various atom attributes. Create a SMARTS query + and then click the respective atom in the + molecule.

+ + diff --git a/views/models.haml b/views/models.haml index 57e8907..cbd6813 100644 --- a/views/models.haml +++ b/views/models.haml @@ -55,17 +55,76 @@ , %a{:href => "#{model.uri}.yaml"} YAML %em (more formats to be added) - %dt Validation: + %dt + Validation: + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) %dd - if model.validation_uri - uri = File.join(model.validation_uri, 'statistics') - - yaml = RestClient.get(uri).to_s + - yaml = RestClient.get(uri).body - v = YAML.load(yaml) + - tp=0; tn=0; fp=0; fn=0; n=0 + - v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell| + - if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true" + - tp = cell[:confusion_matrix_value] + - n += tp + - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false" + - tn = cell[:confusion_matrix_value] + - n += tn + - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true" + - fn = cell[:confusion_matrix_value] + - n += fn + - elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false" + - fp = cell[:confusion_matrix_value] + - n += fp + + + -#%pre + = yaml %dl + %dt Number of predictions: + %dd= n %dt Correct predictions: %dd - = v[:classification_statistics][:percent_correct].to_s + =# sprintf("%.2f", v[:classification_statistics][:percent_correct].to_f) + = sprintf("%.2f", 100*(tp+tn).to_f/n) = '%' + %dt + %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: + %dd + = sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f) + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: + %dd= sprintf("%.3f", tn.to_f/(tn+fp)) + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: + %dd= sprintf("%.3f", tp.to_f/(tp+fn)) + -# %dd + + -# %dt Precision: + -# %dd + = v[:classification_statistics][:class_value_statistics][0][:precision].to_s + = '%' + %dt + %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: + %dd + %table + %tr + %th + %th Measured + %tr + %th Predicted + %th active + %th inactive + %tr + %th active + %td= tp + %td= fp + %tr + %th inactive + %td= fn + %td= tn - else = image_tag("/snake_transparent.gif") if model.validation_status == "Running" = model.validation_status diff --git a/views/predict.haml b/views/predict.haml index f69b583..26c8094 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -1,11 +1,25 @@ +:javascript + function getsmiles() { + if (document.JME.smiles() != '') { + document.form.identifier.value = document.JME.smiles() ; + } + } + .input %p Use this service to obtain predictions from OpenTox models. - unless @models.empty? - %form{ :action => url_for('/predict'), :method => "post", :enctype => "multipart/form-data" } + + %form{:name => "form", :action => url_for('/predict'), :method => "post", :enctype => "multipart/form-data" } %fieldset - %legend Enter a compound identifier - %label{:for => 'identifier'} Name, InChI, Smiles, CAS, ... - %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '50'} + %legend Draw a compound + %label   + .jme + %applet{:code => "JME.class", :name => "JME", :archive => "JME.jar", :width => "500", :height => "360"} + %param{ :name => "options", :value => "polarnitro"} + Please enable Java and JavaScript in your browser to use the JME editor. + + %label{:for => 'identifier'} or enter a Name, InChI, Smiles, CAS, ... + %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'} %fieldset %legend Choose one or more prediction models @@ -15,6 +29,6 @@ %input{:type => 'checkbox', :name => "selection[#{model.id}]", :value => true, :id => model.id} %br - %input{ :type => "submit", :value => "Predict"} + %input{ :type => "submit", :value => "Predict", :onclick => "getsmiles();"} = link_to 'Cancel', '/predict' -- cgit v1.2.3 From e751e915dea86741901c806da661045e617ae9e1 Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 11 May 2010 16:48:22 +0200 Subject: link to xls trainings data file --- views/model.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/views/model.haml b/views/model.haml index da7652e..25513aa 100644 --- a/views/model.haml +++ b/views/model.haml @@ -43,6 +43,8 @@ %a{:href => "#{model.training_dataset}.rdf"} RDF/XML , %a{:href => "#{model.training_dataset}.yaml"} YAML + , + %a{:href => "#{model.training_dataset}.xls"} XLS %em (more formats to be added) %dt Feature dataset: %dd -- cgit v1.2.3 From 799effa9316512ebff9fea4aacfd5c015a03c9bf Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 12 May 2010 12:31:39 +0200 Subject: Modification for new RestClient: body instead of to_s --- application.rb | 12 ++++++------ views/models.haml | 17 +---------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/application.rb b/application.rb index cdc669b..e30ab09 100644 --- a/application.rb +++ b/application.rb @@ -37,7 +37,11 @@ class ToxCreateModel end def algorithm - RestClient.get(File.join(@uri, 'algorithm')).body + begin + RestClient.get(File.join(@uri, 'algorithm')).body + rescue + "" + end end def training_dataset @@ -74,7 +78,7 @@ get '/models/?' do @models = ToxCreateModel.all(:order => [ :created_at.desc ]) @models.each do |model| if !model.uri and model.status == "Completed" - model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body.to_s + model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body model.save end unless @@config[:services]["opentox-model"].match(/localhost/) @@ -241,12 +245,8 @@ post '/predict/?' do # post chemical name to model title = nil db_activities = [] LOGGER.debug model.inspect - #LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) - #LOGGER.debug prediction.inspect source = prediction.creator - #LOGGER.debug source - #LOGGER.debug prediction.to_yaml if prediction.data[@compound.uri] if source.to_s.match(/model/) prediction = prediction.data[@compound.uri].first.values.first diff --git a/views/models.haml b/views/models.haml index cbd6813..d3bdffc 100644 --- a/views/models.haml +++ b/views/models.haml @@ -1,12 +1,3 @@ --# :javascript - function deletemodel(uri) { - var xmlhttp; - return confirm("Are you sure?"); - xmlhttp=new XMLHttpRequest(); - xmlhttp.open('DELETE',uri,false) - xmlhttp.send(null); - } - %p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. - @models.each do |model| - uri = url_for("/model/#{model.id}", :full) @@ -100,12 +91,6 @@ %dt %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: %dd= sprintf("%.3f", tp.to_f/(tp+fn)) - -# %dd - - -# %dt Precision: - -# %dd - = v[:classification_statistics][:class_value_statistics][0][:precision].to_s - = '%' %dt %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: %dd @@ -127,6 +112,6 @@ %td= tn - else = image_tag("/snake_transparent.gif") if model.validation_status == "Running" - = model.validation_status + %a{:href => model.validation_task_uri} #{model.validation_status} -- cgit v1.2.3 From 372dcccbb935db0614df71e5733f16373ad2d481 Mon Sep 17 00:00:00 2001 From: ch Date: Wed, 12 May 2010 14:12:23 +0200 Subject: opentox-api-wrapper version updated --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index e30ab09..e6c481d 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.4.0' +gem 'opentox-ruby-api-wrapper', '= 1.5.0' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 6aa7745d29445d2198637d6e345661cfa590e4fb Mon Sep 17 00:00:00 2001 From: ch Date: Fri, 14 May 2010 16:00:49 +0200 Subject: Status offline added for validation service --- application.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/application.rb b/application.rb index e6c481d..a152e77 100644 --- a/application.rb +++ b/application.rb @@ -29,11 +29,19 @@ class ToxCreateModel end def validation_status - RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body + begin + RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body + rescue + "Service offline" + end end def validation_report_status - RestClient.get(File.join(@validation_report_task_uri, 'hasStatus')).body + begin + RestClient.get(File.join(@validation_report_task_uri, 'hasStatus')).body + rescue + "Service offline" + end end def algorithm -- cgit v1.2.3 From b5496724fa523054c68d8bb9e8be9aeed799d3b1 Mon Sep 17 00:00:00 2001 From: mr Date: Mon, 17 May 2010 09:07:42 +0200 Subject: merge with new version from helma --- application.rb | 21 ++++++++++++--------- public/javascripts/toxcreate.js | 2 +- views/model.haml | 6 +++--- views/model_status.haml | 5 ++--- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/application.rb b/application.rb index dbdba93..177b641 100755 --- a/application.rb +++ b/application.rb @@ -29,7 +29,7 @@ class ToxCreateModel end def validation_status - RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body + RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body if @validation_task_uri end def validation_report_status @@ -124,19 +124,22 @@ end get '/model/:id/?' do response['Content-Type'] = 'text/plain' model = ToxCreateModel.get(params[:id]) - if !model.uri and model.status == "completed" - model.uri = RestClient.get(File.join(model.task_uri, 'resource')).to_s - model.save - end + if !model.uri and model.status == "Completed" + model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body + model.save + end =begin unless @@config[:services]["opentox-model"].match(/localhost/) - if !model.validation_uri and model.validation_status == "completed" - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resource')).to_s + if !model.validation_uri and model.validation_status == "Completed" + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => validation_uri).to_s - LOGGER.debug "Validation Report URI: #{model.validation_report_uri}" + model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body + LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" model.save end + if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' + model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body + end end =end diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index d341c4d..dd2b584 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -36,7 +36,7 @@ $(function() { '_method': 'get' }, success: function(data) { - var erg = data.search(/started/); + var erg = data.search(/Running/); status_changed = false; if(erg < 0) status_changed = true; $("span#model_" + id + "_status").animate({"opacity": "0.1"},1000); diff --git a/views/model.haml b/views/model.haml index affc25a..f676465 100644 --- a/views/model.haml +++ b/views/model.haml @@ -27,7 +27,7 @@ %a{:href => "#", :id => "show_model_#{model.id}_warnings"} show %dd{:id => "model_#{model.id}_warnings", :style => "display: none;"}= model.warnings - - if model.status == 'completed' + - if model.status == 'Completed' %dt Algorithm: %dd %a{:href => model.algorithm} #{File.basename model.algorithm} @@ -56,8 +56,8 @@ %a{:href => "#{model.uri}.yaml"} YAML %em (more formats to be added) %dt Validation: - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) %dd - if model.validation_uri - uri = File.join(model.validation_uri, 'statistics') diff --git a/views/model_status.haml b/views/model_status.haml index 91afb0d..1357d99 100755 --- a/views/model_status.haml +++ b/views/model_status.haml @@ -1,3 +1,2 @@ -- if model.status.match(/started|created/) - = image_tag("/snake_transparent.gif") -= model.status \ No newline at end of file += image_tag("/snake_transparent.gif") if model.status.match(/running|started|created/i) += model.status -- cgit v1.2.3 From 261083e81ee6345481a03774a5ce9f7276385b05 Mon Sep 17 00:00:00 2001 From: mr Date: Mon, 17 May 2010 17:56:40 +0200 Subject: turn off javascript error messages --- public/javascripts/toxcreate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index dd2b584..8c5a6a8 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -70,7 +70,7 @@ $(function() { $("div#model_" + id).html(data); }, error: function(data) { - alert("loadModel error"); + //alert("loadModel error"); } }); return false; @@ -100,7 +100,7 @@ jQuery.fn.deleteModel = function(type, options) { $(opts.elem).fadeTo("slow",0).slideUp("slow"); }, error: function(data) { - alert("model delete error!"); + //alert("model delete error!"); } }); } -- cgit v1.2.3 From d4d9fad65606250b1372f3ba7cfd6a77bed3f139 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 18 May 2010 11:52:26 +0200 Subject: api-wrapper version 1.5.1 --- application.rb | 62 +++++++++++++++++++++------------------------------ views/model.haml | 7 +++--- views/prediction.haml | 9 +++++++- views/style.sass | 2 +- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/application.rb b/application.rb index 08f7bae..0dd84f4 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.5.0' +gem 'opentox-ruby-api-wrapper', '= 1.5.1' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' @@ -68,26 +68,9 @@ class ToxCreateModel end end -end - -DataMapper.auto_upgrade! - -helpers do - def activity(a) - case a.to_s - when "true" - act = "active" - when "false" - act = "inactive" - else - act = "not available" - end - act - end - - def validation(model) + def validation begin - uri = File.join(model.validation_uri, 'statistics') + uri = File.join(@validation_uri, 'statistics') yaml = RestClient.get(uri).body v = YAML.load(yaml) tp=0; tn=0; fp=0; fn=0; n=0 @@ -121,6 +104,24 @@ helpers do "Service not available" end end + +end + +DataMapper.auto_upgrade! + +helpers do + def activity(a) + case a.to_s + when "true" + act = "active" + when "false" + act = "inactive" + else + act = "not available" + end + act + end + end get '/?' do @@ -181,22 +182,7 @@ get '/model/:id/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body model.save end -=begin - unless @@config[:services]["opentox-model"].match(/localhost/) - if !model.validation_uri and model.validation_status == "Completed" - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body - LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" - model.save - end - if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' - model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body - end - end -=end - - @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) + @refresh = true begin haml :model, :locals=>{:model=>model}, :layout => false @@ -224,6 +210,10 @@ get '/csv_format' do haml :csv_format end +get "/confidence" do + haml :confidence +end + get '/tasks' do @tasks = OpenTox::Task.all haml :tasks diff --git a/views/model.haml b/views/model.haml index 519b9a9..9439933 100644 --- a/views/model.haml +++ b/views/model.haml @@ -36,11 +36,11 @@ %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes %dt Training dataset: %dd + %a{:href => "#{model.training_dataset}.xls"} XLS + , %a{:href => "#{model.training_dataset}.rdf"} RDF/XML , %a{:href => "#{model.training_dataset}.yaml"} YAML - , - %a{:href => "#{model.training_dataset}.xls"} XLS %em (more formats to be added) %dt Feature dataset: %dd @@ -55,11 +55,12 @@ %a{:href => "#{model.uri}.yaml"} YAML %em (more formats to be added) %dt Validation: + = model.validation_uri - if model.validation_report_uri %a{:href => model.validation_report_uri, :target => "_blank"} (more details) %dd - if model.validation_uri - - v = validation(model) + - v = model.validation - if v == "Service not available" = v - else diff --git a/views/prediction.haml b/views/prediction.haml index 96fe54d..28bedd4 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -34,4 +34,11 @@ %em= p[:prediction] - if p[:confidence] %br - = "(confidence: #{sprintf('%.03f', p[:confidence].to_f.abs)})" + ( Confidence: + = sprintf('%.03f', p[:confidence].to_f.abs) + ) + +%dl + %dt Confidence: + %dd 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 distiguish between reliable and unreliable predictions. + diff --git a/views/style.sass b/views/style.sass index 43bffd9..cdfc9d5 100644 --- a/views/style.sass +++ b/views/style.sass @@ -33,7 +33,7 @@ body logo top: 1% float: right - display: inline + //display: inline font-size: 2.5em word-spacing: -2px -- cgit v1.2.3 From 32ef55b0460ba2c3fe7aac55ed5cead7a3ee0255 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 18 May 2010 12:26:25 +0200 Subject: wrapper version bumped to 1.5.1 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index a152e77..80ceed3 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.5.0' +gem 'opentox-ruby-api-wrapper', '= 1.5.1' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 95fa563016b05f430c405a47f0d6b409b65d2a0d Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 18 May 2010 13:43:15 +0200 Subject: fix stylesheet bug --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index 43bffd9..719a899 100644 --- a/views/style.sass +++ b/views/style.sass @@ -175,7 +175,7 @@ body background-color = !bg_color2 border: 0 dt - white-spaceborder-top: 2px solid: nowrap + white-space: nowrap width: 15em font-weight: bold float: left -- cgit v1.2.3 From 7b1e97d83136c06d6901543eec7a06c5e62b4e46 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 18 May 2010 16:20:58 +0200 Subject: layout adjusted --- application.rb | 5 ++--- views/layout.haml | 19 +++++++++---------- views/model.haml | 18 +++++++++--------- views/models.haml | 2 +- views/prediction.haml | 4 +--- views/style.sass | 40 ++++++++++++++++++++++------------------ 6 files changed, 44 insertions(+), 44 deletions(-) diff --git a/application.rb b/application.rb index 0dd84f4..090b751 100755 --- a/application.rb +++ b/application.rb @@ -25,6 +25,7 @@ class ToxCreateModel property :created_at, DateTime def status + ##LOGGER.debug RestClient.get(File.join(@task_uri, 'hasStatus')).body RestClient.get(File.join(@task_uri, 'hasStatus')).body end @@ -101,7 +102,7 @@ class ToxCreateModel :specificity => sprintf("%.3f", tn.to_f/(tn+fp)) } rescue - "Service not available" + "Service offline" end end @@ -148,7 +149,6 @@ get '/models/?' do end end end - @refresh = true #if @models.collect{|m| m.status}.grep(/started|created/) haml :models end @@ -182,7 +182,6 @@ get '/model/:id/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body model.save end - @refresh = true begin haml :model, :locals=>{:model=>model}, :layout => false diff --git a/views/layout.haml b/views/layout.haml index 919e965..012e296 100755 --- a/views/layout.haml +++ b/views/layout.haml @@ -3,19 +3,17 @@ %head %meta{'http-equiv' => 'Content-Type', :content => 'text/html'} - - if @refresh - - # %meta{'http-equiv' => "refresh", :content => "15"} %title ToxCreate %script{:type => "text/javascript", :src => "javascripts/jquery.js"} %script{:type => "text/javascript", :src => "javascripts/toxcreate.js"} %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body - -# .logo= image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate' - .headline - %logo - %span1="Tox" - %span2="Create" + .logo= image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate', :align => "right" + -#.headline + .logo + .span1="Tox" + .span2="Create" .index %ul @@ -30,9 +28,10 @@ .content - .notice - This service is for testing purposes only - once a week all models will be deleted. Please send bug reports and feature requests to our - %a{:href => 'http://github.com/helma/opentox-toxmodel/issues'} issue tracker. + - if `hostname`.match(/ot-test|ot-dev/) + .notice + This service is for testing purposes only - once a week all models will be deleted. Please send bug reports and feature requests to our + %a{:href => 'http://github.com/helma/opentox-toxmodel/issues'} issue tracker. - if flash[:notice] %p diff --git a/views/model.haml b/views/model.haml index 9439933..b255e80 100644 --- a/views/model.haml +++ b/views/model.haml @@ -36,28 +36,28 @@ %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes %dt Training dataset: %dd - %a{:href => "#{model.training_dataset}.xls"} XLS + %a{:href => "#{model.training_dataset}.xls"} Excel sheet , %a{:href => "#{model.training_dataset}.rdf"} RDF/XML - , + %em (experts) , %a{:href => "#{model.training_dataset}.yaml"} YAML - %em (more formats to be added) + %em (experts) %dt Feature dataset: %dd %a{:href => "#{model.feature_dataset}.rdf"} RDF/XML , %a{:href => "#{model.feature_dataset}.yaml"} YAML - %em (more formats to be added) + %em (experts, dataset too large for Excel) %dt Model: %dd %a{:href => "#{model.uri}.rdf"} RDF/XML , %a{:href => "#{model.uri}.yaml"} YAML - %em (more formats to be added) - %dt Validation: - = model.validation_uri - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) + %em (experts, models cannot be exported in Excel) + %dt + Validation: + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) %dd - if model.validation_uri - v = model.validation diff --git a/views/models.haml b/views/models.haml index 3d17c36..c11aaa7 100755 --- a/views/models.haml +++ b/views/models.haml @@ -1,4 +1,4 @@ -- stati = @models.map{|m| "#{m.id}" if m.status != "completed"}.compact +- stati = @models.map{|m| "#{m.id}" if m.status != "Completed"}.compact - stati_to_check = stati.length > 0 ? stati.join(", ") : stati = 0 :javascript $(function() { diff --git a/views/prediction.haml b/views/prediction.haml index 28bedd4..74832a2 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -34,9 +34,7 @@ %em= p[:prediction] - if p[:confidence] %br - ( Confidence: - = sprintf('%.03f', p[:confidence].to_f.abs) - ) + = "(Confidence: #{sprintf('%.03f', p[:confidence].to_f.abs)})" %dl %dt Confidence: diff --git a/views/style.sass b/views/style.sass index 474cf56..80ab220 100644 --- a/views/style.sass +++ b/views/style.sass @@ -30,23 +30,27 @@ body .headline - logo - top: 1% + .logo float: right - //display: inline - font-size: 2.5em - word-spacing: -2px - - span1 - color: black - font-weight: bolder - letter-spacing: -3px - - span2 - color = !ot_purple - font-weight: 500 - position: relative - left: -6px + + /* + .logo + top: 1% + float: right + //display: inline + font-size: 2.5em + word-spacing: -2px + + .span1 + color: black + font-weight: bolder + letter-spacing: -3px + + .span2 + color = !ot_purple + font-weight: 500 + position: relative + left: -6px .index clear: both @@ -143,11 +147,11 @@ body color = !body_color background-color = !fg_color border: 1px solid - :margin 2% + :margin 0.5em td :border 1px solid background-color = !bg_color2 - :padding 2% + :padding 0.5em img padding: 0 height: 100% -- cgit v1.2.3 From 1691549ce7fb6f50f7231c5a1102163c1595c587 Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 18 May 2010 20:11:23 +0200 Subject: upload csv, xls and xlsx files for modelcreating --- application.rb | 101 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/application.rb b/application.rb index 177b641..cc704b1 100755 --- a/application.rb +++ b/application.rb @@ -5,6 +5,7 @@ gem 'opentox-ruby-api-wrapper', '= 1.5.0' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' +require 'spreadsheet' LOGGER.progname = File.expand_path __FILE__ use Rack::Flash @@ -201,35 +202,77 @@ post '/upload' do # create a new model duplicates = {} nr_compounds = 0 line_nr = 1 - params[:file][:tempfile].each_line do |line| - unless line.chomp.match(/^.+[,;].*$/) # check CSV format - not all browsers provide correct content-type - flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." - redirect url_for('/create') - end - items = line.chomp.split(/\s*[,;]\s*/) - smiles = items[0] - c = OpenTox::Compound.new(:smiles => smiles) - if c.inchi != "" - duplicates[c.inchi] = [] unless duplicates[c.inchi] - duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp - compound_uri = c.uri - dataset.compounds << compound_uri - dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - case items[1].to_s - when '1' - dataset.data[compound_uri] << {feature_uri => true } - nr_compounds += 1 - when '0' - dataset.data[compound_uri] << {feature_uri => false } - nr_compounds += 1 - else - activity_errors << "Line #{line_nr}: " + line.chomp - end - else - smiles_errors << "Line #{line_nr}: " + line.chomp - end - line_nr += 1 - end + + case params[:file][:type] + when "application/csv", "text/csv" + params[:file][:tempfile].each_line do |line| + unless line.chomp.match(/^.+[,;].*$/) # check CSV format - not all browsers provide correct content-type + flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." + redirect url_for('/create') + end + items = line.chomp.split(/\s*[,;]\s*/) + smiles = items[0] + c = OpenTox::Compound.new(:smiles => smiles) + if c.inchi != "" + duplicates[c.inchi] = [] unless duplicates[c.inchi] + duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp + compound_uri = c.uri + dataset.compounds << compound_uri + dataset.data[compound_uri] = [] unless dataset.data[compound_uri] + case items[1].to_s + when '1' + dataset.data[compound_uri] << {feature_uri => true } + nr_compounds += 1 + when '0' + dataset.data[compound_uri] << {feature_uri => false } + nr_compounds += 1 + else + activity_errors << "Line #{line_nr}: " + line.chomp + end + else + smiles_errors << "Line #{line_nr}: " + line.chomp + end + line_nr += 1 + end + when "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + require 'roo' + require 'ftools' + excel = 'tmp/' + params[:file][:filename] + name = params[:file][:filename] + File.mv(params[:file][:tempfile].path,excel) + if params[:file][:type] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + book = Excelx.new(excel) + else + book = Excel.new(excel) + end + book.default_sheet = 0 + 1.upto(book.last_row) do |row| + smiles = book.cell(row,1) + c = OpenTox::Compound.new(:smiles => smiles) + if c.inchi != "" + duplicates[c.inchi] = [] unless duplicates[c.inchi] + duplicates[c.inchi] << "Line #{line_nr}: " + book.cell(row,1).chomp + compound_uri = c.uri + dataset.compounds << compound_uri + dataset.data[compound_uri] = [] unless dataset.data[compound_uri] + case book.cell(row,2).to_s + when '1' + dataset.data[compound_uri] << {feature_uri => true } + nr_compounds += 1 + when '0' + dataset.data[compound_uri] << {feature_uri => false } + nr_compounds += 1 + else + activity_errors << "Line #{line_nr}: " + book.cell(row,1).chomp + end + else + smiles_errors << "Line #{line_nr}: " + book.cell(row,1).chomp + end + line_nr += 1 + end + else + LOGGER.error "Fileupload Error: " + params[:file].inspect + end dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) @model.task_uri = task_uri -- cgit v1.2.3 From d82222d6b17824606d459769de00c1fa13b2d437 Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 18 May 2010 20:12:37 +0200 Subject: updated views --- views/model.haml | 105 +++++++++++++++++++++++------------------------------- views/models.haml | 2 +- 2 files changed, 45 insertions(+), 62 deletions(-) diff --git a/views/model.haml b/views/model.haml index f676465..644c5f3 100644 --- a/views/model.haml +++ b/views/model.haml @@ -55,69 +55,52 @@ , %a{:href => "#{model.uri}.yaml"} YAML %em (more formats to be added) - %dt Validation: - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) + %dt + Validation: + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) %dd - if model.validation_uri - - uri = File.join(model.validation_uri, 'statistics') - - yaml = RestClient.get(uri).body - - v = YAML.load(yaml) - - tp=0; tn=0; fp=0; fn=0; n=0 - - v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell| - - if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true" - - tp = cell[:confusion_matrix_value] - - n += tp - - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false" - - tn = cell[:confusion_matrix_value] - - n += tn - - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true" - - fn = cell[:confusion_matrix_value] - - n += fn - - elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false" - - fp = cell[:confusion_matrix_value] - - n += fp - - - -#%pre - = yaml - %dl - %dt Number of predictions: - %dd= n - %dt Correct predictions: - %dd - =# sprintf("%.2f", v[:classification_statistics][:percent_correct].to_f) - = sprintf("%.2f", 100*(tp+tn).to_f/n) - = '%' - %dt - %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: - %dd - = sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f) - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: - %dd= sprintf("%.3f", tn.to_f/(tn+fp)) - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: - %dd= sprintf("%.3f", tp.to_f/(tp+fn)) - %dt - %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: - %dd - %table - %tr - %th - %th Measured - %tr - %th Predicted - %th active - %th inactive - %tr - %th active - %td= tp - %td= fp - %tr - %th inactive - %td= fn - %td= tn + - v = model.validation + - if v == "Service not available" + = v + - else + %dl + %dt Number of predictions: + %dd= v[:n] + %dt Correct predictions: + %dd + = v[:correct_predictions] + = '%' + %dt + %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: + %dd + = v[:weighted_area_under_roc] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: + %dd= v[:specificity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: + %dd= v[:sensitivity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: + %dd + %table + %tr + %th + %th Measured + %tr + %th Predicted + %th active + %th inactive + %tr + %th active + %td= v[:tp] + %td= v[:fp] + %tr + %th inactive + %td= v[:fn] + %td= v[:tn] - else = image_tag("/snake_transparent.gif") if model.validation_status == "Running" %a{:href => model.validation_task_uri} #{model.validation_status} \ No newline at end of file diff --git a/views/models.haml b/views/models.haml index 3d17c36..c11aaa7 100755 --- a/views/models.haml +++ b/views/models.haml @@ -1,4 +1,4 @@ -- stati = @models.map{|m| "#{m.id}" if m.status != "completed"}.compact +- stati = @models.map{|m| "#{m.id}" if m.status != "Completed"}.compact - stati_to_check = stati.length > 0 ? stati.join(", ") : stati = 0 :javascript $(function() { -- cgit v1.2.3 From 0e488afddfa563f3057b053958b2109be7a9bb90 Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 18 May 2010 23:17:52 +0200 Subject: javascript delete with predelete reduce of opacity, toggle warnings do not jump to top of page --- public/javascripts/toxcreate.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index 8c5a6a8..47fab03 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -10,8 +10,8 @@ $(function() { $("dd#model_" + id + "_warnings").slideUp("slow"); $("a#show_model_" + id + "_warnings").html("show"); } + return false; }); - return false; }; checkStati = function(stati) { @@ -89,6 +89,7 @@ jQuery.fn.deleteModel = function(type, options) { var opts = $.extend(defaults, options); this.bind(opts.trigger_on, function() { if(confirm(opts.confirm_message)) { + $(opts.elem).fadeTo("slow",0.5); $.ajax({ type: opts.method, url: opts.action, -- cgit v1.2.3 From 9b19f1c64f2b8e3973169608e684e4adc4a35387 Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 18 May 2010 23:20:52 +0200 Subject: fix for empty cells --- application.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application.rb b/application.rb index b32d1c8..770b259 100755 --- a/application.rb +++ b/application.rb @@ -293,7 +293,7 @@ post '/upload' do # create a new model c = OpenTox::Compound.new(:smiles => smiles) if c.inchi != "" duplicates[c.inchi] = [] unless duplicates[c.inchi] - duplicates[c.inchi] << "Line #{line_nr}: " + book.cell(row,1).chomp + duplicates[c.inchi] << "Line #{line_nr}: " + smiles if smiles compound_uri = c.uri dataset.compounds << compound_uri dataset.data[compound_uri] = [] unless dataset.data[compound_uri] @@ -305,15 +305,15 @@ post '/upload' do # create a new model dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else - activity_errors << "Line #{line_nr}: " + book.cell(row,1).chomp + activity_errors << "Line #{line_nr}: " + smiles if smiles end else - smiles_errors << "Line #{line_nr}: " + book.cell(row,1).chomp + smiles_errors << "Line #{line_nr}: " + smiles if smiles end line_nr += 1 end else - LOGGER.error "Fileupload Error: " + params[:file].inspect + LOGGER.error "Fileupload (Excel) Error: " + params[:file].inspect end dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) -- cgit v1.2.3 From 8d70191a19b53fdd70ee5d98462ca5c2def7f343 Mon Sep 17 00:00:00 2001 From: mr Date: Wed, 19 May 2010 18:32:43 +0200 Subject: stylesheets for validation --- views/style.sass | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/views/style.sass b/views/style.sass index 80ab220..d1138de 100644 --- a/views/style.sass +++ b/views/style.sass @@ -170,12 +170,13 @@ body //display: block dd clear: right + margin: 0.2em 0em //display: block - + dl //display: block clear: both - padding: 1em + padding: 1em background-color = !bg_color2 border: 0 dt @@ -186,6 +187,7 @@ body clear: right dd //padding-left: 2em + .footer margin: 0.5em @@ -196,3 +198,16 @@ body .inactive color: green +dl + dd + td + border: 1px dotted #FFFFFF + text-align: left + padding: 0.2em + th + border-bottom: 1px dotted #FFFFFF + text-align: left + background-color: #CCD2DC + padding: 0.2em + table + border-collapse: collapse \ No newline at end of file -- cgit v1.2.3 From 45ff8cea76fb98b4121014cfdf0d8202700a2a63 Mon Sep 17 00:00:00 2001 From: mr Date: Wed, 19 May 2010 23:57:55 +0200 Subject: fix for IE mime-type plain/text for csv --- application.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/application.rb b/application.rb index 770b259..13da470 100755 --- a/application.rb +++ b/application.rb @@ -187,11 +187,10 @@ get '/model/:id/?' do begin haml :model, :locals=>{:model=>model}, :layout => false rescue - return "unable to renderd model" + return "unable to render model" end end - get '/predict/?' do @models = ToxCreateModel.all(:order => [ :created_at.desc ]) @models = @models.collect{|m| m if m.status == 'Completed'}.compact @@ -246,7 +245,7 @@ post '/upload' do # create a new model line_nr = 1 case params[:file][:type] - when "application/csv", "text/csv" + when "application/csv", "text/csv", "text/plain" params[:file][:tempfile].each_line do |line| unless line.chomp.match(/^.+[,;].*$/) # check CSV format - not all browsers provide correct content-type flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." -- cgit v1.2.3 From e7cf59710ed84378e70c790919c785a41715ed68 Mon Sep 17 00:00:00 2001 From: mr Date: Thu, 20 May 2010 00:00:37 +0200 Subject: split validation view, reload model if model.validation_satus is not 'Completed' --- public/javascripts/toxcreate.js | 11 ++++++++- views/model.haml | 51 ++--------------------------------------- views/model_validation.haml | 50 ++++++++++++++++++++++++++++++++++++++++ views/models.haml | 2 ++ 4 files changed, 64 insertions(+), 50 deletions(-) create mode 100644 views/model_validation.haml diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index 47fab03..f2523b3 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -76,7 +76,16 @@ $(function() { return false; }; - + checkValidation = function() { + var reload_id = ""; + $("input.model_validation").each(function(){ + if($(this).val() != "Completed") { + reload_id = this.id.replace("model_validation_",""); + if(/^\d+$/.test(reload_id)) loadModel(reload_id); + }; + }); + var validationCheck = setTimeout('checkValidation()',15000); + } }); jQuery.fn.deleteModel = function(type, options) { diff --git a/views/model.haml b/views/model.haml index b255e80..dc003f6 100644 --- a/views/model.haml +++ b/views/model.haml @@ -54,52 +54,5 @@ , %a{:href => "#{model.uri}.yaml"} YAML %em (experts, models cannot be exported in Excel) - %dt - Validation: - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) - %dd - - if model.validation_uri - - v = model.validation - - if v == "Service not available" - = v - - else - %dl - %dt Number of predictions: - %dd= v[:n] - %dt Correct predictions: - %dd - = v[:correct_predictions] - = '%' - %dt - %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: - %dd - = v[:weighted_area_under_roc] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: - %dd= v[:specificity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: - %dd= v[:sensitivity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: - %dd - %table - %tr - %th - %th Measured - %tr - %th Predicted - %th active - %th inactive - %tr - %th active - %td= v[:tp] - %td= v[:fp] - %tr - %th inactive - %td= v[:fn] - %td= v[:tn] - - else - = image_tag("/snake_transparent.gif") if model.validation_status == "Running" - %a{:href => model.validation_task_uri} #{model.validation_status} + = haml :model_validation, :locals=>{:model=>model}, :layout => false + \ No newline at end of file diff --git a/views/model_validation.haml b/views/model_validation.haml new file mode 100644 index 0000000..a9472ee --- /dev/null +++ b/views/model_validation.haml @@ -0,0 +1,50 @@ +%dt + Validation: + %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) +%dd + - if model.validation_uri + - v = model.validation + - if v == "Service not available" + = v + - else + %dl + %dt Number of predictions: + %dd= v[:n] + %dt Correct predictions: + %dd + = v[:correct_predictions] + = '%' + %dt + %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: + %dd + = v[:weighted_area_under_roc] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: + %dd= v[:specificity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: + %dd= v[:sensitivity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: + %dd + %table + %tr + %th + %th Measured + %tr + %th Predicted + %th active + %th inactive + %tr + %th active + %td= v[:tp] + %td= v[:fp] + %tr + %th inactive + %td= v[:fn] + %td= v[:tn] + - else + = image_tag("/snake_transparent.gif") if model.validation_status == "Running" + %a{:href => model.validation_task_uri} #{model.validation_status} diff --git a/views/models.haml b/views/models.haml index c11aaa7..806a935 100755 --- a/views/models.haml +++ b/views/models.haml @@ -5,6 +5,8 @@ if(#{stati != 0}) { setTimeout('checkStati("#{stati_to_check}")',1500); } + var reload_validation = true; + if(reload_validation) setTimeout('checkValidation()',15000); }); %p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. -- cgit v1.2.3 From 172f1fbcd8da708c3ff87e2c5c49ac5e0e504460 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 20 May 2010 08:42:20 +0200 Subject: debug log removed --- application.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/application.rb b/application.rb index 090b751..a70e0f2 100755 --- a/application.rb +++ b/application.rb @@ -25,7 +25,6 @@ class ToxCreateModel property :created_at, DateTime def status - ##LOGGER.debug RestClient.get(File.join(@task_uri, 'hasStatus')).body RestClient.get(File.join(@task_uri, 'hasStatus')).body end -- cgit v1.2.3 From 376939ea55bbe8f4960c596c44942ccd79d70265 Mon Sep 17 00:00:00 2001 From: mr Date: Thu, 20 May 2010 09:31:47 +0200 Subject: toggle confidence info, upload control via file-extension --- application.rb | 13 +++++++------ views/prediction.haml | 10 ++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/application.rb b/application.rb index 13da470..dadc11c 100755 --- a/application.rb +++ b/application.rb @@ -6,6 +6,8 @@ require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' require 'spreadsheet' +require 'roo' +require 'ftools' LOGGER.progname = File.expand_path __FILE__ use Rack::Flash @@ -244,8 +246,8 @@ post '/upload' do # create a new model nr_compounds = 0 line_nr = 1 - case params[:file][:type] - when "application/csv", "text/csv", "text/plain" + case File.extname(params[:file][:filename]) + when ".csv" params[:file][:tempfile].each_line do |line| unless line.chomp.match(/^.+[,;].*$/) # check CSV format - not all browsers provide correct content-type flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." @@ -275,13 +277,11 @@ post '/upload' do # create a new model end line_nr += 1 end - when "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" - require 'roo' - require 'ftools' + when ".xls", ".xlsx" excel = 'tmp/' + params[:file][:filename] name = params[:file][:filename] File.mv(params[:file][:tempfile].path,excel) - if params[:file][:type] == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + if File.extname(params[:file][:filename]) == ".xlsx" book = Excelx.new(excel) else book = Excel.new(excel) @@ -311,6 +311,7 @@ post '/upload' do # create a new model end line_nr += 1 end + File.safe_unlink(excel) else LOGGER.error "Fileupload (Excel) Error: " + params[:file].inspect end diff --git a/views/prediction.haml b/views/prediction.haml index 74832a2..716d280 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -34,9 +34,15 @@ %em= p[:prediction] - if p[:confidence] %br - = "(Confidence: #{sprintf('%.03f', p[:confidence].to_f.abs)})" + ( + %a{:href => "#", :id => "linkConfidence"} Confidence + = ": #{sprintf('%.03f', p[:confidence].to_f.abs)})" -%dl +%dl#confidence{ :style => "display: none;" } %dt Confidence: %dd 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 distiguish between reliable and unreliable predictions. +:javascript + $("a#linkConfidence").click(function () { + $("dl#confidence").toggle(); + }); -- cgit v1.2.3 From 64ff7459263ea3cd2ad37a56954b6f1a40e657a8 Mon Sep 17 00:00:00 2001 From: mr Date: Thu, 20 May 2010 10:22:02 +0200 Subject: excel upload fix --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index dadc11c..95c423e 100755 --- a/application.rb +++ b/application.rb @@ -296,7 +296,7 @@ post '/upload' do # create a new model compound_uri = c.uri dataset.compounds << compound_uri dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - case book.cell(row,2).to_s + case book.cell(row,2).to_i.to_s when '1' dataset.data[compound_uri] << {feature_uri => true } nr_compounds += 1 -- cgit v1.2.3 From 2f0047dd0a2a76b03eb885713c163366dc7bd773 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 20 May 2010 10:25:25 +0200 Subject: minor layout improvements, validation task uris saved in ToxCreateModel --- application.rb | 12 ++++++++++++ views/model_validation.haml | 17 ++++++++++------- views/style.sass | 22 +++++++++------------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/application.rb b/application.rb index 7767f7b..1826978 100755 --- a/application.rb +++ b/application.rb @@ -182,6 +182,18 @@ get '/model/:id/?' do model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body model.save end + unless @@config[:services]["opentox-model"].match(/localhost/) + if !model.validation_uri and model.validation_status == "Completed" + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body + LOGGER.debug "Validation URI: #{model.validation_uri}" + model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body + LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" + model.save + end + if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' + model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body + end + end begin haml :model, :locals=>{:model=>model}, :layout => false diff --git a/views/model_validation.haml b/views/model_validation.haml index a9472ee..271cb99 100644 --- a/views/model_validation.haml +++ b/views/model_validation.haml @@ -31,18 +31,21 @@ %dd %table %tr - %th - %th Measured + %td{:colspan => 2, :rowspan => 2} + -#%td + %th{:colspan => 2} Measured %tr - %th Predicted - %th active - %th inactive + -#%td{:colspan => 2} + -#%th Predicted + %th{:bgcolor => "#CCD2DC"} active + %th{:bgcolor => "#CCD2DC"} inactive %tr - %th active + %th{:rowspan => 2} Predicted + %th{:bgcolor => "#CCD2DC"} active %td= v[:tp] %td= v[:fp] %tr - %th inactive + %th{:bgcolor => "#CCD2DC"} inactive %td= v[:fn] %td= v[:tn] - else diff --git a/views/style.sass b/views/style.sass index d1138de..d1c62e0 100644 --- a/views/style.sass +++ b/views/style.sass @@ -6,13 +6,6 @@ !text_color = black !notice_border = #000000 -/* - !bg_color = #DDFFFF - !bg_color2 = #F4F4F4 - !fg_color = #5D308A - !body_color = white - !text_color = black - body min-width: 30em font-family: verdana, arial,helvetica,sans-serif @@ -181,7 +174,7 @@ body border: 0 dt white-space: nowrap - width: 15em + width: 16em font-weight: bold float: left clear: right @@ -202,12 +195,15 @@ dl dd td border: 1px dotted #FFFFFF - text-align: left + text-align: right padding: 0.2em + + .blank + border: 0 th border-bottom: 1px dotted #FFFFFF - text-align: left - background-color: #CCD2DC - padding: 0.2em + text-align: center + //background-color: #CCD2DC + padding: 0.3em table - border-collapse: collapse \ No newline at end of file + border-collapse: collapse -- cgit v1.2.3 From 2a97264c3e0daa40a635ef635006925b4b5b9843 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 20 May 2010 10:33:31 +0200 Subject: opentox-ruby-api-wrapper bumped to 1.5.2 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index a93b060..9e9c7a5 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.5.1' +gem 'opentox-ruby-api-wrapper', '= 1.5.2' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 820b3b7055d2f0017b0bec3db1914a6d610b2147 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 20 May 2010 11:02:52 +0200 Subject: Excel instructions added --- application.rb | 4 +++ public/hamster_carcinogenicity.xls | Bin 0 -> 57856 bytes views/create.haml | 4 ++- views/excel_format.haml | 64 +++++++++++++++++++++++++++++++++++++ views/style.sass | 9 ++++++ 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 public/hamster_carcinogenicity.xls create mode 100644 views/excel_format.haml diff --git a/application.rb b/application.rb index 9e9c7a5..33ee54d 100755 --- a/application.rb +++ b/application.rb @@ -222,6 +222,10 @@ get '/csv_format' do haml :csv_format end +get '/excel_format' do + haml :excel_format +end + get "/confidence" do haml :confidence end diff --git a/public/hamster_carcinogenicity.xls b/public/hamster_carcinogenicity.xls new file mode 100644 index 0000000..0015ac6 Binary files /dev/null and b/public/hamster_carcinogenicity.xls differ diff --git a/views/create.haml b/views/create.haml index f754770..3c9798d 100644 --- a/views/create.haml +++ b/views/create.haml @@ -4,7 +4,7 @@ This service creates %a{:href => 'http://lazar.in-silico.de'} lazar classification models (more model building algorithms will follow) from your uploaded datasets. Here are - = link_to "instructions", '/csv_format' + = link_to "instructions", '/excel_format' , for creating training datasets in Excel. %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } @@ -18,6 +18,8 @@ %br %label{:for => 'file'} 2. Upload training data in + = link_to "Excel", '/excel_format' + or = link_to "CSV", '/csv_format' format: %input{:type => 'file', :name => 'file', :id => 'file', :size => '41'} diff --git a/views/excel_format.haml b/views/excel_format.haml new file mode 100644 index 0000000..4cbbd08 --- /dev/null +++ b/views/excel_format.haml @@ -0,0 +1,64 @@ += link_to "Back to model creation", '/create' +%p + The Excel input file should contain a single spreadsheet with two columns. Enter in the first column the chemical structure in + %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification"} SMILES + format, in the second column the activity classification (1: active, 0: inactive), e.g. + +- n = 0 + +.code + %table + %tr + %td + %th A + %th B + %tr + - n += 1 + %th= n + %td CC(=O)Nc1ccc(O)cc1 + %td 1 + %tr + - n += 1 + %th= n + %td O=c1[nH]cnc2[nH]ncc12 + %td 1 + %tr + - n += 1 + %th= n + %td CCCCNc1cc(cc(c1Oc2ccccc2)S(=O)(=O)N)C(=O)O + %td 1 + %tr + - n += 1 + %th= n + %td CC(C)(C)NCC(O)COc1cccc2NC(=O)CCc12 + %td 1 + %tr + - n += 1 + %th= n + %td CN(C)CCCC1(OCc2cc(C#N)ccc21)c3ccc(F)cc3 + %td 1 + %tr + - n += 1 + %th= n + %td CCC(CC)CCN1C(=O)CN=C(C2CCCCC2F)c3cc(Cl)ccc13 + %td 0 + %tr + - n += 1 + %th= n + %td CCN(CC)CC(=O)Nc1c(C)cccc1C + %td 0 + %tr + - n += 1 + %th= n + %td CC(C)(C)NCC(O)COc1cccc2CC(O)C(O)Cc12 + %td 0 + %tr + - n += 1 + %th= n + %td CN1CCCC1c2cccnc2 + %td 0 + +%p + Here is an example file for download: + = link_to "hamster_carcinogenicity.xls", "/hamster_carcinogenicity.xls" + diff --git a/views/style.sass b/views/style.sass index d1c62e0..af53bf0 100644 --- a/views/style.sass +++ b/views/style.sass @@ -128,6 +128,15 @@ body border: 1px solid black padding: 1% background-color: white + table + :border-collapse collapse + th + :padding 0.5em + :border 1px solid + background-color: #CCD2DC + td + :padding 0.5em + :border 1px solid .predictions :text-align center -- cgit v1.2.3 From b751b80a1e5df70d463f71928018e26efb48dbe4 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 21 May 2010 12:37:46 +0200 Subject: improved handling of input formats --- application.rb | 89 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/application.rb b/application.rb index 33ee54d..fd2b1fa 100755 --- a/application.rb +++ b/application.rb @@ -246,7 +246,7 @@ post '/upload' do # create a new model redirect url_for('/create') end unless params[:endpoint] and params[:file] and params[:file][:tempfile] - flash[:notice] = "Please enter an endpoint name and upload a CSV file." + flash[:notice] = "Please enter an endpoint name and upload a Excel or CSV file." redirect url_for('/create') end @model = ToxCreateModel.new @@ -293,43 +293,56 @@ post '/upload' do # create a new model line_nr += 1 end when ".xls", ".xlsx" - excel = 'tmp/' + params[:file][:filename] - name = params[:file][:filename] - File.mv(params[:file][:tempfile].path,excel) - if File.extname(params[:file][:filename]) == ".xlsx" - book = Excelx.new(excel) - else - book = Excel.new(excel) - end - book.default_sheet = 0 - 1.upto(book.last_row) do |row| - smiles = book.cell(row,1) - c = OpenTox::Compound.new(:smiles => smiles) - if c.inchi != "" - duplicates[c.inchi] = [] unless duplicates[c.inchi] - duplicates[c.inchi] << "Line #{line_nr}: " + smiles if smiles - compound_uri = c.uri - dataset.compounds << compound_uri - dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - case book.cell(row,2).to_i.to_s - when '1' - dataset.data[compound_uri] << {feature_uri => true } - nr_compounds += 1 - when '0' - dataset.data[compound_uri] << {feature_uri => false } - nr_compounds += 1 - else - activity_errors << "Line #{line_nr}: " + smiles if smiles - end - else - smiles_errors << "Line #{line_nr}: " + smiles if smiles - end - line_nr += 1 - end - File.safe_unlink(excel) + begin + excel = 'tmp/' + params[:file][:filename] + name = params[:file][:filename] + File.mv(params[:file][:tempfile].path,excel) + if File.extname(params[:file][:filename]) == ".xlsx" + book = Excelx.new(excel) + else + book = Excel.new(excel) + end + book.default_sheet = 0 + 1.upto(book.last_row) do |row| + smiles = book.cell(row,1) + c = OpenTox::Compound.new(:smiles => smiles) + if c.inchi != "" + duplicates[c.inchi] = [] unless duplicates[c.inchi] + duplicates[c.inchi] << "Line #{line_nr}: " + smiles if smiles + compound_uri = c.uri + dataset.compounds << compound_uri + dataset.data[compound_uri] = [] unless dataset.data[compound_uri] + case book.cell(row,2).to_i.to_s + when '1' + dataset.data[compound_uri] << {feature_uri => true } + nr_compounds += 1 + when '0' + dataset.data[compound_uri] << {feature_uri => false } + nr_compounds += 1 + else + activity_errors << "Line #{line_nr}: " + smiles if smiles + end + else + smiles_errors << "Line #{line_nr}: " + smiles if smiles + end + line_nr += 1 + end + File.safe_unlink(excel) + rescue + flash[:notice] = "Please upload a Excel file created according to these #{link_to "instructions", "excel_format"}." + redirect url_for('/create') + end else - LOGGER.error "Fileupload (Excel) Error: " + params[:file].inspect + LOGGER.error "File upload error: " + params[:file].inspect + flash[:notice] = File.extname(params[:file][:filename]) + "is not a valid file extension. Please create an input file according to the instructions for #{link_to "Excel", "excel_format"} or #{link_to "CSV", "csv_format"}." + redirect url_for('/create') end + + if nr_compounds < 10 + flash[:notice] = "Too few compounds to create a prediction model." + redirect url_for('/create') + end + dataset_uri = dataset.save task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) @model.task_uri = task_uri @@ -412,6 +425,10 @@ delete '/?' do "All Models deleted." end +#get '/error' do +# fail "testing mail delivery" +#end + # SASS stylesheet get '/stylesheets/style.css' do headers 'Content-Type' => 'text/css; charset=utf-8' -- cgit v1.2.3 From 853d76bbf32b90b25a323530c4f4db4e53d2b8e6 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 21 May 2010 12:42:08 +0200 Subject: opentox-ruby-api-wrapper bumped to 1.5.3 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index fd2b1fa..c35daec 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.5.2' +gem 'opentox-ruby-api-wrapper', '= 1.5.3' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 6097dc989880fe6803af7663d616cbfbe5a8846c Mon Sep 17 00:00:00 2001 From: mr Date: Fri, 21 May 2010 13:52:24 +0200 Subject: fix Confidence toggle link --- views/prediction.haml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/views/prediction.haml b/views/prediction.haml index 716d280..bbc0346 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -35,14 +35,15 @@ - if p[:confidence] %br ( - %a{:href => "#", :id => "linkConfidence"} Confidence + %a{:href => "#", :id => "linkConfidence#{p.object_id}"} Confidence = ": #{sprintf('%.03f', p[:confidence].to_f.abs)})" + :javascript + $("a#linkConfidence#{p.object_id}").click(function () { + $("dl#confidence").toggle(); + }); %dl#confidence{ :style => "display: none;" } %dt Confidence: %dd 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 distiguish between reliable and unreliable predictions. -:javascript - $("a#linkConfidence").click(function () { - $("dl#confidence").toggle(); - }); + -- cgit v1.2.3 From 0b0e5218f2e37a3e9b9e54ceaa09638977451811 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 21 May 2010 16:47:50 +0200 Subject: opentox-api-wrapper bumped to 1.5.4 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index c35daec..387ac4b 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.5.3' +gem 'opentox-ruby-api-wrapper', '= 1.5.4' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 4554e78aeb72de67ec343d2d81f9a547fe7c7ec2 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 21 May 2010 18:46:23 +0200 Subject: opentox-api-wrapper bumped to 1.5.5 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 387ac4b..8101d8d 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.5.4' +gem "opentox-ruby-api-wrapper", "= 1.5.4" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From d8f859f02ee46fa47ecf0c240f6238c0dc6350eb Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 21 May 2010 18:48:47 +0200 Subject: opentox-api-wrapper bumped to --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 8101d8d..6113e85 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.5.4" +gem "opentox-ruby-api-wrapper", "= " require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From bcb80fbfb2e7f0b40eeb05c9b19e612b13a447c6 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 21 May 2010 18:57:53 +0200 Subject: opentox-api-wrapper bumped to 1.5.5 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 6113e85..45a099c 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= " +gem "opentox-ruby-api-wrapper", "= 1.5.5" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 71ad2bb972ad09cd2d1a497726bbc31aa50cc70b Mon Sep 17 00:00:00 2001 From: ch Date: Fri, 21 May 2010 22:24:57 +0200 Subject: -am --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 387ac4b..97d5a88 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem 'opentox-ruby-api-wrapper', '= 1.5.4' +gem 'opentox-ruby-api-wrapper', '= 1.5.5' require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 0a95b83e2e19e37c5a0d4466b468f63434f3c8e2 Mon Sep 17 00:00:00 2001 From: ch Date: Tue, 25 May 2010 13:19:57 +0200 Subject: more instructions for model construction and more informative error messages --- application.rb | 9 +++++---- views/create.haml | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/application.rb b/application.rb index 45a099c..1e0eff9 100755 --- a/application.rb +++ b/application.rb @@ -312,7 +312,8 @@ post '/upload' do # create a new model compound_uri = c.uri dataset.compounds << compound_uri dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - case book.cell(row,2).to_i.to_s + #case book.cell(row,2).to_i.to_s # reads also floats + case book.cell(row,2).to_s when '1' dataset.data[compound_uri] << {feature_uri => true } nr_compounds += 1 @@ -329,17 +330,17 @@ post '/upload' do # create a new model end File.safe_unlink(excel) rescue - flash[:notice] = "Please upload a Excel file created according to these #{link_to "instructions", "excel_format"}." + flash[:notice] = "Please upload a Excel file created according to these #{link_to "instructions", "/excel_format"}." redirect url_for('/create') end else LOGGER.error "File upload error: " + params[:file].inspect - flash[:notice] = File.extname(params[:file][:filename]) + "is not a valid file extension. Please create an input file according to the instructions for #{link_to "Excel", "excel_format"} or #{link_to "CSV", "csv_format"}." + flash[:notice] = File.extname(params[:file][:filename]) + "is not a valid file extension. Please create an input file according to the instructions for #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"}." redirect url_for('/create') end if nr_compounds < 10 - flash[:notice] = "Too few compounds to create a prediction model." + flash[:notice] = "Too few compounds to create a prediction model. Did you provide compounds in SMILES format and classification activities as 0 and 1 as described in the #{link_to "instructions", "/excel_format"}? As a rule of thumb you will need at least 100 training compounds for nongeneric datasets. A lower number could be sufficient for congeneric datasets." redirect url_for('/create') end diff --git a/views/create.haml b/views/create.haml index 3c9798d..85a832d 100644 --- a/views/create.haml +++ b/views/create.haml @@ -3,7 +3,8 @@ %p This service creates %a{:href => 'http://lazar.in-silico.de'} lazar - classification models (more model building algorithms will follow) from your uploaded datasets. Here are + %em classification + models (regression models and further modelling algorithms will be added in future versions) from your uploaded datasets. Here are = link_to "instructions", '/excel_format' , for creating training datasets in Excel. -- cgit v1.2.3 From d1baabf2ed8e2bcff1b5716fd983b93095b1cc4c Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 25 May 2010 17:52:17 +0200 Subject: caching errors during model creation as last resort for corrupt input files --- application.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 1e0eff9..454a63f 100755 --- a/application.rb +++ b/application.rb @@ -345,7 +345,12 @@ post '/upload' do # create a new model end dataset_uri = dataset.save - task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) + begin + task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) + flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." + redirect url_for('/create') + rescue + end @model.task_uri = task_uri unless @@config[:services]["opentox-model"].match(/localhost/) -- cgit v1.2.3 From e5a3b5acc3b5d6fbc7245ebd31abad1fc3432552 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 25 May 2010 19:04:46 +0200 Subject: Improvements according to Sylvias comments --- views/create.haml | 4 +++- views/model.haml | 5 +++-- views/prediction.haml | 18 ++++++++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/views/create.haml b/views/create.haml index 85a832d..0f50756 100644 --- a/views/create.haml +++ b/views/create.haml @@ -4,9 +4,11 @@ This service creates %a{:href => 'http://lazar.in-silico.de'} lazar %em classification - models (regression models and further modelling algorithms will be added in future versions) from your uploaded datasets. Here are + models (i.e. models that discriminate between toxic/nontoxic compounds) from your uploaded datasets. Here are = link_to "instructions", '/excel_format' , for creating training datasets in Excel. + %p + Facilities to create models for quantitative values (e.g. LC50s) and further modelling algorithms will be added in future versions. %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } %fieldset diff --git a/views/model.haml b/views/model.haml index dc003f6..b70bb43 100644 --- a/views/model.haml +++ b/views/model.haml @@ -30,7 +30,8 @@ - if model.status == 'Completed' %dt Algorithm: %dd - %a{:href => model.algorithm} #{File.basename model.algorithm} + %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} #{File.basename model.algorithm} + -# %a{:href => model.algorithm} RDF/XML %dt Descriptors: %dd %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes @@ -55,4 +56,4 @@ %a{:href => "#{model.uri}.yaml"} YAML %em (experts, models cannot be exported in Excel) = haml :model_validation, :locals=>{:model=>model}, :layout => false - \ No newline at end of file + diff --git a/views/prediction.haml b/views/prediction.haml index bbc0346..92b434b 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -21,7 +21,15 @@ - elsif activity(a) == 'inactive' .inactive = activity(a) - %br (training data) + %br + ( + %a{:href => "#", :id => "linkTrainingData#{p.object_id}"} Training data + :javascript + $("a#linkTrainingData#{p.object_id}").click(function () { + $("dl#training_data").toggle(); + }); + ) + - else - if activity(p[:prediction]) == 'active' .active @@ -36,14 +44,20 @@ %br ( %a{:href => "#", :id => "linkConfidence#{p.object_id}"} Confidence - = ": #{sprintf('%.03f', p[:confidence].to_f.abs)})" + = ": #{sprintf('%.03f', p[:confidence].to_f.abs)}" :javascript $("a#linkConfidence#{p.object_id}").click(function () { $("dl#confidence").toggle(); }); + ) %dl#confidence{ :style => "display: none;" } %dt Confidence: %dd 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 distiguish between reliable and unreliable predictions. +%dl#training_data{ :style => "display: none;" } + %dt Training data: + %dd Experimental result(s) from the training dataset are displayed here. + + -- cgit v1.2.3 From 72a12cd9683540e737f5d1d0031cc2c50a670dc2 Mon Sep 17 00:00:00 2001 From: ch Date: Wed, 26 May 2010 14:59:07 +0200 Subject: ignoring invalid validation_uris, fixed bug for data upload --- application.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/application.rb b/application.rb index 454a63f..53753f4 100755 --- a/application.rb +++ b/application.rb @@ -140,11 +140,14 @@ get '/models/?' do end unless @@config[:services]["opentox-model"].match(/localhost/) if !model.validation_uri and model.validation_status == "Completed" - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body - LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" - model.save + begin + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body + LOGGER.debug "Validation URI: #{model.validation_uri}" + model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body + LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" + model.save + rescue + end end if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body @@ -347,9 +350,9 @@ post '/upload' do # create a new model dataset_uri = dataset.save begin task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) + rescue flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." redirect url_for('/create') - rescue end @model.task_uri = task_uri -- cgit v1.2.3 From 21ccd17cd4826c8eb0aafdd2c26673a3e8fd991e Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 26 May 2010 21:45:55 +0200 Subject: Excel parsing fixed --- application.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application.rb b/application.rb index 53753f4..ad10bc0 100755 --- a/application.rb +++ b/application.rb @@ -316,11 +316,11 @@ post '/upload' do # create a new model dataset.compounds << compound_uri dataset.data[compound_uri] = [] unless dataset.data[compound_uri] #case book.cell(row,2).to_i.to_s # reads also floats - case book.cell(row,2).to_s - when '1' + case book.cell(row,2) + when 1.0 dataset.data[compound_uri] << {feature_uri => true } nr_compounds += 1 - when '0' + when 0.0 dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else -- cgit v1.2.3 From d75a8f4f652ce3cb754b7cd1aa0d7d14accdad3f Mon Sep 17 00:00:00 2001 From: ch Date: Sun, 30 May 2010 11:49:35 +0200 Subject: robots.txt added --- application.rb | 4 ++-- public/robots.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 public/robots.txt diff --git a/application.rb b/application.rb index ad10bc0..bdd91df 100755 --- a/application.rb +++ b/application.rb @@ -183,12 +183,12 @@ end get '/model/:id/?' do response['Content-Type'] = 'text/plain' model = ToxCreateModel.get(params[:id]) - if !model.uri and model.status == "Completed" + if model and !model.uri and model.status == "Completed" model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body model.save end unless @@config[:services]["opentox-model"].match(/localhost/) - if !model.validation_uri and model.validation_status == "Completed" + if model and !model.validation_uri and model.validation_status == "Completed" model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body LOGGER.debug "Validation URI: #{model.validation_uri}" model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / -- cgit v1.2.3 From 4f2cb75eed72160ac868a55db6e8b031f464d72e Mon Sep 17 00:00:00 2001 From: ist Date: Wed, 2 Jun 2010 15:47:51 +0200 Subject: Added field "classification" to Model --- application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/application.rb b/application.rb index bdd91df..a6c359b 100755 --- a/application.rb +++ b/application.rb @@ -26,6 +26,7 @@ class ToxCreateModel property :warnings, Text, :length => 2**32-1 property :nr_compounds, Integer property :created_at, DateTime + property :classification, Boolean def status RestClient.get(File.join(@task_uri, 'hasStatus')).body -- cgit v1.2.3 From bf5b7384c5785add79ae5e0fc02083ed42717201 Mon Sep 17 00:00:00 2001 From: ist Date: Wed, 2 Jun 2010 16:39:00 +0200 Subject: Created field "classification" Field definition default: true (set on POST) switches automatically to false when activity values are not 1.0 or 0.0. --- application.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application.rb b/application.rb index a6c359b..4c1b0e3 100755 --- a/application.rb +++ b/application.rb @@ -255,6 +255,7 @@ post '/upload' do # create a new model end @model = ToxCreateModel.new @model.name = params[:endpoint] + @model.classification = true; dataset = OpenTox::Dataset.new dataset.title = params[:endpoint] feature_uri = url_for("/feature#"+URI.encode(params[:endpoint]), :full) @@ -289,6 +290,7 @@ post '/upload' do # create a new model dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else + @model.classification = false; activity_errors << "Line #{line_nr}: " + line.chomp end else @@ -325,6 +327,7 @@ post '/upload' do # create a new model dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else + @model.classification = false; activity_errors << "Line #{line_nr}: " + smiles if smiles end else -- cgit v1.2.3 From 68a34a90b707de77081d75e88204760f4118117d Mon Sep 17 00:00:00 2001 From: ist Date: Wed, 2 Jun 2010 17:22:04 +0200 Subject: Removed member status of "classification" variable Don't want to force db migration if not necessary. Not necessary because classification property should be stored in opentox-model. --- application.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/application.rb b/application.rb index 4c1b0e3..5e8bb85 100755 --- a/application.rb +++ b/application.rb @@ -26,7 +26,6 @@ class ToxCreateModel property :warnings, Text, :length => 2**32-1 property :nr_compounds, Integer property :created_at, DateTime - property :classification, Boolean def status RestClient.get(File.join(@task_uri, 'hasStatus')).body @@ -255,7 +254,7 @@ post '/upload' do # create a new model end @model = ToxCreateModel.new @model.name = params[:endpoint] - @model.classification = true; + classification = true; dataset = OpenTox::Dataset.new dataset.title = params[:endpoint] feature_uri = url_for("/feature#"+URI.encode(params[:endpoint]), :full) @@ -290,7 +289,7 @@ post '/upload' do # create a new model dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else - @model.classification = false; + classification = false; activity_errors << "Line #{line_nr}: " + line.chomp end else @@ -327,7 +326,7 @@ post '/upload' do # create a new model dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else - @model.classification = false; + classification = false; activity_errors << "Line #{line_nr}: " + smiles if smiles end else @@ -353,7 +352,7 @@ post '/upload' do # create a new model dataset_uri = dataset.save begin - task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) + task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri, :classification => classification) rescue flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." redirect url_for('/create') -- cgit v1.2.3 From ab30ae1bd71401da60f80659189323ec84c94493 Mon Sep 17 00:00:00 2001 From: ist Date: Fri, 4 Jun 2010 18:12:24 +0200 Subject: Handle quantitative activity values --- application.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/application.rb b/application.rb index 5e8bb85..8c05f95 100755 --- a/application.rb +++ b/application.rb @@ -254,7 +254,6 @@ post '/upload' do # create a new model end @model = ToxCreateModel.new @model.name = params[:endpoint] - classification = true; dataset = OpenTox::Dataset.new dataset.title = params[:endpoint] feature_uri = url_for("/feature#"+URI.encode(params[:endpoint]), :full) @@ -288,9 +287,9 @@ post '/upload' do # create a new model when '0' dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 - else - classification = false; - activity_errors << "Line #{line_nr}: " + line.chomp + else + # AM: handle quantitative values + dataset.data[compound_uri] << {feature_uri => items[1].to_f} end else smiles_errors << "Line #{line_nr}: " + line.chomp @@ -326,7 +325,6 @@ post '/upload' do # create a new model dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else - classification = false; activity_errors << "Line #{line_nr}: " + smiles if smiles end else @@ -346,13 +344,13 @@ post '/upload' do # create a new model end if nr_compounds < 10 - flash[:notice] = "Too few compounds to create a prediction model. Did you provide compounds in SMILES format and classification activities as 0 and 1 as described in the #{link_to "instructions", "/excel_format"}? As a rule of thumb you will need at least 100 training compounds for nongeneric datasets. A lower number could be sufficient for congeneric datasets." + flash[:notice] = "Too few compounds to create a prediction model. Did you provide compounds in SMILES format and classification activities as described in the #{link_to "instructions", "/excel_format"}? As a rule of thumb you will need at least 100 training compounds for nongeneric datasets. A lower number could be sufficient for congeneric datasets." redirect url_for('/create') end dataset_uri = dataset.save begin - task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri, :classification => classification) + task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) rescue flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." redirect url_for('/create') -- cgit v1.2.3 From d97cf05b4550a8d1a6ef7de4cce2b24b9b46497a Mon Sep 17 00:00:00 2001 From: ist Date: Fri, 4 Jun 2010 19:10:07 +0200 Subject: Fixed number of compounds counting --- application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/application.rb b/application.rb index 8c05f95..e449c7f 100755 --- a/application.rb +++ b/application.rb @@ -290,6 +290,7 @@ post '/upload' do # create a new model else # AM: handle quantitative values dataset.data[compound_uri] << {feature_uri => items[1].to_f} + nr_compounds += 1 end else smiles_errors << "Line #{line_nr}: " + line.chomp -- cgit v1.2.3 From 4e266f73936fe0a7921041ebb4d46b846289822c Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 8 Jun 2010 12:13:53 +0200 Subject: remove deleted model from html --- public/javascripts/toxcreate.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index f2523b3..6185b93 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -108,6 +108,7 @@ jQuery.fn.deleteModel = function(type, options) { }, success: function(data) { $(opts.elem).fadeTo("slow",0).slideUp("slow"); + $(opts.elem).remove(); }, error: function(data) { //alert("model delete error!"); -- cgit v1.2.3 From d12941818d2210a622727c576fa37ca8248d873e Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 8 Jun 2010 16:55:05 +0200 Subject: change validation reload, sass to new version-format(globals), excel import cellformats(integer float or string --- application.rb | 56 ++++++-------- public/javascripts/toxcreate.js | 14 ++-- views/model.haml | 97 +++++++++++------------ views/model_validation.haml | 105 ++++++++++++------------- views/style.sass | 168 +++++++++++++++++----------------------- 5 files changed, 207 insertions(+), 233 deletions(-) diff --git a/application.rb b/application.rb index ad10bc0..3de9c58 100755 --- a/application.rb +++ b/application.rb @@ -125,16 +125,8 @@ helpers do act end -end - -get '/?' do - redirect url_for('/create') -end - -get '/models/?' do - @models = ToxCreateModel.all(:order => [ :created_at.desc ]) - @models.each do |model| - if !model.uri and model.status == "Completed" + def process_model(model) + if !model.uri and model.status == "Completed" model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body model.save end @@ -153,6 +145,17 @@ get '/models/?' do model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body end end + end +end + +get '/?' do + redirect url_for('/create') +end + +get '/models/?' do + @models = ToxCreateModel.all(:order => [ :created_at.desc ]) + @models.each do |model| + process_model(model) end haml :models end @@ -180,28 +183,20 @@ get '/model/:id/status/?' do end end -get '/model/:id/?' do +get '/model/:id/:view/?' do response['Content-Type'] = 'text/plain' model = ToxCreateModel.get(params[:id]) - if !model.uri and model.status == "Completed" - model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body - model.save - end - unless @@config[:services]["opentox-model"].match(/localhost/) - if !model.validation_uri and model.validation_status == "Completed" - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body - LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" - model.save - end - if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' - model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body - end - end + process_model(model) begin - haml :model, :locals=>{:model=>model}, :layout => false + case params[:view] + when "model" + haml :model, :locals=>{:model=>model}, :layout => false + when "validation" + haml :model_validation, :locals=>{:model=>model}, :layout => false + else + return "render error" + end rescue return "unable to render model" end @@ -315,12 +310,11 @@ post '/upload' do # create a new model compound_uri = c.uri dataset.compounds << compound_uri dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - #case book.cell(row,2).to_i.to_s # reads also floats case book.cell(row,2) - when 1.0 + when 1, 1.0, "1" dataset.data[compound_uri] << {feature_uri => true } nr_compounds += 1 - when 0.0 + when 0, 0.0, "0" dataset.data[compound_uri] << {feature_uri => false } nr_compounds += 1 else diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index 6185b93..b1555c6 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -43,7 +43,7 @@ $(function() { $("span#model_" + id + "_status").animate({"opacity": "1"},1000); if( status_changed ) { $("span#model_" + id + "_status").html(data); - loadModel(id); + loadModel(id, 'model'); id = -1; } }, @@ -55,9 +55,9 @@ $(function() { return id; }; - loadModel = function(id) { + loadModel = function(id, view) { if(id == "") return -1; - var opts = {method: 'get', action: 'model/' + id }; + var opts = {method: 'get', action: 'model/' + id + '/' + view, view: view }; var out = id; $.ajax({ type: opts.method, @@ -67,7 +67,8 @@ $(function() { '_method': 'get' }, success: function(data) { - $("div#model_" + id).html(data); + if (view == "model") $("div#model_" + id).html(data); + if (view == "validation") $("dl#model_validation_" + id).html(data); }, error: function(data) { //alert("loadModel error"); @@ -81,7 +82,7 @@ $(function() { $("input.model_validation").each(function(){ if($(this).val() != "Completed") { reload_id = this.id.replace("model_validation_",""); - if(/^\d+$/.test(reload_id)) loadModel(reload_id); + if(/^\d+$/.test(reload_id)) loadModel(reload_id, 'validation'); }; }); var validationCheck = setTimeout('checkValidation()',15000); @@ -107,8 +108,7 @@ jQuery.fn.deleteModel = function(type, options) { '_method': 'delete' }, success: function(data) { - $(opts.elem).fadeTo("slow",0).slideUp("slow"); - $(opts.elem).remove(); + $(opts.elem).fadeTo("slow",0).slideUp("slow").remove(); }, error: function(data) { //alert("model delete error!"); diff --git a/views/model.haml b/views/model.haml index b70bb43..fd1d114 100644 --- a/views/model.haml +++ b/views/model.haml @@ -8,52 +8,53 @@ %div{:id => "model_#{model.id}"} %h2 = model.name - %dl - %dt Status: - %dd - %span{:id => "model_#{model.id}_status", :class => model.status} - = haml :model_status, :locals=>{:model=>model}, :layout => false - ( - %a{:href => url_for("/model/#{model.id}"), :id => "delete_#{model.id}", :class => 'delete'} delete - ) - %dt Started: - %dd= model.created_at.strftime("%m/%d/%Y - %I:%M:%S%p") - %dt Training compounds: - %dd= model.nr_compounds - %dt Warnings: - - if model.warnings == '' - %dd - - - else - %a{:href => "#", :id => "show_model_#{model.id}_warnings"} show - %dd{:id => "model_#{model.id}_warnings", :style => "display: none;"}= model.warnings - - - if model.status == 'Completed' - %dt Algorithm: + .model + %dl + %dt Status: %dd - %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} #{File.basename model.algorithm} - -# %a{:href => model.algorithm} RDF/XML - %dt Descriptors: - %dd - %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes - %dt Training dataset: - %dd - %a{:href => "#{model.training_dataset}.xls"} Excel sheet - , - %a{:href => "#{model.training_dataset}.rdf"} RDF/XML - %em (experts) , - %a{:href => "#{model.training_dataset}.yaml"} YAML - %em (experts) - %dt Feature dataset: - %dd - %a{:href => "#{model.feature_dataset}.rdf"} RDF/XML - , - %a{:href => "#{model.feature_dataset}.yaml"} YAML - %em (experts, dataset too large for Excel) - %dt Model: - %dd - %a{:href => "#{model.uri}.rdf"} RDF/XML - , - %a{:href => "#{model.uri}.yaml"} YAML - %em (experts, models cannot be exported in Excel) - = haml :model_validation, :locals=>{:model=>model}, :layout => false - + %span{:id => "model_#{model.id}_status", :class => model.status} + = haml :model_status, :locals=>{:model=>model}, :layout => false + ( + %a{:href => url_for("/model/#{model.id}"), :id => "delete_#{model.id}", :class => 'delete'} delete + ) + %dt Started: + %dd= model.created_at.strftime("%m/%d/%Y - %I:%M:%S%p") + %dt Training compounds: + %dd= model.nr_compounds + %dt Warnings: + - if model.warnings == '' + %dd - + - else + %a{:href => "#", :id => "show_model_#{model.id}_warnings"} show + %dd{:id => "model_#{model.id}_warnings", :style => "display: none;"}= model.warnings + + - if model.status == 'Completed' + %dt Algorithm: + %dd + %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} #{File.basename model.algorithm} + -# %a{:href => model.algorithm} RDF/XML + %dt Descriptors: + %dd + %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes + %dt Training dataset: + %dd + %a{:href => "#{model.training_dataset}.xls"} Excel sheet + , + %a{:href => "#{model.training_dataset}.rdf"} RDF/XML + %em (experts) , + %a{:href => "#{model.training_dataset}.yaml"} YAML + %em (experts) + %dt Feature dataset: + %dd + %a{:href => "#{model.feature_dataset}.rdf"} RDF/XML + , + %a{:href => "#{model.feature_dataset}.yaml"} YAML + %em (experts, dataset too large for Excel) + %dt Model: + %dd + %a{:href => "#{model.uri}.rdf"} RDF/XML + , + %a{:href => "#{model.uri}.yaml"} YAML + %em (experts, models cannot be exported in Excel) + = haml :model_validation, :locals=>{:model=>model}, :layout => false + diff --git a/views/model_validation.haml b/views/model_validation.haml index 271cb99..8f5e3ce 100644 --- a/views/model_validation.haml +++ b/views/model_validation.haml @@ -1,53 +1,54 @@ -%dt - Validation: - %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) -%dd - - if model.validation_uri - - v = model.validation - - if v == "Service not available" - = v +%dl{:id => "model_validation_#{model.id}"} + %dt + Validation: + %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) + %dd + - if model.validation_uri + - v = model.validation + - if v == "Service not available" + = v + - else + %dl + %dt Number of predictions: + %dd= v[:n] + %dt Correct predictions: + %dd + = v[:correct_predictions] + = '%' + %dt + %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: + %dd + = v[:weighted_area_under_roc] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: + %dd= v[:specificity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: + %dd= v[:sensitivity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: + %dd + %table + %tr + %td{:colspan => 2, :rowspan => 2} + -#%td + %th{:colspan => 2} Measured + %tr + -#%td{:colspan => 2} + -#%th Predicted + %th{:bgcolor => "#CCD2DC"} active + %th{:bgcolor => "#CCD2DC"} inactive + %tr + %th{:rowspan => 2} Predicted + %th{:bgcolor => "#CCD2DC"} active + %td= v[:tp] + %td= v[:fp] + %tr + %th{:bgcolor => "#CCD2DC"} inactive + %td= v[:fn] + %td= v[:tn] - else - %dl - %dt Number of predictions: - %dd= v[:n] - %dt Correct predictions: - %dd - = v[:correct_predictions] - = '%' - %dt - %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: - %dd - = v[:weighted_area_under_roc] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: - %dd= v[:specificity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: - %dd= v[:sensitivity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: - %dd - %table - %tr - %td{:colspan => 2, :rowspan => 2} - -#%td - %th{:colspan => 2} Measured - %tr - -#%td{:colspan => 2} - -#%th Predicted - %th{:bgcolor => "#CCD2DC"} active - %th{:bgcolor => "#CCD2DC"} inactive - %tr - %th{:rowspan => 2} Predicted - %th{:bgcolor => "#CCD2DC"} active - %td= v[:tp] - %td= v[:fp] - %tr - %th{:bgcolor => "#CCD2DC"} inactive - %td= v[:fn] - %td= v[:tn] - - else - = image_tag("/snake_transparent.gif") if model.validation_status == "Running" - %a{:href => model.validation_task_uri} #{model.validation_status} + = image_tag("/snake_transparent.gif") if model.validation_status == "Running" + %a{:href => model.validation_task_uri} #{model.validation_status} diff --git a/views/style.sass b/views/style.sass index af53bf0..68c6ca2 100644 --- a/views/style.sass +++ b/views/style.sass @@ -1,169 +1,150 @@ -!bg_color = #B9DCFF -!bg_color2 = #e5e7eb -!fg_color = #424345 -!ot_purple = #5D308A -!body_color = white -!text_color = black -!notice_border = #000000 +$bg_color: #b9dcff +$bg_color2: #e5e7eb +$fg_color: #424345 +$ot_purple: #5d308a +$body_color: white +$text_color: black +$notice_border: black body min-width: 30em - font-family: verdana, arial,helvetica,sans-serif - background-color = !body_color - color = !text_color + font-family: verdana, arial, helvetica, sans-serif + background-color: $body_color + color: $text_color padding: 1em - a text-decoration: none font-weight: bold - color = !ot_purple - - a:hover - color = black - + color: $ot_purple + a:hover + color: black .headline - .logo float: right - - /* - .logo - top: 1% - float: right - //display: inline - font-size: 2.5em - word-spacing: -2px - - .span1 - color: black - font-weight: bolder - letter-spacing: -3px - - .span2 - color = !ot_purple - font-weight: 500 - position: relative - left: -6px - + /* .logo + * top: 1% + * float: right + * //display: inline + * font-size: 2.5em + * word-spacing: -2px + * + * .span1 + * color: black + * font-weight: bolder + * letter-spacing: -3px + * + * .span2 + * color = !ot_purple + * font-weight: 500 + * position: relative + * left: -6px .index clear: both - ul margin: 0 0 2px 0 padding: 0 white-space: nowrap list-style-type: none - li margin: 0 padding: 2px display: inline border-right: 1px solid - color = !body_color + color: $body_color border-top: 1px solid - color = !body_color - background-color = !fg_color + color: $body_color + background-color: $fg_color padding-left: 0.5em padding-right: 0.5em font-weight: bold - a text-decoration: none - color = !bg_color + color: $bg_color &:hover - color = !body_color - + color: $body_color li.selected font-weight: bold - background-color= !bg_color + background-color: $bg_color border: 1px solid - color = !fg_color + color: $fg_color border-bottom: 1px solid - color = !bg_color + color: $bg_color a - color = !text_color - - + color: $text_color .content - background-color = !bg_color + background-color: $bg_color height: 100% //padding: 0.5em //margin: 1% padding: 1em border: 1px solid - color = !fg_color - + color: $fg_color h2 margin: 20px 3px 2px 3px - .notice //background-color = !body_color padding: 1em - background-color = !body_color - border: 1px solid - border-color = !notice_border - + background-color: $body_color + border: 1px solid + border-color: $notice_border .input text-align: left form padding: 1em - background-color = !bg_color2 + background-color: $bg_color2 border: 1px solid - color = !fg_color + color: $fg_color fieldset margin: 0 padding: 0 border: 0 legend font-weight: bold - color = !fg_color + color: $fg_color label width: 25em display: block float: left br clear: both - .code border: 1px solid black padding: 1% background-color: white table - :border-collapse collapse + border-collapse: collapse th - :padding 0.5em - :border 1px solid - background-color: #CCD2DC + padding: 0.5em + border: 1px solid + background-color: #ccd2dc td - :padding 0.5em - :border 1px solid - + padding: 0.5em + border: 1px solid .predictions - :text-align center + text-align: center table - :border-spacing 0 - :border-collapse collapse - :margin 0 - + border-spacing: 0 + border-collapse: collapse + margin: 0 th - color = !body_color - background-color = !fg_color + color: $body_color + background-color: $fg_color border: 1px solid - :margin 0.5em + margin: 0.5em td - :border 1px solid - background-color = !bg_color2 - :padding 0.5em + border: 1px solid + background-color: $bg_color2 + padding: 0.5em img padding: 0 height: 100% - + .model + padding: 0em 1em + background-color: $bg_color2 + border: 1px solid + margin-top: 0.6em dl //display: block - padding: 1em - background-color = !bg_color2 - border: 1px solid - margin-top: 0.6em dt width: 15em font-weight: bold @@ -174,12 +155,11 @@ body clear: right margin: 0.2em 0em //display: block - dl //display: block clear: both - padding: 1em - background-color = !bg_color2 + padding: 0em + background-color: $bg_color2 border: 0 dt white-space: nowrap @@ -189,8 +169,6 @@ body clear: right dd //padding-left: 2em - - .footer margin: 0.5em padding: 0.5em @@ -200,17 +178,17 @@ body .inactive color: green + dl dd td - border: 1px dotted #FFFFFF + border: 1px dotted white text-align: right padding: 0.2em - .blank border: 0 th - border-bottom: 1px dotted #FFFFFF + border-bottom: 1px dotted white text-align: center //background-color: #CCD2DC padding: 0.3em -- cgit v1.2.3 From 9036bfacd92620800b76434cf1a1548d192bb44d Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 15 Jun 2010 17:17:51 +0200 Subject: updated for new datamapper release --- application.rb | 2 +- views/style.sass | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/application.rb b/application.rb index 3de9c58..70b0657 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.5.5" +gem "opentox-ruby-api-wrapper", "= 1.5.6" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' diff --git a/views/style.sass b/views/style.sass index 68c6ca2..2fd0ed7 100644 --- a/views/style.sass +++ b/views/style.sass @@ -22,22 +22,22 @@ body .logo float: right /* .logo - * top: 1% - * float: right - * //display: inline - * font-size: 2.5em - * word-spacing: -2px - * - * .span1 - * color: black - * font-weight: bolder - * letter-spacing: -3px - * - * .span2 - * color = !ot_purple - * font-weight: 500 - * position: relative - * left: -6px + top: 1% + float: right + //display: inline + font-size: 2.5em + word-spacing: -2px + + .span1 + color: black + font-weight: bolder + letter-spacing: -3px + + .span2 + color = !ot_purple + font-weight: 500 + position: relative + left: -6px .index clear: both ul -- cgit v1.2.3 From d8aa6f493d2e74678c7268cc0d7f2ab6ce7ac6de Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 25 Jun 2010 20:14:51 +0200 Subject: regression initially working --- application.rb | 308 +++++++------------------------------------------- helper.rb | 36 ++++++ model.rb | 100 ++++++++++++++++ parser.rb | 110 ++++++++++++++++++ views/prediction.haml | 2 + views/tasks.haml | 21 ---- 6 files changed, 291 insertions(+), 286 deletions(-) mode change 100755 => 100644 application.rb create mode 100644 helper.rb create mode 100644 model.rb create mode 100644 parser.rb delete mode 100644 views/tasks.haml diff --git a/application.rb b/application.rb old mode 100755 new mode 100644 index 2be5f00..24fbcc6 --- a/application.rb +++ b/application.rb @@ -5,149 +5,16 @@ gem "opentox-ruby-api-wrapper", "= 1.5.6" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -require 'spreadsheet' -require 'roo' require 'ftools' +require File.join(File.dirname(__FILE__),'model.rb') +require File.join(File.dirname(__FILE__),'helper.rb') +require File.join(File.dirname(__FILE__),'parser.rb') + LOGGER.progname = File.expand_path __FILE__ use Rack::Flash set :sessions, true -class ToxCreateModel - include DataMapper::Resource - property :id, Serial - property :name, String, :length => 255 - property :uri, String, :length => 255 - property :task_uri, String, :length => 255 - property :validation_task_uri, String, :length => 255 - property :validation_uri, String, :length => 255 - property :validation_report_task_uri, String, :length => 255 - property :validation_report_uri, String, :length => 255 - property :warnings, Text, :length => 2**32-1 - property :nr_compounds, Integer - property :created_at, DateTime - - def status - RestClient.get(File.join(@task_uri, 'hasStatus')).body - end - - def validation_status - begin - RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body - rescue - "Service offline" - end - end - - def validation_report_status - begin - RestClient.get(File.join(@validation_report_task_uri, 'hasStatus')).body - rescue - "Service offline" - end - end - - def algorithm - begin - RestClient.get(File.join(@uri, 'algorithm')).body - rescue - "" - end - end - - def training_dataset - begin - RestClient.get(File.join(@uri, 'trainingDataset')).body - rescue - "" - end - end - - def feature_dataset - begin - RestClient.get(File.join(@uri, 'feature_dataset')).body - rescue - "" - end - end - - def validation - begin - uri = File.join(@validation_uri, 'statistics') - yaml = RestClient.get(uri).body - v = YAML.load(yaml) - tp=0; tn=0; fp=0; fn=0; n=0 - v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell| - if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true" - tp = cell[:confusion_matrix_value] - n += tp - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false" - tn = cell[:confusion_matrix_value] - n += tn - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true" - fn = cell[:confusion_matrix_value] - n += fn - elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false" - fp = cell[:confusion_matrix_value] - n += fp - end - end - { - :n => n, - :tp => tp, - :fp => fp, - :tn => tn, - :fn => fn, - :correct_predictions => sprintf("%.2f", 100*(tp+tn).to_f/n), - :weighted_area_under_roc => sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f), - :sensitivity => sprintf("%.3f", tp.to_f/(tp+fn)), - :specificity => sprintf("%.3f", tn.to_f/(tn+fp)) - } - rescue - "Service offline" - end - end - -end - -DataMapper.auto_upgrade! - -helpers do - def activity(a) - case a.to_s - when "true" - act = "active" - when "false" - act = "inactive" - else - act = "not available" - end - act - end - - def process_model(model) - if !model.uri and model.status == "Completed" - model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body - model.save - end - unless @@config[:services]["opentox-model"].match(/localhost/) - if !model.validation_uri and model.validation_status == "Completed" - begin - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body - LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" - model.save - rescue - end - end - if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' - model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body - end - end - end -end - get '/?' do redirect url_for('/create') end @@ -228,17 +95,8 @@ get "/confidence" do haml :confidence end -get '/tasks' do - @tasks = OpenTox::Task.all - haml :tasks -end - -get '/task' do - @task = OpenTox::Task.find(session[:task_uri]) - haml :task -end - post '/upload' do # create a new model + if params[:endpoint] == '' flash[:notice] = "Please enter an endpoint name." redirect url_for('/create') @@ -247,143 +105,62 @@ post '/upload' do # create a new model flash[:notice] = "Please enter an endpoint name and upload a Excel or CSV file." redirect url_for('/create') end + @model = ToxCreateModel.new @model.name = params[:endpoint] - dataset = OpenTox::Dataset.new - dataset.title = params[:endpoint] feature_uri = url_for("/feature#"+URI.encode(params[:endpoint]), :full) - dataset.features << feature_uri - smiles_errors = [] - activity_errors = [] - duplicates = {} - nr_compounds = 0 - line_nr = 1 - - case File.extname(params[:file][:filename]) - when ".csv" - params[:file][:tempfile].each_line do |line| - unless line.chomp.match(/^.+[,;].*$/) # check CSV format - not all browsers provide correct content-type - flash[:notice] = "Please upload a CSV file created according to these #{link_to "instructions", "csv_format"}." - redirect url_for('/create') - end - items = line.chomp.split(/\s*[,;]\s*/) - smiles = items[0] - c = OpenTox::Compound.new(:smiles => smiles) - if c.inchi != "" - duplicates[c.inchi] = [] unless duplicates[c.inchi] - duplicates[c.inchi] << "Line #{line_nr}: " + line.chomp - compound_uri = c.uri - dataset.compounds << compound_uri - dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - case items[1].to_s - when '1' - dataset.data[compound_uri] << {feature_uri => true } - nr_compounds += 1 - when '0' - dataset.data[compound_uri] << {feature_uri => false } - nr_compounds += 1 - else - # AM: handle quantitative values - dataset.data[compound_uri] << {feature_uri => items[1].to_f} - nr_compounds += 1 - end - else - smiles_errors << "Line #{line_nr}: " + line.chomp - end - line_nr += 1 - end - when ".xls", ".xlsx" - begin - excel = 'tmp/' + params[:file][:filename] - name = params[:file][:filename] - File.mv(params[:file][:tempfile].path,excel) - if File.extname(params[:file][:filename]) == ".xlsx" - book = Excelx.new(excel) - else - book = Excel.new(excel) - end - book.default_sheet = 0 - 1.upto(book.last_row) do |row| - smiles = book.cell(row,1) - c = OpenTox::Compound.new(:smiles => smiles) - if c.inchi != "" - duplicates[c.inchi] = [] unless duplicates[c.inchi] - duplicates[c.inchi] << "Line #{line_nr}: " + smiles if smiles - compound_uri = c.uri - dataset.compounds << compound_uri - dataset.data[compound_uri] = [] unless dataset.data[compound_uri] - case book.cell(row,2) - when 1, 1.0, "1" - dataset.data[compound_uri] << {feature_uri => true } - nr_compounds += 1 - when 0, 0.0, "0" - dataset.data[compound_uri] << {feature_uri => false } - nr_compounds += 1 - else - activity_errors << "Line #{line_nr}: " + smiles if smiles - end - else - smiles_errors << "Line #{line_nr}: " + smiles if smiles - end - line_nr += 1 - end - File.safe_unlink(excel) - rescue - flash[:notice] = "Please upload a Excel file created according to these #{link_to "instructions", "/excel_format"}." - redirect url_for('/create') - end - else - LOGGER.error "File upload error: " + params[:file].inspect - flash[:notice] = File.extname(params[:file][:filename]) + "is not a valid file extension. Please create an input file according to the instructions for #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"}." - redirect url_for('/create') - end + parser = Parser.new params[:file], feature_uri - if nr_compounds < 10 - flash[:notice] = "Too few compounds to create a prediction model. Did you provide compounds in SMILES format and classification activities as described in the #{link_to "instructions", "/excel_format"}? As a rule of thumb you will need at least 100 training compounds for nongeneric datasets. A lower number could be sufficient for congeneric datasets." - redirect url_for('/create') + unless parser.format_errors.empty? + flash[:notice] = "Incorrect file format. Please follow the instructions for #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} formats." end - dataset_uri = dataset.save - begin - task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => dataset_uri, :prediction_feature => feature_uri) - rescue - flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." + if parser.dataset.compounds.empty? + flash[:notice] = "Dataset #{params[:file][:filename]} is empty." redirect url_for('/create') end - @model.task_uri = task_uri + #begin + @model.task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => parser.dataset_uri, :prediction_feature => feature_uri) + #rescue + # flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." + # redirect url_for('/create') + #end + +=begin unless @@config[:services]["opentox-model"].match(/localhost/) validation_task_uri = OpenTox::Validation.crossvalidation( :algorithm_uri => OpenTox::Algorithm::Lazar.uri, - :dataset_uri => dataset_uri, + :dataset_uri => parser.dataset_uri, :prediction_feature => feature_uri, :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" ).uri - #LOGGER.debug "Validation task: " + validation_task_uri + LOGGER.debug "Validation task: " + validation_task_uri @model.validation_task_uri = validation_task_uri end +=end + +=begin + if parser.nr_compounds < 10 + flash[:notice] = "Too few compounds to create a prediction model. Did you provide compounds in SMILES format and classification activities as described in the #{link_to "instructions", "/excel_format"}? As a rule of thumb you will need at least 100 training compounds for nongeneric datasets. A lower number could be sufficient for congeneric datasets." + redirect url_for('/create') + end +=end - @model.nr_compounds = nr_compounds + @model.nr_compounds = parser.nr_compounds @model.warnings = '' - if smiles_errors.size > 0 - @model.warnings += "

Incorrect Smiles structures (ignored):

" - @model.warnings += smiles_errors.join("
") - end - if activity_errors.size > 0 - @model.warnings += "

Irregular activities (ignored - please use 1 for active and 0 for inactive compounds):

" - @model.warnings += activity_errors.join("
") - end + @model.warnings += "

Incorrect Smiles structures (ignored):

" + parser.smiles_errors.join("
") unless parser.smiles_errors.empty? + @model.warnings += "

Irregular activities (ignored):

" + parser.activity_errors.join("
") unless parser.activity_errors.empty? duplicate_warnings = '' - duplicates.each {|inchi,lines| duplicate_warnings += "

#{lines.join('
')}

" if lines.size > 1 } - unless duplicate_warnings == '' - @model.warnings += "

Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):

" - @model.warnings += duplicate_warnings - end + parser.duplicates.each {|inchi,lines| duplicate_warnings += "

#{lines.join('
')}

" if lines.size > 1 } + @model.warnings += "

Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):

" + duplicate_warnings unless duplicate_warnings.empty? @model.save + flash[:notice] = "Model creation started. Please be patient - model building may take up to several hours depending on the number and size of the input molecules." redirect url_for('/models') + # TODO: check for empty model end post '/predict/?' do # post chemical name to model @@ -405,13 +182,17 @@ post '/predict/?' do # post chemical name to model confidence = nil title = nil db_activities = [] - LOGGER.debug model.inspect + LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) source = prediction.creator if prediction.data[@compound.uri] if source.to_s.match(/model/) prediction = prediction.data[@compound.uri].first.values.first - @predictions << {:title => model.name, :prediction => prediction[:classification], :confidence => prediction[:confidence]} + if prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")] + @predictions << {:title => model.name, :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")], :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")]} + elsif prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")] + @predictions << {:title => model.name, :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")], :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")]} + end else prediction = prediction.data[@compound.uri].first.values @predictions << {:title => model.name, :measured_activities => prediction} @@ -430,12 +211,9 @@ delete '/?' do "All Models deleted." end -#get '/error' do -# fail "testing mail delivery" -#end - # SASS stylesheet get '/stylesheets/style.css' do headers 'Content-Type' => 'text/css; charset=utf-8' sass :style end + diff --git a/helper.rb b/helper.rb new file mode 100644 index 0000000..e4f91e5 --- /dev/null +++ b/helper.rb @@ -0,0 +1,36 @@ +helpers do + def activity(a) + case a.to_s + when "true" + act = "active" + when "false" + act = "inactive" + else + act = "not available" + end + act + end + + def process_model(model) + if !model.uri and model.status == "Completed" + model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body + model.save + end + unless @@config[:services]["opentox-model"].match(/localhost/) + if !model.validation_uri and model.validation_status == "Completed" + begin + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body + LOGGER.debug "Validation URI: #{model.validation_uri}" + model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body + LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" + model.save + rescue + end + end + if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' + model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body + end + end + end +end + diff --git a/model.rb b/model.rb new file mode 100644 index 0000000..36670d9 --- /dev/null +++ b/model.rb @@ -0,0 +1,100 @@ +class ToxCreateModel + include DataMapper::Resource + property :id, Serial + property :name, String, :length => 255 + property :uri, String, :length => 255 + property :task_uri, String, :length => 255 + property :validation_task_uri, String, :length => 255 + property :validation_uri, String, :length => 255 + property :validation_report_task_uri, String, :length => 255 + property :validation_report_uri, String, :length => 255 + property :warnings, Text, :length => 2**32-1 + property :nr_compounds, Integer + property :created_at, DateTime + + def status + RestClient.get(File.join(@task_uri, 'hasStatus')).body + end + + def validation_status + begin + RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body + rescue + "Service offline" + end + end + + def validation_report_status + begin + RestClient.get(File.join(@validation_report_task_uri, 'hasStatus')).body + rescue + "Service offline" + end + end + + def algorithm + begin + RestClient.get(File.join(@uri, 'algorithm')).body + rescue + "" + end + end + + def training_dataset + begin + RestClient.get(File.join(@uri, 'trainingDataset')).body + rescue + "" + end + end + + def feature_dataset + begin + RestClient.get(File.join(@uri, 'feature_dataset')).body + rescue + "" + end + end + + def validation + begin + uri = File.join(@validation_uri, 'statistics') + yaml = RestClient.get(uri).body + v = YAML.load(yaml) + tp=0; tn=0; fp=0; fn=0; n=0 + v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell| + if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true" + tp = cell[:confusion_matrix_value] + n += tp + elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false" + tn = cell[:confusion_matrix_value] + n += tn + elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true" + fn = cell[:confusion_matrix_value] + n += fn + elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false" + fp = cell[:confusion_matrix_value] + n += fp + end + end + { + :n => n, + :tp => tp, + :fp => fp, + :tn => tn, + :fn => fn, + :correct_predictions => sprintf("%.2f", 100*(tp+tn).to_f/n), + :weighted_area_under_roc => sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f), + :sensitivity => sprintf("%.3f", tp.to_f/(tp+fn)), + :specificity => sprintf("%.3f", tn.to_f/(tn+fp)) + } + rescue + "Service offline" + end + end + +end + +DataMapper.auto_upgrade! + + diff --git a/parser.rb b/parser.rb new file mode 100644 index 0000000..040714a --- /dev/null +++ b/parser.rb @@ -0,0 +1,110 @@ +require 'spreadsheet' +require 'roo' +class Parser + + attr_accessor :dataset, :format_errors, :smiles_errors, :activity_errors, :duplicates, :nr_compounds, :dataset_uri + + def initialize(file, endpoint_uri) + + @file = file + @dataset = OpenTox::Dataset.new + @feature_uri = endpoint_uri + @dataset.features << endpoint_uri + @dataset.title = URI.decode(endpoint_uri.split(/#/).last) + @format_errors = "" + @smiles_errors = [] + @activity_errors = [] + @duplicates = {} + @nr_compounds = 0 + @data = [] + @activities = [] + @type = "classification" + + # check format by extension - not all browsers provide correct content-type]) + case File.extname(@file[:filename]) + when ".csv" + self.csv + when ".xls", ".xlsx" + self.excel + else + @format_errors = "#{@file[:filename]} is a unsupported file type." + return false + end + + # create dataset + @data.each do |items| + @dataset.compounds << items[0] + @dataset.data[items[0]] = [] unless @dataset.data[items[0]] + case @type + when "classification" + case items[1].to_i.to_s + when '1' + @dataset.data[items[0]] << {@feature_uri => true } + when '0' + @dataset.data[items[0]] << {@feature_uri => false } + end + when "regression" + @dataset.data[items[0]] << {@feature_uri => items[1]} + end + end + @dataset_uri = @dataset.save + + end + + def csv + row = 0 + @file[:tempfile].each_line do |line| + row += 1 + unless line.chomp.match(/^.+[,;].*$/) # check CSV format + @format_errors = "#{@file[:filename]} is not a valid CSV file." + return false + end + items = line.chomp.gsub(/["']/,'').split(/\s*[,;]\s*/) # remove quotes + LOGGER.debug items.join(",") + input = validate(items[0], items[1], row) # smiles, activity + @data << input if input + end + end + + def excel + excel = 'tmp/' + @file[:filename] + File.mv(@file[:tempfile].path,excel) + begin + if File.extname(@file[:filename]) == ".xlsx" + book = Excelx.new(excel) + else + book = Excel.new(excel) + end + book.default_sheet = 0 + 1.upto(book.last_row) do |row| + input = validate( book.cell(row,1), book.cell(row,2), row ) # smiles, activity + @data << input + end + File.safe_unlink(@file[:tempfile]) + rescue + @format_errors = "#{@file[:filename]} is not a valid Excel input file." + return false + end + end + + def validate(smiles, act, row) + compound = OpenTox::Compound.new(:smiles => smiles) + if compound.inchi == "" + @smiles_errors << "Row #{row}: " + [smiles,act].join(", ") + return false + end + if !numeric?(act) + @activity_errors << "Row #{row}: " + [smiles,act].join(", ") + return false + end + @duplicates[compound.inchi] = [] unless @duplicates[compound.inchi] + @duplicates[compound.inchi] << "Row #{row}: " + [smiles, act].join(", ") + @type = "regression" unless act.to_f == 0.0 or act.to_f == 1.0 + @nr_compounds += 1 + [ compound.uri, act.to_f ] + end + + def numeric?(object) + true if Float(object) rescue false + end +end diff --git a/views/prediction.haml b/views/prediction.haml index 92b434b..993c966 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -21,6 +21,8 @@ - elsif activity(a) == 'inactive' .inactive = activity(a) + - else + = a %br ( %a{:href => "#", :id => "linkTrainingData#{p.object_id}"} Training data diff --git a/views/tasks.haml b/views/tasks.haml deleted file mode 100644 index 3de21b5..0000000 --- a/views/tasks.haml +++ /dev/null @@ -1,21 +0,0 @@ -%table - %tr - %th Task - %th Resource - %th Status - %th Started - %th Finished - - @tasks.each do |t| - -# This is inefficient - make only 1 query to the task service and save variables - %tr - %td= t.uri - %td= t.resource - %td= t.status - %td= t.created_at - %td= t.finished_at - -# %td - - case t.status - - when /created|started/ - %form{:name => "cancel", :action => url_for("/task/cancel"), :method => 'post'} - %input{:type => 'hidden', :name => 'uri', :value => t.uri} - %input{:type => "submit", :value => "Cancel"} -- cgit v1.2.3 From bc62e2ce00ea62e369f6fbf70452f00e179621cb Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 28 Jun 2010 17:13:06 +0200 Subject: updated for api-wrapper 1.5.7 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 70b0657..7f9db64 100755 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.5.6" +gem "opentox-ruby-api-wrapper", "= 1.5.7" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From b27d0f1e805f2c85194b851cea44c156469df6e6 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Tue, 29 Jun 2010 11:35:18 +0200 Subject: validation on localhost enabled --- application.rb | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/application.rb b/application.rb index 7f9db64..129ef5c 100755 --- a/application.rb +++ b/application.rb @@ -130,21 +130,21 @@ helpers do model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body model.save end - unless @@config[:services]["opentox-model"].match(/localhost/) - if !model.validation_uri and model.validation_status == "Completed" - begin - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body - LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" - model.save - rescue - end - end - if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' - model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body + #unless @@config[:services]["opentox-model"].match(/localhost/) + if !model.validation_uri and model.validation_status == "Completed" + begin + model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body + LOGGER.debug "Validation URI: #{model.validation_uri}" + model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body + LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" + model.save + rescue end end + if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' + model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body + end + #end end end @@ -350,16 +350,16 @@ post '/upload' do # create a new model end @model.task_uri = task_uri - unless @@config[:services]["opentox-model"].match(/localhost/) - validation_task_uri = OpenTox::Validation.crossvalidation( - :algorithm_uri => OpenTox::Algorithm::Lazar.uri, - :dataset_uri => dataset_uri, - :prediction_feature => feature_uri, - :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" - ).uri - #LOGGER.debug "Validation task: " + validation_task_uri - @model.validation_task_uri = validation_task_uri - end + #unless @@config[:services]["opentox-model"].match(/localhost/) + validation_task_uri = OpenTox::Validation.crossvalidation( + :algorithm_uri => OpenTox::Algorithm::Lazar.uri, + :dataset_uri => dataset_uri, + :prediction_feature => feature_uri, + :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" + ).uri + #LOGGER.debug "Validation task: " + validation_task_uri + @model.validation_task_uri = validation_task_uri + #end @model.nr_compounds = nr_compounds @model.warnings = '' -- cgit v1.2.3 From 258e55e5cbd1355a30dad6bbe2a2638609db9a18 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 2 Jul 2010 12:40:02 +0200 Subject: regression validation (partially) working --- application.rb | 40 ++++++++----------- helper.rb | 20 ---------- model.rb | 38 +++++++++++++++++- parser.rb | 27 ++++++++----- views/create.haml | 30 +++++++------- views/csv_format.haml | 23 ----------- views/excel_format.haml | 64 ------------------------------ views/help.haml | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ views/layout.haml | 5 +-- views/model.haml | 2 + views/prediction.haml | 4 +- 11 files changed, 195 insertions(+), 159 deletions(-) delete mode 100644 views/csv_format.haml delete mode 100644 views/excel_format.haml create mode 100644 views/help.haml diff --git a/application.rb b/application.rb index fecdb63..40aabef 100644 --- a/application.rb +++ b/application.rb @@ -21,9 +21,7 @@ end get '/models/?' do @models = ToxCreateModel.all(:order => [ :created_at.desc ]) - @models.each do |model| - process_model(model) - end + @models.each { |model| model.process } haml :models end @@ -53,7 +51,7 @@ end get '/model/:id/:view/?' do response['Content-Type'] = 'text/plain' model = ToxCreateModel.get(params[:id]) - process_model(model) + model.process begin case params[:view] @@ -79,16 +77,8 @@ get '/create' do haml :create end -get '/about' do - haml :about -end - -get '/csv_format' do - haml :csv_format -end - -get '/excel_format' do - haml :excel_format +get '/help' do + haml :help end get "/confidence" do @@ -120,12 +110,12 @@ post '/upload' do # create a new model redirect url_for('/create') end - #begin + begin @model.task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => parser.dataset_uri, :prediction_feature => feature_uri) - #rescue - # flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." - # redirect url_for('/create') - #end + rescue + flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." + redirect url_for('/create') + end validation_task_uri = OpenTox::Validation.crossvalidation( :algorithm_uri => OpenTox::Algorithm::Lazar.uri, @@ -180,16 +170,19 @@ post '/predict/?' do # post chemical name to model db_activities = [] LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) + # TODO check if prediction failed - returns string source = prediction.creator if prediction.data[@compound.uri] - if source.to_s.match(/model/) + if source.to_s.match(/model/) # real prediction prediction = prediction.data[@compound.uri].first.values.first - if prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")] + LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")] + LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] + if !prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")].nil? @predictions << {:title => model.name, :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")], :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")]} - elsif prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")] + elsif !prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")].nil? @predictions << {:title => model.name, :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")], :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")]} end - else + else # database value prediction = prediction.data[@compound.uri].first.values @predictions << {:title => model.name, :measured_activities => prediction} end @@ -197,6 +190,7 @@ post '/predict/?' do # post chemical name to model @predictions << {:title => model.name, :prediction => "not available (no similar compounds in the training dataset)"} end end + LOGGER.debug @predictions.inspect haml :prediction end diff --git a/helper.rb b/helper.rb index 90529f6..4a5f739 100644 --- a/helper.rb +++ b/helper.rb @@ -10,25 +10,5 @@ helpers do end act end - - def process_model(model) - if !model.uri and model.status == "Completed" - model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body - model.save - end - if !model.validation_uri and model.validation_status == "Completed" - begin - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body - LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" - model.save - rescue - end - end - if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' - model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body - end - end end diff --git a/model.rb b/model.rb index 36670d9..e35507b 100644 --- a/model.rb +++ b/model.rb @@ -1,4 +1,5 @@ class ToxCreateModel + include DataMapper::Resource property :id, Serial property :name, String, :length => 255 @@ -56,6 +57,21 @@ class ToxCreateModel end end + def type + lazar = RestClient.get(@uri, :accept => "application/x-yaml").body + #LOGGER.debug lazar + lazar = YAML.load(lazar) + #LOGGER.debug lazar.inspect + case lazar.dependentVariables + when /classification/ + return "classification" + when /regression/ + return "regression" + else + return "unknown" + end + end + def validation begin uri = File.join(@validation_uri, 'statistics') @@ -93,8 +109,26 @@ class ToxCreateModel end end + def process + if !@uri and status == "Completed" + @uri = RestClient.get(File.join(@task_uri, 'resultURI')).body + save + end + if !@validation_uri and validation_status == "Completed" + begin + @validation_uri = RestClient.get(File.join(@validation_task_uri, 'resultURI')).body + LOGGER.debug "Validation URI: #{@validation_uri}" + @validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @validation_uri).body + LOGGER.debug "Validation Report Task URI: #{@validation_report_task_uri}" + save + rescue + end + end + if @validation_report_task_uri and !@validation_report_uri and validation_report_status == 'Completed' + @validation_report_uri = RestClient.get(File.join(@validation_report_task_uri, 'resultURI')).body + end + end + end DataMapper.auto_upgrade! - - diff --git a/parser.rb b/parser.rb index 040714a..8754531 100644 --- a/parser.rb +++ b/parser.rb @@ -37,14 +37,18 @@ class Parser @dataset.data[items[0]] = [] unless @dataset.data[items[0]] case @type when "classification" - case items[1].to_i.to_s - when '1' + case items[1].to_s + when TRUE_REGEXP @dataset.data[items[0]] << {@feature_uri => true } - when '0' + when FALSE_REGEXP @dataset.data[items[0]] << {@feature_uri => false } end when "regression" - @dataset.data[items[0]] << {@feature_uri => items[1]} + if items[1].to_f == 0 + @activity_errors << "Row #{items[2]}: Zero values not allowed for regression datasets - entry ignored." + else + @dataset.data[items[0]] << {@feature_uri => items[1].to_f} + end end end @dataset_uri = @dataset.save @@ -78,7 +82,7 @@ class Parser book.default_sheet = 0 1.upto(book.last_row) do |row| input = validate( book.cell(row,1), book.cell(row,2), row ) # smiles, activity - @data << input + @data << input if input end File.safe_unlink(@file[:tempfile]) rescue @@ -93,18 +97,23 @@ class Parser @smiles_errors << "Row #{row}: " + [smiles,act].join(", ") return false end - if !numeric?(act) + unless numeric?(act) or classification?(act) @activity_errors << "Row #{row}: " + [smiles,act].join(", ") return false end @duplicates[compound.inchi] = [] unless @duplicates[compound.inchi] @duplicates[compound.inchi] << "Row #{row}: " + [smiles, act].join(", ") - @type = "regression" unless act.to_f == 0.0 or act.to_f == 1.0 + @type = "regression" unless classification?(act) @nr_compounds += 1 - [ compound.uri, act.to_f ] + [ compound.uri, act , row ] end def numeric?(object) - true if Float(object) rescue false + true if Float(object) rescue false + end + + def classification?(object) + !object.to_s.strip.match(TRUE_REGEXP).nil? or !object.to_s.strip.match(FALSE_REGEXP).nil? end + end diff --git a/views/create.haml b/views/create.haml index 0f50756..3cf05c1 100644 --- a/views/create.haml +++ b/views/create.haml @@ -2,28 +2,32 @@ %p This service creates - %a{:href => 'http://lazar.in-silico.de'} lazar - %em classification - models (i.e. models that discriminate between toxic/nontoxic compounds) from your uploaded datasets. Here are - = link_to "instructions", '/excel_format' - , for creating training datasets in Excel. + %ul + %li + %a{:href => 'http://lazar.in-silico.de'} lazar + %em classification + models (i.e. models that discriminate between toxic/nontoxic compounds) and + %li + %a{:href => 'http://lazar.in-silico.de'} lazar + %em regression + models (i.e. models that predict quantitative values, e.g. LC50's) + from your uploaded datasets. Further modelling algorithms will be added in future versions. + %p - Facilities to create models for quantitative values (e.g. LC50s) and further modelling algorithms will be added in future versions. + Please read the + = link_to "instructions for creating training datasets", '/help' + before submitting. %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } %fieldset - -#%legend - Upload training data and create a - %a{:href => 'http://lazar.in-silico.de'} lazar - model - %label{:for => 'endpoint'} 1. Enter a name for your endpoint: + %label{:for => 'endpoint'} 1. Enter endpoint name and unit (for regression): %input{:type => 'text', :name => 'endpoint', :id => 'endpoint', :size => '50'} %br %label{:for => 'file'} 2. Upload training data in - = link_to "Excel", '/excel_format' + = link_to "Excel", '/help' or - = link_to "CSV", '/csv_format' + = link_to "CSV", '/help' format: %input{:type => 'file', :name => 'file', :id => 'file', :size => '41'} %input{ :type => "submit", :value => "Create model"} diff --git a/views/csv_format.haml b/views/csv_format.haml deleted file mode 100644 index 999bb68..0000000 --- a/views/csv_format.haml +++ /dev/null @@ -1,23 +0,0 @@ -= link_to "Back to model creation", '/create' -%p - The input file should contain two columns, separated by a comma. Enter in the first column the chemical structure in - %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification"} SMILES - format, in the second column the activity classification (1: active, 0: inactive), e.g. - -.code - %code - %br CC(=O)Nc1ccc(O)cc1, 1 - %br O=c1[nH]cnc2[nH]ncc12, 1 - %br CCCCNc1cc(cc(c1Oc2ccccc2)S(=O)(=O)N)C(=O)O, 1 - %br CC(C)(C)NCC(O)COc1cccc2NC(=O)CCc12, 1 - %br CN(C)CCCC1(OCc2cc(C#N)ccc21)c3ccc(F)cc3, 1 - %br CCC(CC)CCN1C(=O)CN=C(C2CCCCC2F)c3cc(Cl)ccc13, 0 - %br CCN(CC)CC(=O)Nc1c(C)cccc1C, 0 - %br CC(C)(C)NCC(O)COc1cccc2CC(O)C(O)Cc12, 0 - %br CN1CCCC1c2cccnc2, 0 - -%p - Here is an example for download: - = link_to "hamster_carcinogenicity.csv", "/hamster_carcinogenicity.csv" - -%p You can create input files in Excel: Create a sheet with two columns and export them as CSV file with the "Save As" option from the menu, selecting the CSV (comma delimited) format. diff --git a/views/excel_format.haml b/views/excel_format.haml deleted file mode 100644 index 4cbbd08..0000000 --- a/views/excel_format.haml +++ /dev/null @@ -1,64 +0,0 @@ -= link_to "Back to model creation", '/create' -%p - The Excel input file should contain a single spreadsheet with two columns. Enter in the first column the chemical structure in - %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification"} SMILES - format, in the second column the activity classification (1: active, 0: inactive), e.g. - -- n = 0 - -.code - %table - %tr - %td - %th A - %th B - %tr - - n += 1 - %th= n - %td CC(=O)Nc1ccc(O)cc1 - %td 1 - %tr - - n += 1 - %th= n - %td O=c1[nH]cnc2[nH]ncc12 - %td 1 - %tr - - n += 1 - %th= n - %td CCCCNc1cc(cc(c1Oc2ccccc2)S(=O)(=O)N)C(=O)O - %td 1 - %tr - - n += 1 - %th= n - %td CC(C)(C)NCC(O)COc1cccc2NC(=O)CCc12 - %td 1 - %tr - - n += 1 - %th= n - %td CN(C)CCCC1(OCc2cc(C#N)ccc21)c3ccc(F)cc3 - %td 1 - %tr - - n += 1 - %th= n - %td CCC(CC)CCN1C(=O)CN=C(C2CCCCC2F)c3cc(Cl)ccc13 - %td 0 - %tr - - n += 1 - %th= n - %td CCN(CC)CC(=O)Nc1c(C)cccc1C - %td 0 - %tr - - n += 1 - %th= n - %td CC(C)(C)NCC(O)COc1cccc2CC(O)C(O)Cc12 - %td 0 - %tr - - n += 1 - %th= n - %td CN1CCCC1c2cccnc2 - %td 0 - -%p - Here is an example file for download: - = link_to "hamster_carcinogenicity.xls", "/hamster_carcinogenicity.xls" - diff --git a/views/help.haml b/views/help.haml new file mode 100644 index 0000000..52339ce --- /dev/null +++ b/views/help.haml @@ -0,0 +1,101 @@ += link_to "Back to model creation", '/create' +%p + Input files have two columns. Enter in the first column the chemical structure in + %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification"} SMILES + format, in the second column the toxic activity. +%dl + %dt Classification datasets + %dd Please use 1/0, active/inactive or true/false to indicate active/inactive compounds. + %dt Regression datasets + %dd + Enter a quantitative value. For optimal performance you should + %ul + %li use molar units + %li enter non-logarithmic values (logarithms are taken internally) + %li avoid 0 activities (will be ignored) +%p + Input files are accepted in + %a{:href => "http://en.wikipedia.org/wiki/Microsoft_Excel"} Excel + and + %a{:href => "en.wikipedia.org/wiki/Comma-separated_values"} CSV + formats. + +%h3 Excel example + +- n = 0 + +.code + %table + %tr + %td + %th A + %th B + %tr + - n += 1 + %th= n + %td CC(=O)Nc1ccc(O)cc1 + %td 1 + %tr + - n += 1 + %th= n + %td O=c1[nH]cnc2[nH]ncc12 + %td 1 + %tr + - n += 1 + %th= n + %td CCCCNc1cc(cc(c1Oc2ccccc2)S(=O)(=O)N)C(=O)O + %td 1 + %tr + - n += 1 + %th= n + %td CC(C)(C)NCC(O)COc1cccc2NC(=O)CCc12 + %td 1 + %tr + - n += 1 + %th= n + %td CN(C)CCCC1(OCc2cc(C#N)ccc21)c3ccc(F)cc3 + %td 1 + %tr + - n += 1 + %th= n + %td CCC(CC)CCN1C(=O)CN=C(C2CCCCC2F)c3cc(Cl)ccc13 + %td 0 + %tr + - n += 1 + %th= n + %td CCN(CC)CC(=O)Nc1c(C)cccc1C + %td 0 + %tr + - n += 1 + %th= n + %td CC(C)(C)NCC(O)COc1cccc2CC(O)C(O)Cc12 + %td 0 + %tr + - n += 1 + %th= n + %td CN1CCCC1c2cccnc2 + %td 0 + +%p + Excel example file for download: + = link_to "hamster_carcinogenicity.xls", "/hamster_carcinogenicity.xls" + +%h3 CSV example + +.code + %code + %br CC(=O)Nc1ccc(O)cc1, 1 + %br O=c1[nH]cnc2[nH]ncc12, 1 + %br CCCCNc1cc(cc(c1Oc2ccccc2)S(=O)(=O)N)C(=O)O, 1 + %br CC(C)(C)NCC(O)COc1cccc2NC(=O)CCc12, 1 + %br CN(C)CCCC1(OCc2cc(C#N)ccc21)c3ccc(F)cc3, 1 + %br CCC(CC)CCN1C(=O)CN=C(C2CCCCC2F)c3cc(Cl)ccc13, 0 + %br CCN(CC)CC(=O)Nc1c(C)cccc1C, 0 + %br CC(C)(C)NCC(O)COc1cccc2CC(O)C(O)Cc12, 0 + %br CN1CCCC1c2cccnc2, 0 + +%p + CSV example for download: + = link_to "hamster_carcinogenicity.csv", "/hamster_carcinogenicity.csv" + +%p You can create CSV files in Excel: Create a sheet with two columns and export them as CSV file with the "Save As" option from the menu, selecting the CSV (comma delimited) format. diff --git a/views/layout.haml b/views/layout.haml index 012e296..7935b33 100755 --- a/views/layout.haml +++ b/views/layout.haml @@ -23,11 +23,10 @@ = link_to "Inspect", "/models" %li{:class => ("selected" if /predict/ =~ request.path )} = link_to "Predict", "/predict" - %li{:class => ("selected" if /about/ =~ request.path )} - = link_to "About", "/about" + %li{:class => ("selected" if /help/ =~ request.path )} + = link_to "Help", "/help" .content - - if `hostname`.match(/ot-test|ot-dev/) .notice This service is for testing purposes only - once a week all models will be deleted. Please send bug reports and feature requests to our diff --git a/views/model.haml b/views/model.haml index fd1d114..e336de6 100644 --- a/views/model.haml +++ b/views/model.haml @@ -33,6 +33,8 @@ %dd %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} #{File.basename model.algorithm} -# %a{:href => model.algorithm} RDF/XML + %dt Type: + %dd= model.type %dt Descriptors: %dd %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes diff --git a/views/prediction.haml b/views/prediction.haml index 993c966..96385ef 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -41,12 +41,12 @@ = activity(p[:prediction]) - else %br - %em= p[:prediction] + %em= sprintf('%.03g', p[:prediction]) - if p[:confidence] %br ( %a{:href => "#", :id => "linkConfidence#{p.object_id}"} Confidence - = ": #{sprintf('%.03f', p[:confidence].to_f.abs)}" + = ": #{sprintf('%.03g', p[:confidence].to_f.abs)}" :javascript $("a#linkConfidence#{p.object_id}").click(function () { $("dl#confidence").toggle(); -- cgit v1.2.3 From 6b8b0a161f492f15c33d4f18e50b604e0fd547bc Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 2 Jul 2010 17:50:43 +0200 Subject: Initial regression validation display --- application.rb | 14 ++++++---- model.rb | 39 +++++++++++++++----------- public/javascripts/toxcreate.js | 2 +- views/classification_validation.haml | 54 ++++++++++++++++++++++++++++++++++++ views/model.haml | 7 +++-- views/model_validation.haml | 54 ------------------------------------ views/regression_validation.haml | 19 +++++++++++++ 7 files changed, 110 insertions(+), 79 deletions(-) create mode 100644 views/classification_validation.haml delete mode 100644 views/model_validation.haml create mode 100644 views/regression_validation.haml diff --git a/application.rb b/application.rb index 40aabef..735f388 100644 --- a/application.rb +++ b/application.rb @@ -53,18 +53,20 @@ get '/model/:id/:view/?' do model = ToxCreateModel.get(params[:id]) model.process - begin + #begin case params[:view] when "model" haml :model, :locals=>{:model=>model}, :layout => false - when "validation" - haml :model_validation, :locals=>{:model=>model}, :layout => false + when "classification_validation" + haml :classification_validation, :locals=>{:model=>model}, :layout => false + when "regression_validation" + haml :regression_validation, :locals=>{:model=>model}, :layout => false else return "render error" end - rescue - return "unable to render model" - end + #rescue + # return "unable to render model" + #end end get '/predict/?' do diff --git a/model.rb b/model.rb index e35507b..6e2441a 100644 --- a/model.rb +++ b/model.rb @@ -11,6 +11,7 @@ class ToxCreateModel property :validation_report_uri, String, :length => 255 property :warnings, Text, :length => 2**32-1 property :nr_compounds, Integer + property :type, String property :created_at, DateTime def status @@ -57,22 +58,7 @@ class ToxCreateModel end end - def type - lazar = RestClient.get(@uri, :accept => "application/x-yaml").body - #LOGGER.debug lazar - lazar = YAML.load(lazar) - #LOGGER.debug lazar.inspect - case lazar.dependentVariables - when /classification/ - return "classification" - when /regression/ - return "regression" - else - return "unknown" - end - end - - def validation + def classification_validation begin uri = File.join(@validation_uri, 'statistics') yaml = RestClient.get(uri).body @@ -109,11 +95,32 @@ class ToxCreateModel end end + def regression_validation + begin + uri = File.join(@validation_uri, 'statistics') + yaml = RestClient.get(uri).body + v = YAML.load(yaml) + rescue + "Service offline" + end + end + def process + if !@uri and status == "Completed" @uri = RestClient.get(File.join(@task_uri, 'resultURI')).body + lazar = YAML.load(RestClient.get(@uri, :accept => "application/x-yaml").body) + case lazar.dependentVariables + when /classification/ + @type = "classification" + when /regression/ + @type = "regression" + else + @type = "unknown" + end save end + if !@validation_uri and validation_status == "Completed" begin @validation_uri = RestClient.get(File.join(@validation_task_uri, 'resultURI')).body diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index b1555c6..cd2efa2 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -68,7 +68,7 @@ $(function() { }, success: function(data) { if (view == "model") $("div#model_" + id).html(data); - if (view == "validation") $("dl#model_validation_" + id).html(data); + if (view ~= /validation/) $("dl#model_validation_" + id).html(data); }, error: function(data) { //alert("loadModel error"); diff --git a/views/classification_validation.haml b/views/classification_validation.haml new file mode 100644 index 0000000..6d18d09 --- /dev/null +++ b/views/classification_validation.haml @@ -0,0 +1,54 @@ +%dl{:id => "model_validation_#{model.id}"} + %dt + Validation: + %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) + %dd + - if model.validation_uri + - v = model.classification_validation + - if v == "Service offline" + = v + - else + %dl + %dt Number of predictions: + %dd= v[:n] + %dt Correct predictions: + %dd + = v[:correct_predictions] + = '%' + %dt + %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: + %dd + = v[:weighted_area_under_roc] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: + %dd= v[:specificity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: + %dd= v[:sensitivity] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: + %dd + %table + %tr + %td{:colspan => 2, :rowspan => 2} + -#%td + %th{:colspan => 2} Measured + %tr + -#%td{:colspan => 2} + -#%th Predicted + %th{:bgcolor => "#CCD2DC"} active + %th{:bgcolor => "#CCD2DC"} inactive + %tr + %th{:rowspan => 2} Predicted + %th{:bgcolor => "#CCD2DC"} active + %td= v[:tp] + %td= v[:fp] + %tr + %th{:bgcolor => "#CCD2DC"} inactive + %td= v[:fn] + %td= v[:tn] + - else + = image_tag("/snake_transparent.gif") if model.validation_status == "Running" + %a{:href => model.validation_task_uri} #{model.validation_status} diff --git a/views/model.haml b/views/model.haml index e336de6..234dcc6 100644 --- a/views/model.haml +++ b/views/model.haml @@ -32,7 +32,6 @@ %dt Algorithm: %dd %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} #{File.basename model.algorithm} - -# %a{:href => model.algorithm} RDF/XML %dt Type: %dd= model.type %dt Descriptors: @@ -58,5 +57,9 @@ , %a{:href => "#{model.uri}.yaml"} YAML %em (experts, models cannot be exported in Excel) - = haml :model_validation, :locals=>{:model=>model}, :layout => false + - case model.type + - when "classification" + = haml :classification_validation, :locals=>{:model=>model}, :layout => false + -when "regression" + = haml :regression_validation, :locals=>{:model=>model}, :layout => false diff --git a/views/model_validation.haml b/views/model_validation.haml deleted file mode 100644 index 8f5e3ce..0000000 --- a/views/model_validation.haml +++ /dev/null @@ -1,54 +0,0 @@ -%dl{:id => "model_validation_#{model.id}"} - %dt - Validation: - %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) - %dd - - if model.validation_uri - - v = model.validation - - if v == "Service not available" - = v - - else - %dl - %dt Number of predictions: - %dd= v[:n] - %dt Correct predictions: - %dd - = v[:correct_predictions] - = '%' - %dt - %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: - %dd - = v[:weighted_area_under_roc] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: - %dd= v[:specificity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: - %dd= v[:sensitivity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: - %dd - %table - %tr - %td{:colspan => 2, :rowspan => 2} - -#%td - %th{:colspan => 2} Measured - %tr - -#%td{:colspan => 2} - -#%th Predicted - %th{:bgcolor => "#CCD2DC"} active - %th{:bgcolor => "#CCD2DC"} inactive - %tr - %th{:rowspan => 2} Predicted - %th{:bgcolor => "#CCD2DC"} active - %td= v[:tp] - %td= v[:fp] - %tr - %th{:bgcolor => "#CCD2DC"} inactive - %td= v[:fn] - %td= v[:tn] - - else - = image_tag("/snake_transparent.gif") if model.validation_status == "Running" - %a{:href => model.validation_task_uri} #{model.validation_status} diff --git a/views/regression_validation.haml b/views/regression_validation.haml new file mode 100644 index 0000000..983599b --- /dev/null +++ b/views/regression_validation.haml @@ -0,0 +1,19 @@ +%dl{:id => "model_validation_#{model.id}"} + %dt + Validation: + %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} (more details) + %dd + - if model.validation_uri + - v = model.regression_validation + - if v == "Service offline" + = v + - else + %dl + %dt Number of predictions: + %dd= v[:n] + %p= v.inspect + - else + = image_tag("/snake_transparent.gif") if model.validation_status == "Running" + %a{:href => model.validation_task_uri} #{model.validation_status} -- cgit v1.2.3 From 4e7cb403dc2572593a3eef601b14e28a27f2524c Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 2 Jul 2010 18:42:53 +0200 Subject: failed predictions fixed --- application.rb | 3 ++- views/prediction.haml | 7 +++++-- views/style.sass | 3 +++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/application.rb b/application.rb index 735f388..3967df5 100644 --- a/application.rb +++ b/application.rb @@ -166,13 +166,14 @@ post '/predict/?' do # post chemical name to model @predictions = [] params[:selection].keys.each do |id| model = ToxCreateModel.get(id.to_i) + model.process unless model.uri + LOGGER.debug model.to_yaml prediction = nil confidence = nil title = nil db_activities = [] LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) - # TODO check if prediction failed - returns string source = prediction.creator if prediction.data[@compound.uri] if source.to_s.match(/model/) # real prediction diff --git a/views/prediction.haml b/views/prediction.haml index 96385ef..1edb2e8 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -39,9 +39,12 @@ - elsif activity(p[:prediction]) == 'inactive' .inactive = activity(p[:prediction]) + - elsif p[:prediction].is_a?(Float) + .other + = sprintf('%.03g', p[:prediction]) - else - %br - %em= sprintf('%.03g', p[:prediction]) + .other + %em= p[:prediction].to_s - if p[:confidence] %br ( diff --git a/views/style.sass b/views/style.sass index 2fd0ed7..1900517 100644 --- a/views/style.sass +++ b/views/style.sass @@ -179,6 +179,9 @@ body .inactive color: green +.other + color: black + dl dd td -- cgit v1.2.3 From 5eec83b4196c84b32817d045d31b0815db38fb05 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 5 Jul 2010 12:22:04 +0200 Subject: javascript regexp fixed --- application.rb | 10 +++++----- model.rb | 2 ++ public/javascripts/toxcreate.js | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/application.rb b/application.rb index 3967df5..c18a394 100644 --- a/application.rb +++ b/application.rb @@ -51,9 +51,9 @@ end get '/model/:id/:view/?' do response['Content-Type'] = 'text/plain' model = ToxCreateModel.get(params[:id]) - model.process + model = model.process - #begin + begin case params[:view] when "model" haml :model, :locals=>{:model=>model}, :layout => false @@ -64,9 +64,9 @@ get '/model/:id/:view/?' do else return "render error" end - #rescue - # return "unable to render model" - #end + rescue + return "unable to render model" + end end get '/predict/?' do diff --git a/model.rb b/model.rb index 6e2441a..6430933 100644 --- a/model.rb +++ b/model.rb @@ -136,6 +136,8 @@ class ToxCreateModel end end + self + end DataMapper.auto_upgrade! diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index cd2efa2..6d593cc 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -68,7 +68,7 @@ $(function() { }, success: function(data) { if (view == "model") $("div#model_" + id).html(data); - if (view ~= /validation/) $("dl#model_validation_" + id).html(data); + if (view.match(/validation/)) $("dl#model_validation_" + id).html(data); }, error: function(data) { //alert("loadModel error"); -- cgit v1.2.3 From fc0f9e5fa3b521397d2026e649c4873600026838 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 14 Jul 2010 13:56:50 +0200 Subject: model creation working, validation report generation fails for large datasets --- application.rb | 22 +++++++++++------- model.rb | 49 ++++++++++++++++++++++++++-------------- views/regression_validation.haml | 14 +++++++++--- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/application.rb b/application.rb index c18a394..5d5435e 100644 --- a/application.rb +++ b/application.rb @@ -51,21 +51,27 @@ end get '/model/:id/:view/?' do response['Content-Type'] = 'text/plain' model = ToxCreateModel.get(params[:id]) - model = model.process + model.process + model.save begin case params[:view] when "model" haml :model, :locals=>{:model=>model}, :layout => false - when "classification_validation" - haml :classification_validation, :locals=>{:model=>model}, :layout => false - when "regression_validation" - haml :regression_validation, :locals=>{:model=>model}, :layout => false + when /validation/ + if model.type == "classification" + haml :classification_validation, :locals=>{:model=>model}, :layout => false + elsif model.type == "regression" + haml :regression_validation, :locals=>{:model=>model}, :layout => false + else + return "Unknown model type '#{model.type}'" + end else - return "render error" + return "unable to render model: id #{params[:id]}, view #{params[:view]}" + #return "render error" end rescue - return "unable to render model" + return "unable to render model: id #{params[:id]}, view #{params[:view]}" end end @@ -145,7 +151,7 @@ post '/upload' do # create a new model @model.warnings += "

Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):

" + duplicate_warnings unless duplicate_warnings.empty? @model.save - flash[:notice] = "Model creation started. Please be patient - model building may take up to several hours depending on the number and size of the input molecules." + flash[:notice] = "Model creation and validation started - this may last up to several hours depending on the number and size of the training compounds." redirect url_for('/models') # TODO: check for empty model diff --git a/model.rb b/model.rb index 6430933..5b68558 100644 --- a/model.rb +++ b/model.rb @@ -15,7 +15,11 @@ class ToxCreateModel property :created_at, DateTime def status - RestClient.get(File.join(@task_uri, 'hasStatus')).body + #begin + RestClient.get(File.join(@task_uri, 'hasStatus')).body + #rescue + # "Service offline" + #end end def validation_status @@ -107,36 +111,47 @@ class ToxCreateModel def process - if !@uri and status == "Completed" - @uri = RestClient.get(File.join(@task_uri, 'resultURI')).body + if @uri.nil? and status == "Completed" + update :uri => RestClient.get(File.join(@task_uri, 'resultURI')).body lazar = YAML.load(RestClient.get(@uri, :accept => "application/x-yaml").body) case lazar.dependentVariables when /classification/ - @type = "classification" + update :type => "classification" when /regression/ - @type = "regression" + update :type => "regression" else - @type = "unknown" + update :type => "unknown" end - save - end - if !@validation_uri and validation_status == "Completed" + elsif @validation_uri.nil? and validation_status == "Completed" begin - @validation_uri = RestClient.get(File.join(@validation_task_uri, 'resultURI')).body + update :validation_uri => RestClient.get(File.join(@validation_task_uri, 'resultURI')).body LOGGER.debug "Validation URI: #{@validation_uri}" - @validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @validation_uri).body + update :validation_report_task_uri => RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @validation_uri).body LOGGER.debug "Validation Report Task URI: #{@validation_report_task_uri}" - save rescue + LOGGER.warn "Cannot create Validation Report Task #{@validation_report_task_uri} for Validation URI #{@validation_uri} from Task #{@validation_task_uri}" + end + + elsif @validation_report_uri.nil? and validation_report_status == "Completed" + begin + LOGGER.debug File.join(@validation_report_task_uri, 'resultURI') + LOGGER.debug "Report URI: "+RestClient.get(File.join(@validation_report_task_uri, 'resultURI')).body + update :validation_report_uri => RestClient.get(File.join(@validation_report_task_uri, 'resultURI')).body + rescue + LOGGER.warn "Cannot create Validation Report for Task URI #{@validation_report_task_uri} " end end - if @validation_report_task_uri and !@validation_report_uri and validation_report_status == 'Completed' - @validation_report_uri = RestClient.get(File.join(@validation_report_task_uri, 'resultURI')).body - end - end - self + #LOGGER.debug self.to_yaml + #LOGGER.debug @uri + #LOGGER.debug @validation_uri + #LOGGER.debug @validation_uri.nil? + #LOGGER.debug validation_status + #LOGGER.debug self.validation_report_task_uri + #LOGGER.debug self.validation_report_uri + #self.save + end end diff --git a/views/regression_validation.haml b/views/regression_validation.haml index 983599b..6f9e106 100644 --- a/views/regression_validation.haml +++ b/views/regression_validation.haml @@ -11,9 +11,17 @@ = v - else %dl - %dt Number of predictions: - %dd= v[:n] - %p= v.inspect + %dt Number of predictions + %dd= v[:num_instances] - v[:num_unpredicted] + %dt + %a{:href => "http://en.wikipedia.org/wiki/R-squared"} R-squared + %dd= sprintf '%.03g', v[:regression_statistics][:r_square] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Root_mean_square_deviation"} Root Mean Square Error + %dd= sprintf '%.03g', v[:regression_statistics][:root_mean_squared_error] + %dt + %a{:href => "http://en.wikipedia.org/wiki/Mean_absolute_error"} Mean Absolute Error + %dd= sprintf '%.03g', v[:regression_statistics][:mean_absolute_error] - else = image_tag("/snake_transparent.gif") if model.validation_status == "Running" %a{:href => model.validation_task_uri} #{model.validation_status} -- cgit v1.2.3 From 5e2bc1400491b5a9a281d2305888fee33048bb05 Mon Sep 17 00:00:00 2001 From: gebele Date: Thu, 15 Jul 2010 15:51:37 +0200 Subject: test text color --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index 2fd0ed7..f52cb92 100644 --- a/views/style.sass +++ b/views/style.sass @@ -3,7 +3,7 @@ $bg_color2: #e5e7eb $fg_color: #424345 $ot_purple: #5d308a $body_color: white -$text_color: black +$text_color: green $notice_border: black body -- cgit v1.2.3 From 19c5c0a50970b6deac03e2adf667eb7af99ee608 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 10:03:45 +0200 Subject: overflow for large predictions --- views/style.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/views/style.sass b/views/style.sass index f52cb92..549e022 100644 --- a/views/style.sass +++ b/views/style.sass @@ -122,6 +122,7 @@ body border: 1px solid .predictions text-align: center + overflow: auto table border-spacing: 0 border-collapse: collapse -- cgit v1.2.3 From 58d8326476b79b6ea8cbcd17a0ff68c8c3ec68a2 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 10:07:09 +0200 Subject: overflow for large predictions --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index 549e022..d131479 100644 --- a/views/style.sass +++ b/views/style.sass @@ -122,7 +122,7 @@ body border: 1px solid .predictions text-align: center - overflow: auto + overflow: scroll table border-spacing: 0 border-collapse: collapse -- cgit v1.2.3 From 17d6d71144fff7516d4556ae94ee443fad96e517 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 10:49:17 +0200 Subject: overflow fix for large predictions --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index d131479..af38c4c 100644 --- a/views/style.sass +++ b/views/style.sass @@ -3,7 +3,7 @@ $bg_color2: #e5e7eb $fg_color: #424345 $ot_purple: #5d308a $body_color: white -$text_color: green +$text_color: black $notice_border: black body -- cgit v1.2.3 From a41936739d0d498f0e5214edea2517838ad2f867 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 11:15:50 +0200 Subject: overflow for large predictions --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index af38c4c..79bf13c 100644 --- a/views/style.sass +++ b/views/style.sass @@ -122,7 +122,7 @@ body border: 1px solid .predictions text-align: center - overflow: scroll + overflow: auto table border-spacing: 0 border-collapse: collapse -- cgit v1.2.3 From 4a691290e63fa1bf9f4935ff782c62aea7df2715 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 19 Jul 2010 12:20:37 +0200 Subject: opentox-api-wrapper bumped to 1.6.0 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 5d5435e..1d3d652 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.5.7" +gem "opentox-ruby-api-wrapper", "= 1.6.0" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From ade53cc2226f5bb560b8a9e6ad2dea638a312727 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 14:43:14 +0200 Subject: without font logo --- views/layout.haml | 4 ---- views/style.sass | 18 +----------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/views/layout.haml b/views/layout.haml index 012e296..a8f14c5 100755 --- a/views/layout.haml +++ b/views/layout.haml @@ -10,10 +10,6 @@ %body .logo= image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate', :align => "right" - -#.headline - .logo - .span1="Tox" - .span2="Create" .index %ul diff --git a/views/style.sass b/views/style.sass index 79bf13c..c1b1696 100644 --- a/views/style.sass +++ b/views/style.sass @@ -21,23 +21,7 @@ body .headline .logo float: right - /* .logo - top: 1% - float: right - //display: inline - font-size: 2.5em - word-spacing: -2px - - .span1 - color: black - font-weight: bolder - letter-spacing: -3px - - .span2 - color = !ot_purple - font-weight: 500 - position: relative - left: -6px + .index clear: both ul -- cgit v1.2.3 From 71a43e44d069bdcd7831e8cdf07765af2f07cf95 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 14:50:17 +0200 Subject: new table style --- views/style.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/views/style.sass b/views/style.sass index c1b1696..b8dd53d 100644 --- a/views/style.sass +++ b/views/style.sass @@ -96,6 +96,7 @@ body padding: 1% background-color: white table + display: inline-table border-collapse: collapse th padding: 0.5em -- cgit v1.2.3 From ed65b38f793ab75140b87dccf1aefba2230303ac Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 14:53:34 +0200 Subject: without liststyle in index --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index b8dd53d..8436ce1 100644 --- a/views/style.sass +++ b/views/style.sass @@ -28,7 +28,7 @@ body margin: 0 0 2px 0 padding: 0 white-space: nowrap - list-style-type: none + //list-style-type: none li margin: 0 padding: 2px -- cgit v1.2.3 From 9e2a5644d5e6d4ce8a0f954e1b0cf21f52fce302 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 14:58:35 +0200 Subject: cleared syntax --- views/style.sass | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/views/style.sass b/views/style.sass index 8436ce1..4492767 100644 --- a/views/style.sass +++ b/views/style.sass @@ -28,7 +28,7 @@ body margin: 0 0 2px 0 padding: 0 white-space: nowrap - //list-style-type: none + list-style-type: none li margin: 0 padding: 2px @@ -58,15 +58,12 @@ body .content background-color: $bg_color height: 100% - //padding: 0.5em - //margin: 1% padding: 1em border: 1px solid color: $fg_color h2 margin: 20px 3px 2px 3px .notice - //background-color = !body_color padding: 1em background-color: $body_color border: 1px solid @@ -130,19 +127,15 @@ body border: 1px solid margin-top: 0.6em dl - //display: block dt width: 15em font-weight: bold float: left clear: both - //display: block dd clear: right margin: 0.2em 0em - //display: block dl - //display: block clear: both padding: 0em background-color: $bg_color2 @@ -153,8 +146,7 @@ body font-weight: bold float: left clear: right - dd - //padding-left: 2em + .footer margin: 0.5em padding: 0.5em @@ -176,7 +168,6 @@ dl th border-bottom: 1px dotted white text-align: center - //background-color: #CCD2DC padding: 0.3em table border-collapse: collapse -- cgit v1.2.3 From 183b6dbe1f0d9e5939eda401018feb57b3bd0948 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 15:02:31 +0200 Subject: index display inline --- views/style.sass | 1 + 1 file changed, 1 insertion(+) diff --git a/views/style.sass b/views/style.sass index 4492767..ede5b6a 100644 --- a/views/style.sass +++ b/views/style.sass @@ -30,6 +30,7 @@ body white-space: nowrap list-style-type: none li + display: inline margin: 0 padding: 2px display: inline -- cgit v1.2.3 From 865059337a20b0740ea3521b61543045d7b51a45 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 15:07:12 +0200 Subject: index without clear --- views/style.sass | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/views/style.sass b/views/style.sass index ede5b6a..1cc49ef 100644 --- a/views/style.sass +++ b/views/style.sass @@ -23,14 +23,13 @@ body float: right .index - clear: both + //clear: both ul margin: 0 0 2px 0 padding: 0 white-space: nowrap list-style-type: none li - display: inline margin: 0 padding: 2px display: inline -- cgit v1.2.3 From 3f497641fc5f302562a3c4e7ffffa228b81738b7 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 15:09:30 +0200 Subject: index redo clear float --- views/style.sass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/style.sass b/views/style.sass index 1cc49ef..4492767 100644 --- a/views/style.sass +++ b/views/style.sass @@ -23,7 +23,7 @@ body float: right .index - //clear: both + clear: both ul margin: 0 0 2px 0 padding: 0 -- cgit v1.2.3 From d77ec12f83489f92417efc6287ddf8f987795198 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 15:19:45 +0200 Subject: sass position replace in --- application.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/application.rb b/application.rb index 129ef5c..0a6cd6a 100755 --- a/application.rb +++ b/application.rb @@ -13,6 +13,13 @@ LOGGER.progname = File.expand_path __FILE__ use Rack::Flash set :sessions, true + +# SASS stylesheet +get '/stylesheets/style.css' do + headers 'Content-Type' => 'text/css; charset=utf-8' + sass :style +end + class ToxCreateModel include DataMapper::Resource property :id, Serial @@ -26,6 +33,7 @@ class ToxCreateModel property :warnings, Text, :length => 2**32-1 property :nr_compounds, Integer property :created_at, DateTime + def status RestClient.get(File.join(@task_uri, 'hasStatus')).body @@ -432,8 +440,4 @@ end # fail "testing mail delivery" #end -# SASS stylesheet -get '/stylesheets/style.css' do - headers 'Content-Type' => 'text/css; charset=utf-8' - sass :style -end + -- cgit v1.2.3 From bd4b6eae34ccade055bc847da15584765ad2b43d Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 19 Jul 2010 15:39:53 +0200 Subject: page refresh until validation report finished --- model.rb | 8 -------- public/javascripts/toxcreate.js | 4 ++-- views/classification_validation.haml | 2 +- views/regression_validation.haml | 2 +- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/model.rb b/model.rb index 5b68558..d10b95f 100644 --- a/model.rb +++ b/model.rb @@ -143,14 +143,6 @@ class ToxCreateModel end end - #LOGGER.debug self.to_yaml - #LOGGER.debug @uri - #LOGGER.debug @validation_uri - #LOGGER.debug @validation_uri.nil? - #LOGGER.debug validation_status - #LOGGER.debug self.validation_report_task_uri - #LOGGER.debug self.validation_report_uri - #self.save end end diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index 6d593cc..048bd46 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -79,9 +79,9 @@ $(function() { checkValidation = function() { var reload_id = ""; - $("input.model_validation").each(function(){ + $("input.model_validation_report").each(function(){ if($(this).val() != "Completed") { - reload_id = this.id.replace("model_validation_",""); + reload_id = this.id.replace("model_validation_report_",""); if(/^\d+$/.test(reload_id)) loadModel(reload_id, 'validation'); }; }); diff --git a/views/classification_validation.haml b/views/classification_validation.haml index 6d18d09..26f0617 100644 --- a/views/classification_validation.haml +++ b/views/classification_validation.haml @@ -1,7 +1,7 @@ %dl{:id => "model_validation_#{model.id}"} %dt Validation: - %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } + %input{ :id => "model_validation_report_#{model.id}", :type => "hidden", :value => "#{model.validation_report_status}", :class => "model_validation_report" } - if model.validation_report_uri %a{:href => model.validation_report_uri, :target => "_blank"} (more details) %dd diff --git a/views/regression_validation.haml b/views/regression_validation.haml index 6f9e106..ac45307 100644 --- a/views/regression_validation.haml +++ b/views/regression_validation.haml @@ -1,7 +1,7 @@ %dl{:id => "model_validation_#{model.id}"} %dt Validation: - %input{ :id => "model_validation_#{model.id}", :type => "hidden", :value => "#{model.validation_status}", :class => "model_validation" } + %input{ :id => "model_validation_report_#{model.id}", :type => "hidden", :value => "#{model.validation_report_status}", :class => "model_validation_report" } - if model.validation_report_uri %a{:href => model.validation_report_uri, :target => "_blank"} (more details) %dd -- cgit v1.2.3 From 290489a540a358ddd77e1d261ae0eb8bfc17eec8 Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 19 Jul 2010 18:45:51 +0200 Subject: favicon added --- application.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/application.rb b/application.rb index 0a6cd6a..aa1f0c1 100755 --- a/application.rb +++ b/application.rb @@ -34,7 +34,6 @@ class ToxCreateModel property :nr_compounds, Integer property :created_at, DateTime - def status RestClient.get(File.join(@task_uri, 'hasStatus')).body end -- cgit v1.2.3 From 949748180cceddded909900f65e9ca75de969779 Mon Sep 17 00:00:00 2001 From: gebele Date: Tue, 20 Jul 2010 09:54:17 +0200 Subject: merge fix in application.rb --- application.rb | 137 --------------------------------------------------------- 1 file changed, 137 deletions(-) diff --git a/application.rb b/application.rb index ec9962d..3156fcd 100644 --- a/application.rb +++ b/application.rb @@ -21,143 +21,6 @@ get '/stylesheets/style.css' do sass :style end -class ToxCreateModel - include DataMapper::Resource - property :id, Serial - property :name, String, :length => 255 - property :uri, String, :length => 255 - property :task_uri, String, :length => 255 - property :validation_task_uri, String, :length => 255 - property :validation_uri, String, :length => 255 - property :validation_report_task_uri, String, :length => 255 - property :validation_report_uri, String, :length => 255 - property :warnings, Text, :length => 2**32-1 - property :nr_compounds, Integer - property :created_at, DateTime - - def status - RestClient.get(File.join(@task_uri, 'hasStatus')).body - end - - def validation_status - begin - RestClient.get(File.join(@validation_task_uri, 'hasStatus')).body - rescue - "Service offline" - end - end - - def validation_report_status - begin - RestClient.get(File.join(@validation_report_task_uri, 'hasStatus')).body - rescue - "Service offline" - end - end - - def algorithm - begin - RestClient.get(File.join(@uri, 'algorithm')).body - rescue - "" - end - end - - def training_dataset - begin - RestClient.get(File.join(@uri, 'trainingDataset')).body - rescue - "" - end - end - - def feature_dataset - begin - RestClient.get(File.join(@uri, 'feature_dataset')).body - rescue - "" - end - end - - def validation - begin - uri = File.join(@validation_uri, 'statistics') - yaml = RestClient.get(uri).body - v = YAML.load(yaml) - tp=0; tn=0; fp=0; fn=0; n=0 - v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell| - if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true" - tp = cell[:confusion_matrix_value] - n += tp - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false" - tn = cell[:confusion_matrix_value] - n += tn - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true" - fn = cell[:confusion_matrix_value] - n += fn - elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false" - fp = cell[:confusion_matrix_value] - n += fp - end - end - { - :n => n, - :tp => tp, - :fp => fp, - :tn => tn, - :fn => fn, - :correct_predictions => sprintf("%.2f", 100*(tp+tn).to_f/n), - :weighted_area_under_roc => sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f), - :sensitivity => sprintf("%.3f", tp.to_f/(tp+fn)), - :specificity => sprintf("%.3f", tn.to_f/(tn+fp)) - } - rescue - "Service offline" - end - end - -end - -DataMapper.auto_upgrade! - -helpers do - def activity(a) - case a.to_s - when "true" - act = "active" - when "false" - act = "inactive" - else - act = "not available" - end - act - end - - def process_model(model) - if !model.uri and model.status == "Completed" - model.uri = RestClient.get(File.join(model.task_uri, 'resultURI')).body - model.save - end - #unless @@config[:services]["opentox-model"].match(/localhost/) - if !model.validation_uri and model.validation_status == "Completed" - begin - model.validation_uri = RestClient.get(File.join(model.validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{model.validation_uri}" - model.validation_report_task_uri = RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => model.validation_uri).body - LOGGER.debug "Validation Report Task URI: #{model.validation_report_task_uri}" - model.save - rescue - end - end - if model.validation_report_task_uri and !model.validation_report_uri and model.validation_report_status == 'Completed' - model.validation_report_uri = RestClient.get(File.join(model.validation_report_task_uri, 'resultURI')).body - end - #end - end -end - -======= ->>>>>>> helma/master get '/?' do redirect url_for('/create') end -- cgit v1.2.3 From ff443a3ee2008e24ce3b02d8fc86ed026585ac38 Mon Sep 17 00:00:00 2001 From: gebele Date: Tue, 20 Jul 2010 10:05:58 +0200 Subject: merge fix application.rb --- application.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/application.rb b/application.rb index 3156fcd..880aeaf 100644 --- a/application.rb +++ b/application.rb @@ -15,12 +15,6 @@ LOGGER.progname = File.expand_path __FILE__ use Rack::Flash set :sessions, true -# SASS stylesheet -get '/stylesheets/style.css' do - headers 'Content-Type' => 'text/css; charset=utf-8' - sass :style -end - get '/?' do redirect url_for('/create') end @@ -216,3 +210,8 @@ delete '/?' do "All Models deleted." end +# SASS stylesheet +get '/stylesheets/style.css' do + headers 'Content-Type' => 'text/css; charset=utf-8' + sass :style +end -- cgit v1.2.3 From 109a6fb7e22e04adec386f6147e2f1fd9438486e Mon Sep 17 00:00:00 2001 From: gebele Date: Tue, 20 Jul 2010 11:30:30 +0200 Subject: favicon added --- public/favicon.ico | Bin 0 -> 1406 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/favicon.ico diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..ba4fae1 Binary files /dev/null and b/public/favicon.ico differ -- cgit v1.2.3 From 617fee94e1824515dc699a6265260c7b92a0fcea Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 22 Jul 2010 17:12:51 +0200 Subject: CONFIG reverted to @@config --- application.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/application.rb b/application.rb index 1d3d652..9501b4c 100644 --- a/application.rb +++ b/application.rb @@ -10,8 +10,6 @@ require File.join(File.dirname(__FILE__),'model.rb') require File.join(File.dirname(__FILE__),'helper.rb') require File.join(File.dirname(__FILE__),'parser.rb') -LOGGER.progname = File.expand_path __FILE__ - use Rack::Flash set :sessions, true -- cgit v1.2.3 From deb9d2c9a005c152983a70c17c227fc59c917f0b Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 29 Jul 2010 19:34:34 +0200 Subject: html representation of lazar predictions moved from model service to toxcreate --- application.rb | 48 +++++++++++++-- views/fragment.haml | 9 +++ views/layout.haml | 8 +-- views/lazar.haml | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++ views/next.haml | 7 +++ views/prediction.haml | 7 ++- views/prev.haml | 8 +++ views/style.sass | 26 ++++++++ 8 files changed, 265 insertions(+), 11 deletions(-) create mode 100644 views/fragment.haml create mode 100644 views/lazar.haml create mode 100644 views/next.haml create mode 100644 views/prev.haml diff --git a/application.rb b/application.rb index 9501b4c..2eca13d 100644 --- a/application.rb +++ b/application.rb @@ -66,7 +66,6 @@ get '/model/:id/:view/?' do end else return "unable to render model: id #{params[:id]}, view #{params[:view]}" - #return "render error" end rescue return "unable to render model: id #{params[:id]}, view #{params[:view]}" @@ -176,8 +175,9 @@ post '/predict/?' do # post chemical name to model confidence = nil title = nil db_activities = [] - LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" + #LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) + #prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) source = prediction.creator if prediction.data[@compound.uri] if source.to_s.match(/model/) # real prediction @@ -185,9 +185,19 @@ post '/predict/?' do # post chemical name to model LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")] LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] if !prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")].nil? - @predictions << {:title => model.name, :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")], :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")]} + @predictions << { + :title => model.name, + :model_uri => model.uri, + :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")], + :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] + } elsif !prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")].nil? - @predictions << {:title => model.name, :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")], :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")]} + @predictions << { + :title => model.name, + :model_uri => model.uri, + :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")], + :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] + } end else # database value prediction = prediction.data[@compound.uri].first.values @@ -202,6 +212,36 @@ post '/predict/?' do # post chemical name to model haml :prediction end +post "/lazar/?" do + @page = 0 + @page = params[:page].to_i if params[:page] + @highlight = params[:highlight] + @model_uri = params[:model_uri] + @prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) + @compound = OpenTox::Compound.new(:uri => params[:compound_uri]) + @title = @prediction.title + if @prediction.data[@compound.uri] + if @prediction.creator.to_s.match(/model/) # real prediction + p = @prediction.data[@compound.uri].first.values.first + if !p[File.join(@@config[:services]["opentox-model"],"lazar#classification")].nil? + feature = File.join(@@config[:services]["opentox-model"],"lazar#classification") + elsif !p[File.join(@@config[:services]["opentox-model"],"lazar#regression")].nil? + feature = File.join(@@config[:services]["opentox-model"],"lazar#regression") + end + @activity = p[feature] + @confidence = p[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] + @neighbors = p[File.join(@@config[:services]["opentox-model"],"lazar#neighbors")]#.sort{|a,b| b.last[:similarity] <=> a.last[:similarity]} + #@training_activities = p[File.join(@@config[:services]["opentox-model"],"lazar#activities")] + @features = p[File.join(@@config[:services]["opentox-model"],"lazar#features")] + else # database value + @measured_activities = @prediction.data[@compound.uri].first.values + end + else + @activity = "not available (no similar compounds in the training dataset)" + end + haml :lazar +end + delete '/?' do ToxCreateModel.auto_migrate! response['Content-Type'] = 'text/plain' diff --git a/views/fragment.haml b/views/fragment.haml new file mode 100644 index 0000000..fa7495d --- /dev/null +++ b/views/fragment.haml @@ -0,0 +1,9 @@ +%form{:name => "form", :action => url_for('/lazar'), :method => "post", :enctype => "multipart/form-data" } + %input{:type => :hidden, :name => :compound_uri, :value => compound_uri} + %input{:type => :hidden, :name => :model_uri, :value => model_uri} + %input{:type => :hidden, :name => :highlight, :value => smarts} + - if smarts.nil? + %input{ :type => "submit", :value => "Reset"} + - else + %input{ :type => "submit", :value => smarts} + diff --git a/views/layout.haml b/views/layout.haml index 7935b33..61d1650 100755 --- a/views/layout.haml +++ b/views/layout.haml @@ -10,11 +10,7 @@ %body .logo= image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate', :align => "right" - -#.headline - .logo - .span1="Tox" - .span2="Create" - + .index %ul %li{:class => ("selected" if /\/create/ =~ request.path )} @@ -27,7 +23,7 @@ = link_to "Help", "/help" .content - - if `hostname`.match(/ot-test|ot-dev/) + - if `hostname`.match(/ot-test/) .notice This service is for testing purposes only - once a week all models will be deleted. Please send bug reports and feature requests to our %a{:href => 'http://github.com/helma/opentox-toxmodel/issues'} issue tracker. diff --git a/views/lazar.haml b/views/lazar.haml new file mode 100644 index 0000000..057b1cd --- /dev/null +++ b/views/lazar.haml @@ -0,0 +1,163 @@ +.lazar-predictions + %table + %tr + %th= @title.gsub(/_lazar_.*$/,' ').capitalize + %th Prediction + %th + %a{:href => "#", :id => "linkConfidence#{p.object_id}"} Confidence + :javascript + $("a#linkConfidence#{p.object_id}").click(function () { + $("dl#confidence").toggle(); + }); + -#%th + Significant fragments + = haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => nil}, :layout => false + -#%th Additional data + + %tr + %td + %img{:src => @compound.display_smarts_uri(@features[:activating].keys,@features[:deactivating].keys, params[:highlight]), :alt => @compound.smiles} + %td + - if @measured_activities + %br + - @measured_activities.each do |a| + - if activity(a) == 'active' + .active + = activity(a) + - elsif activity(a) == 'inactive' + .inactive + = activity(a) + - else + = a + %br + ( + %a{:href => "#", :id => "linkTrainingData#{p.object_id}"} Training data + :javascript + $("a#linkTrainingData#{p.object_id}").click(function () { + $("dl#training_data").toggle(); + }); + ) + + - else + - if activity(@activity) == 'active' + .active + = activity(@activity) + - elsif activity(@activity) == 'inactive' + .inactive + = activity(@activity) + - elsif @activity.is_a?(Float) + .other + = sprintf('%.03g', @activity) + - else + .other + %em= @activity.to_s + %td= sprintf('%.03g', @confidence.to_f.abs) if @confidence + -#%td + %table + - unless @features[:activating].empty? + %tr + %th activating + %th p value + - if @features[:activating] + - @features[:activating].sort{|a,b| b.last <=> a.last }.each do |f| + %tr + - if @highlight == f[0] + %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false + %td.selected= f[1] + - else + %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false + %td= f[1] + - unless @features[:deactivating].empty? + %tr + %th deactivating + %th p value + - if @features[:deactivating] + - @features[:deactivating].sort{|a,b| b.last <=> a.last }.each do |f| + %tr + - if @highlight == f[0] + %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false + %td.selected= f[1] + - else + %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false + %td= f[1] + -#%td + + %tr + %th + Neighbors + = haml :prev, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => @highlight, :page => @page, :size => @neighbors.size}, :layout => false + = "(#{5*@page+1}-#{5*@page+5}/#{@neighbors.size})" + = haml :next, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => @highlight, :page => @page, :size => @neighbors.size}, :layout => false + %th Activity + %th Similarity (activity specific) + -#%th + Significant fragemnts + = haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => nil}, :layout => false + -#%th Additional data + -#%th Exclude + - first = 5*@page + - last = first+4 + - @neighbors.sort{|a,b| b.last[:similarity] <=> a.last[:similarity]}[first..last].each do |uri,data| + - c = OpenTox::Compound.new(:uri => uri) + %tr + %td + -#%br + %a{:href => c.display_smarts_uri(data[:features][:activating].collect{|f| f[:smarts]}, data[:features][:deactivating].collect{|f| f[:smarts]}, params[:highlight])} #{c.smiles} + %br + %img{:src => c.display_smarts_uri(data[:features][:activating].collect{|f| f[:smarts]}, data[:features][:deactivating].collect{|f| f[:smarts]}, params[:highlight]), :alt => c.smiles} + %td + - data[:activities].each do |act| + - if activity(act) == 'active' + .active + = activity(act) + - elsif activity(act) == 'inactive' + .inactive + = activity(act) + - elsif act.is_a?(Float) + .other + = sprintf('%.03g', act) + - else + .other + %em= act.to_s + %td + = sprintf('%.03g', data[:similarity]) + -#%td + %table + - unless data[:features][:activating].empty? + %tr + %th activating + %th p value + - data[:features][:activating].sort{|a,b| b[:p_value] <=> a[:p_value] }.each do |f| + %tr + - if @highlight == f[:smarts] + %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false + %td.selected= f[:p_value] + - else + %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false + %td= f[:p_value] + - unless data[:features][:deactivating].empty? + %tr + %th deactivating + %th p value + - data[:features][:deactivating].sort{|a,b| b[:p_value] <=> a[:p_value] }.each do |f| + %tr + - if @highlight == f[:smarts] + %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false + %td.selected= f[:p_value] + - else + %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false + %td= f[:p_value] + -#%td + -#%td + + +%dl#confidence{ :style => "display: none;" } + %dt Confidence: + %dd 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 distiguish between reliable and unreliable predictions. + + +%dl#training_data{ :style => "display: none;" } + %dt Training data: + %dd Experimental result(s) from the training dataset are displayed here. + + diff --git a/views/next.haml b/views/next.haml new file mode 100644 index 0000000..b7a2b3a --- /dev/null +++ b/views/next.haml @@ -0,0 +1,7 @@ +- unless 5*page.to_i+5 >= size + %form{:name => "form", :action => url_for('/lazar'), :method => "post", :enctype => "multipart/form-data" } + %input{:type => :hidden, :name => :compound_uri, :value => compound_uri} + %input{:type => :hidden, :name => :model_uri, :value => model_uri} + %input{:type => :hidden, :name => :highlight, :value => smarts} + %input{:type => :hidden, :name => :page, :value => page.to_i+1} + %input{ :type => "submit", :value => ">>"} diff --git a/views/prediction.haml b/views/prediction.haml index 1edb2e8..94d7987 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -6,7 +6,7 @@ %th{:colspan => @predictions.size+1} = @identifier %tr - %th + %td %img{:src => @compound.image_uri, :alt => @compound.smiles} - @predictions.each do |p| %td @@ -55,6 +55,11 @@ $("dl#confidence").toggle(); }); ) + %br + %form{:name => "form", :action => url_for('/lazar'), :method => "post", :enctype => "multipart/form-data" } + %input{:type => :hidden, :name => :compound_uri, :value => @compound.uri} + %input{:type => :hidden, :name => :model_uri, :value => p[:model_uri]} + %input{ :type => "submit", :value => "Details"} %dl#confidence{ :style => "display: none;" } %dt Confidence: diff --git a/views/prev.haml b/views/prev.haml new file mode 100644 index 0000000..9a00579 --- /dev/null +++ b/views/prev.haml @@ -0,0 +1,8 @@ +- unless page.to_i == 0 + %form{:name => "form", :action => url_for('/lazar'), :method => "post", :enctype => "multipart/form-data" } + %input{:type => :hidden, :name => :compound_uri, :value => compound_uri} + %input{:type => :hidden, :name => :model_uri, :value => model_uri} + %input{:type => :hidden, :name => :highlight, :value => smarts} + %input{:type => :hidden, :name => :page, :value => page.to_i-1} + %input{ :type => "submit", :value => "<<"} + diff --git a/views/style.sass b/views/style.sass index 1900517..ce579e3 100644 --- a/views/style.sass +++ b/views/style.sass @@ -138,6 +138,32 @@ body img padding: 0 height: 100% + .lazar-predictions + clear: both + margin-top: 2% + table + border-spacing: 0 + border-collapse: collapse + margin: 0 + th + border: 1px solid + color: $body_color + background-color: $fg_color + //border: 1px solid + margin: 0.5em + td + border: 1px solid + background-color: $bg_color2 + padding: 0.5em + table + font-size: x-small + td + border: none + td.selected + background-color: blue + //img + padding: 0 + //height: 100% .model padding: 0em 1em background-color: $bg_color2 -- cgit v1.2.3 From 05ed7ad074f48cf36b60740665c1a0962ff0a55d Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Thu, 29 Jul 2010 19:43:20 +0200 Subject: denis merged --- views/model_status.haml | 0 views/models.haml | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 views/model_status.haml mode change 100755 => 100644 views/models.haml diff --git a/views/model_status.haml b/views/model_status.haml old mode 100755 new mode 100644 diff --git a/views/models.haml b/views/models.haml old mode 100755 new mode 100644 -- cgit v1.2.3 From 4315a4ef2bfc625dc2f3ed69dd6c90ddb0dd5593 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Fri, 6 Aug 2010 13:30:15 +0200 Subject: lazar details implemented --- application.rb | 53 +++++++--- helper.rb | 48 ++++++--- views/compound_image.haml | 2 + views/confidence.haml | 7 ++ views/feature_table.haml | 28 ++++++ views/js_link.haml | 5 + views/layout.haml | 2 +- views/lazar.haml | 206 ++++++++++----------------------------- views/lazar_algorithm.haml | 44 +++++++++ views/neighbors.haml | 45 +++++++++ views/neighbors_navigation.haml | 22 +++++ views/next.haml | 7 -- views/prediction.haml | 36 +------ views/prev.haml | 8 -- views/significant_fragments.haml | 10 ++ views/similarity.haml | 19 ++++ views/style.sass | 86 +++++++++++----- views/training_data.haml | 7 ++ 18 files changed, 379 insertions(+), 256 deletions(-) create mode 100644 views/compound_image.haml create mode 100644 views/confidence.haml create mode 100644 views/feature_table.haml create mode 100644 views/js_link.haml create mode 100644 views/lazar_algorithm.haml create mode 100644 views/neighbors.haml create mode 100644 views/neighbors_navigation.haml delete mode 100644 views/next.haml delete mode 100644 views/prev.haml create mode 100644 views/significant_fragments.haml create mode 100644 views/similarity.haml create mode 100644 views/training_data.haml diff --git a/application.rb b/application.rb index cd4cb54..7bbbafb 100644 --- a/application.rb +++ b/application.rb @@ -28,11 +28,11 @@ delete '/model/:id/?' do begin RestClient.delete model.uri if model.uri RestClient.delete model.task_uri if model.task_uri + model.destroy! + flash[:notice] = "#{model.name} model deleted." rescue flash[:notice] = "#{model.name} model delete error." end - model.destroy! - flash[:notice] = "#{model.name} model deleted." redirect url_for('/models') end @@ -122,14 +122,20 @@ post '/upload' do # create a new model redirect url_for('/create') end - validation_task_uri = OpenTox::Validation.crossvalidation( - :algorithm_uri => OpenTox::Algorithm::Lazar.uri, - :dataset_uri => parser.dataset_uri, - :prediction_feature => feature_uri, - :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" - ).uri - LOGGER.debug "Validation task: " + validation_task_uri - @model.validation_task_uri = validation_task_uri +=begin + begin + validation_task_uri = OpenTox::Validation.crossvalidation( + :algorithm_uri => OpenTox::Algorithm::Lazar.uri, + :dataset_uri => parser.dataset_uri, + :prediction_feature => feature_uri, + :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" + ).uri + LOGGER.debug "Validation task: " + validation_task_uri + @model.validation_task_uri = validation_task_uri + rescue + flash[:notice] = "Model validation failed." + end +=end =begin if parser.nr_compounds < 10 @@ -170,7 +176,6 @@ post '/predict/?' do # post chemical name to model params[:selection].keys.each do |id| model = ToxCreateModel.get(id.to_i) model.process unless model.uri - LOGGER.debug model.to_yaml prediction = nil confidence = nil title = nil @@ -178,12 +183,13 @@ post '/predict/?' do # post chemical name to model #LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) #prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) + LOGGER.debug prediction.to_yaml source = prediction.creator if prediction.data[@compound.uri] if source.to_s.match(/model/) # real prediction prediction = prediction.data[@compound.uri].first.values.first - LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")] - LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] + #LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")] + #LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] if !prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")].nil? @predictions << { :title => model.name, @@ -215,7 +221,7 @@ end post "/lazar/?" do @page = 0 @page = params[:page].to_i if params[:page] - @highlight = params[:highlight] + #@highlight = params[:highlight] @model_uri = params[:model_uri] @prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) @compound = OpenTox::Compound.new(:uri => params[:compound_uri]) @@ -230,8 +236,7 @@ post "/lazar/?" do end @activity = p[feature] @confidence = p[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] - @neighbors = p[File.join(@@config[:services]["opentox-model"],"lazar#neighbors")]#.sort{|a,b| b.last[:similarity] <=> a.last[:similarity]} - #@training_activities = p[File.join(@@config[:services]["opentox-model"],"lazar#activities")] + @neighbors = p[File.join(@@config[:services]["opentox-model"],"lazar#neighbors")] @features = p[File.join(@@config[:services]["opentox-model"],"lazar#features")] else # database value @measured_activities = @prediction.data[@compound.uri].first.values @@ -242,6 +247,22 @@ post "/lazar/?" do haml :lazar end +# proxy to get data from compound service +# (jQuery load does not work with external URIs) +get %r{/compound/(.*)} do |inchi| + OpenTox::Compound.new(:inchi => inchi).names.gsub(/\n/,', ') +end + +=begin +post "/neighbors" do + @neighbors = params[:neighbors] + @page = params[:page].to_i + LOGGER.debug @neighbors + LOGGER.debug @page + haml :neighbors +end +=end + delete '/?' do ToxCreateModel.auto_migrate! response['Content-Type'] = 'text/plain' diff --git a/helper.rb b/helper.rb index 4a5f739..9c4b04c 100644 --- a/helper.rb +++ b/helper.rb @@ -1,14 +1,40 @@ helpers do - def activity(a) - case a.to_s - when "true" - act = "active" - when "false" - act = "inactive" - else - act = "not available" - end - act - 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 compound_image(compound,features) + haml :compound_image, :locals => {:compound => compound, :features => features}, :layout => false + end + + def activity_markup(activity) + case activity.class.to_s + when /Float/ + haml ".other #{sprintf('%.03g', activity)}", :layout => false + 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 + + def neighbors_navigation + @page = 0 unless @page + haml :neighbors_navigation, :layout => false + end + end diff --git a/views/compound_image.haml b/views/compound_image.haml new file mode 100644 index 0000000..c6f962a --- /dev/null +++ b/views/compound_image.haml @@ -0,0 +1,2 @@ +%img{:src => compound.display_smarts_uri(features[:activating].collect{|f| f[:smarts]},@features[:deactivating].collect{|f| f[:smarts]}), :alt => compound.smiles} + diff --git a/views/confidence.haml b/views/confidence.haml new file mode 100644 index 0000000..2b72d63 --- /dev/null +++ b/views/confidence.haml @@ -0,0 +1,7 @@ +%dl#confidence{ :style => "display: none;" } + %dt + Confidence + ( + = hide_link "#confidence" + ) + %dd 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 distiguish between reliable and unreliable predictions. diff --git a/views/feature_table.haml b/views/feature_table.haml new file mode 100644 index 0000000..4fa927c --- /dev/null +++ b/views/feature_table.haml @@ -0,0 +1,28 @@ +%table + - unless features[:activating].empty? + %tr + %th + activating + ( + %a{:href => "http://www.daylight.com/dayhtml/doc/theory/theory.smarts.html"} SMARTS + ) + %th p value + - if features[:activating] + - features[:activating].sort{|a,b| b[:p_value] <=> a[:p_value] }.each do |f| + %tr + %td= f[:smarts] + %td= f[:p_value] + - unless features[:deactivating].empty? + %tr + %th + deactivating + ( + %a{:href => "http://www.daylight.com/dayhtml/doc/theory/theory.smarts.html"} SMARTS + ) + %th p value + - if features[:deactivating] + - features[:deactivating].sort{|a,b| b[:p_value] <=> a[:p_value] }.each do |f| + %tr + %td= f[:smarts] + %td= f[:p_value] + diff --git a/views/js_link.haml b/views/js_link.haml new file mode 100644 index 0000000..7d8cdce --- /dev/null +++ b/views/js_link.haml @@ -0,0 +1,5 @@ +%a{:href => "#{destination}", :id => "js_link#{@link_id}"} #{name} +:javascript + $("a#js_link#{@link_id}").click(function () { + $("#{destination}").#{method}(); + }); diff --git a/views/layout.haml b/views/layout.haml index a301358..6c9202b 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -16,7 +16,7 @@ = link_to "Create", "/create" %li{:class => ("selected" if /models/ =~ request.path )} = link_to "Inspect", "/models" - %li{:class => ("selected" if /predict/ =~ request.path )} + %li{:class => ("selected" if /predict|lazar/ =~ request.path )} = link_to "Predict", "/predict" %li{:class => ("selected" if /help/ =~ request.path )} = link_to "Help", "/help" diff --git a/views/lazar.haml b/views/lazar.haml index 057b1cd..59d5396 100644 --- a/views/lazar.haml +++ b/views/lazar.haml @@ -1,163 +1,55 @@ +%p= link_to "New prediction", "/predict" .lazar-predictions - %table - %tr - %th= @title.gsub(/_lazar_.*$/,' ').capitalize - %th Prediction - %th - %a{:href => "#", :id => "linkConfidence#{p.object_id}"} Confidence - :javascript - $("a#linkConfidence#{p.object_id}").click(function () { - $("dl#confidence").toggle(); - }); - -#%th - Significant fragments - = haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => nil}, :layout => false - -#%th Additional data - %tr - %td - %img{:src => @compound.display_smarts_uri(@features[:activating].keys,@features[:deactivating].keys, params[:highlight]), :alt => @compound.smiles} - %td - - if @measured_activities - %br - - @measured_activities.each do |a| - - if activity(a) == 'active' - .active - = activity(a) - - elsif activity(a) == 'inactive' - .inactive - = activity(a) - - else - = a - %br - ( - %a{:href => "#", :id => "linkTrainingData#{p.object_id}"} Training data - :javascript - $("a#linkTrainingData#{p.object_id}").click(function () { - $("dl#training_data").toggle(); - }); - ) + -# explanations + = haml :lazar_algorithm, :layout => false + = haml :confidence, :layout => false + = haml :similarity, :layout => false + = haml :significant_fragments, :layout => false + = haml :training_data, :layout => false - - else - - if activity(@activity) == 'active' - .active - = activity(@activity) - - elsif activity(@activity) == 'inactive' - .inactive - = activity(@activity) - - elsif @activity.is_a?(Float) - .other - = sprintf('%.03g', @activity) - - else - .other - %em= @activity.to_s - %td= sprintf('%.03g', @confidence.to_f.abs) if @confidence - -#%td - %table - - unless @features[:activating].empty? - %tr - %th activating - %th p value - - if @features[:activating] - - @features[:activating].sort{|a,b| b.last <=> a.last }.each do |f| - %tr - - if @highlight == f[0] - %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false - %td.selected= f[1] - - else - %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false - %td= f[1] - - unless @features[:deactivating].empty? - %tr - %th deactivating - %th p value - - if @features[:deactivating] - - @features[:deactivating].sort{|a,b| b.last <=> a.last }.each do |f| - %tr - - if @highlight == f[0] - %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false - %td.selected= f[1] - - else - %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[0]}, :layout => false - %td= f[1] - -#%td + %a{:name => "prediction"} + %table + %thead + %tr + %th= @title.gsub(/_lazar_.*$/,' ').capitalize + %th= toggle_link("#lazar_algorithm","Prediction") + %th= toggle_link("#confidence","Confidence") + %th Supporting information - %tr - %th - Neighbors - = haml :prev, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => @highlight, :page => @page, :size => @neighbors.size}, :layout => false - = "(#{5*@page+1}-#{5*@page+5}/#{@neighbors.size})" - = haml :next, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => @highlight, :page => @page, :size => @neighbors.size}, :layout => false - %th Activity - %th Similarity (activity specific) - -#%th - Significant fragemnts - = haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => nil}, :layout => false - -#%th Additional data - -#%th Exclude - - first = 5*@page - - last = first+4 - - @neighbors.sort{|a,b| b.last[:similarity] <=> a.last[:similarity]}[first..last].each do |uri,data| - - c = OpenTox::Compound.new(:uri => uri) %tr - %td - -#%br - %a{:href => c.display_smarts_uri(data[:features][:activating].collect{|f| f[:smarts]}, data[:features][:deactivating].collect{|f| f[:smarts]}, params[:highlight])} #{c.smiles} - %br - %img{:src => c.display_smarts_uri(data[:features][:activating].collect{|f| f[:smarts]}, data[:features][:deactivating].collect{|f| f[:smarts]}, params[:highlight]), :alt => c.smiles} - %td - - data[:activities].each do |act| - - if activity(act) == 'active' - .active - = activity(act) - - elsif activity(act) == 'inactive' - .inactive - = activity(act) - - elsif act.is_a?(Float) - .other - = sprintf('%.03g', act) - - else - .other - %em= act.to_s + %td.image= compound_image(@compound,@features) + %td= activity_markup(@activity) + %td= sprintf('%.03g', @confidence.to_f.abs) if @confidence %td - = sprintf('%.03g', data[:similarity]) - -#%td - %table - - unless data[:features][:activating].empty? - %tr - %th activating - %th p value - - data[:features][:activating].sort{|a,b| b[:p_value] <=> a[:p_value] }.each do |f| - %tr - - if @highlight == f[:smarts] - %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false - %td.selected= f[:p_value] - - else - %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false - %td= f[:p_value] - - unless data[:features][:deactivating].empty? - %tr - %th deactivating - %th p value - - data[:features][:deactivating].sort{|a,b| b[:p_value] <=> a[:p_value] }.each do |f| - %tr - - if @highlight == f[:smarts] - %td.selected= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false - %td.selected= f[:p_value] - - else - %td= haml :fragment, :locals => {:compound_uri => @compound.uri, :model_uri => @model_uri, :smarts => f[:smarts]}, :layout => false - %td= f[:p_value] - -#%td - -#%td - - -%dl#confidence{ :style => "display: none;" } - %dt Confidence: - %dd 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 distiguish between reliable and unreliable predictions. - - -%dl#training_data{ :style => "display: none;" } - %dt Training data: - %dd Experimental result(s) from the training dataset are displayed here. - - + %ul + %li + %a{:href => "#prediction", :id => "show_names"} Names and synonyms + :javascript + $("a#show_names").click(function () { + $("#compound_names").load("#{File.join("compound",@compound.inchi)}"); + $("tr#names").toggle(); + }); + %li= toggle_link("#fragments","Significant fragments") + -# This does not work, ask nina/vedrin + -# %li + %a{:href => "http://ambit.uni-plovdiv.bg:8080/ambit2/query/structure/?search=#{@compound.smiles}"} Ambit data + -# %li + %a{:href => "http://www.ncbi.nlm.nih.gov/sites/entrez?cmd=PureSearch&db=pccompound&term=#{URI.encode('"'+@compound.inchi+'"[InChI]')}"} PubChem data + (external) + -# %li + %a{:href => "http://chem.sis.nlm.nih.gov/chemidplus/direct.jsp?result=advanced&inchi=#{URI.encode @compound.inchi}"} ToxNet data + -#http://chem.sis.nlm.nih.gov/chemidplus/direct.jsp?result=advanced®no=000143157 + + %tr#names{ :style => "display: none;" } + %td{:colspan => '4'} + %a{:name => 'names'} + = hide_link('#names') + #compound_names + %tr#fragments{ :style => "display: none;" } + %td{:colspan => '4'} + = hide_link('#fragments') + = haml :feature_table, :locals => {:features => @features}, :layout => false + + %tbody#neighbors + = haml :neighbors, :locals => {:neighbors => @neighbors, :page => @page}, :layout => :false diff --git a/views/lazar_algorithm.haml b/views/lazar_algorithm.haml new file mode 100644 index 0000000..6322b17 --- /dev/null +++ b/views/lazar_algorithm.haml @@ -0,0 +1,44 @@ +%dl#lazar_algorithm + %dt + %code lazar + prediction + ( + = hide_link "#lazar_algorithm" + ) + %dd + %p + %code lazar + searches the training dataset for + = toggle_link "#similarity", "similar" + compounds + %em (neighbors) + and calculates the prediction from their measured activities. + %code lazar + calculates predictions using + %ul + %li + a majority vote (weighted by compound similarity) for + %em classification + %li + a local QSAR model based on neighbors for + %em regression + + %p + = toggle_link "#significant_fragments", "Significant fragments" + are highlighted in the structure display as follows: + %ul + %li + .active activating fragments + %li + .inactive deactivating fragments + %li + .inconclusive regions, where activating and deactivating fragments overlap + %li + .other inert parts + + %p + Please keep in mind that predictions are based on the measured activities of neighbors. + = toggle_link "#significant_fragments", "Significant fragments" + are solely used to determine + = toggle_link "#similarity", "activity specific similarities" + of neighbors. diff --git a/views/neighbors.haml b/views/neighbors.haml new file mode 100644 index 0000000..82fafd2 --- /dev/null +++ b/views/neighbors.haml @@ -0,0 +1,45 @@ +%tr + %th + Neighbors + = neighbors_navigation + %th= toggle_link("#training_data","Measured activity") + %th= toggle_link("#similarity","Similarity") + %th Supporting information + +- first = 5*page +- last = first+4 +- neighbor_id = 0 +- neighbors.sort{|a,b| b.last[:similarity] <=> a.last[:similarity]}[first..last].each do |uri,data| + - neighbor_id += 1 + - compound = OpenTox::Compound.new(:uri => uri) + %tr + %td.image= compound_image(compound,data[:features]) + %td + - data[:activities].each do |act| + = activity_markup(act) + %td= sprintf('%.03g', data[:similarity]) + %td + %ul + %li + %a{:href => "#prediction", :id => "show_names#{neighbor_id}"} Names and synonyms + :javascript + $("a#show_names#{neighbor_id}").click(function () { + $("#compound_names#{neighbor_id}").load("#{File.join("compound",compound.inchi)}"); + $("#names#{neighbor_id}").toggle(); + }); + %li= toggle_link("#fragments#{neighbor_id}","Significant fragments") + -#%li Ambit data + -# %li + %a{:href => "http://www.ncbi.nlm.nih.gov/sites/entrez?cmd=PureSearch&db=pccompound&term=#{URI.encode('"'+compound.inchi+'"[InChI]')}"} PubChem data + (external) + -# %li ToxNet data + + %tr{:id => "names#{neighbor_id}", :style => "display: none;" } + %td{:colspan => '4'} + = hide_link("#names#{neighbor_id}") + %div{:id => "compound_names#{neighbor_id}"} + %tr{:id => "fragments#{neighbor_id}", :style => "display: none;" } + %td{:colspan => '4'} + = hide_link("#fragments#{neighbor_id}") + = haml :feature_table, :locals => {:features => data[:features]}, :layout => false + diff --git a/views/neighbors_navigation.haml b/views/neighbors_navigation.haml new file mode 100644 index 0000000..43ec3ed --- /dev/null +++ b/views/neighbors_navigation.haml @@ -0,0 +1,22 @@ +.neighbors_navigation + + %form{:name => "nav", :action => url_for('/lazar#prediction'), :method => "post", :enctype => "multipart/form-data", :id => "nav"} + %input{:type => :hidden, :name => :compound_uri, :value => @compound.uri} + %input{:type => :hidden, :name => :model_uri, :value => @model_uri} + %input{:type => :hidden, :name => :page, :id => "page"} + + #prev= "prev" unless @page.to_i == 0 + + = "(#{5*@page+1}-#{5*@page+5}/#{@neighbors.size})" + + #next= "next" unless 5*@page.to_i+5 >= @neighbors.size + + :javascript + $("#prev").click(function() { + $("#page").val(#{@page-1}); + $("#nav").submit(); + }); + $("#next").click(function() { + $("#page").val(#{@page+1}); + $("#nav").submit(); + }); diff --git a/views/next.haml b/views/next.haml deleted file mode 100644 index b7a2b3a..0000000 --- a/views/next.haml +++ /dev/null @@ -1,7 +0,0 @@ -- unless 5*page.to_i+5 >= size - %form{:name => "form", :action => url_for('/lazar'), :method => "post", :enctype => "multipart/form-data" } - %input{:type => :hidden, :name => :compound_uri, :value => compound_uri} - %input{:type => :hidden, :name => :model_uri, :value => model_uri} - %input{:type => :hidden, :name => :highlight, :value => smarts} - %input{:type => :hidden, :name => :page, :value => page.to_i+1} - %input{ :type => "submit", :value => ">>"} diff --git a/views/prediction.haml b/views/prediction.haml index 94d7987..dd7d155 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -15,17 +15,10 @@ - if p[:measured_activities] %br - p[:measured_activities].each do |a| - - if activity(a) == 'active' - .active - = activity(a) - - elsif activity(a) == 'inactive' - .inactive - = activity(a) - - else - = a + = activity_markup(a) %br ( - %a{:href => "#", :id => "linkTrainingData#{p.object_id}"} Training data + %a{:href => "#", :id => "linkTrainingData#{p.object_id}"} Measured activity :javascript $("a#linkTrainingData#{p.object_id}").click(function () { $("dl#training_data").toggle(); @@ -33,18 +26,7 @@ ) - else - - if activity(p[:prediction]) == 'active' - .active - = activity(p[:prediction]) - - elsif activity(p[:prediction]) == 'inactive' - .inactive - = activity(p[:prediction]) - - elsif p[:prediction].is_a?(Float) - .other - = sprintf('%.03g', p[:prediction]) - - else - .other - %em= p[:prediction].to_s + = activity_markup(p[:prediction]) - if p[:confidence] %br ( @@ -61,13 +43,5 @@ %input{:type => :hidden, :name => :model_uri, :value => p[:model_uri]} %input{ :type => "submit", :value => "Details"} -%dl#confidence{ :style => "display: none;" } - %dt Confidence: - %dd 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 distiguish between reliable and unreliable predictions. - - -%dl#training_data{ :style => "display: none;" } - %dt Training data: - %dd Experimental result(s) from the training dataset are displayed here. - - += haml :confidence, :layout => false += haml :training_data, :layout => false diff --git a/views/prev.haml b/views/prev.haml deleted file mode 100644 index 9a00579..0000000 --- a/views/prev.haml +++ /dev/null @@ -1,8 +0,0 @@ -- unless page.to_i == 0 - %form{:name => "form", :action => url_for('/lazar'), :method => "post", :enctype => "multipart/form-data" } - %input{:type => :hidden, :name => :compound_uri, :value => compound_uri} - %input{:type => :hidden, :name => :model_uri, :value => model_uri} - %input{:type => :hidden, :name => :highlight, :value => smarts} - %input{:type => :hidden, :name => :page, :value => page.to_i-1} - %input{ :type => "submit", :value => "<<"} - diff --git a/views/significant_fragments.haml b/views/significant_fragments.haml new file mode 100644 index 0000000..87cb113 --- /dev/null +++ b/views/significant_fragments.haml @@ -0,0 +1,10 @@ +%dl#significant_fragments{ :style => "display: none;" } + %dt + Significant fragments + ( + = hide_link "#significant_fragments" + ) + %dd + Substructures that occur (statistically significant) more frequently in active or inactive compounds. Substuctures can take any shape (without cycles) and are determined with the + %a{:href => "http://www.maunz.de/libfminer2-bbrc-doc/"} fminer + algorithm. diff --git a/views/similarity.haml b/views/similarity.haml new file mode 100644 index 0000000..659eb50 --- /dev/null +++ b/views/similarity.haml @@ -0,0 +1,19 @@ +%dl#similarity{ :style => "display: none;" } + %dt + Similarity + ( + = hide_link "#similarity" + ) + %dd + %code lazar + calculates + %em activity specific + similarities based on the presence of statistically + = toggle_link "#significant_fragments", "significant fragments" + This procedure will + %ul + %li consider only those parts of a chemical structure that are relevant for a particular endpoint + %li ignore inert parts of the structure + %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. + diff --git a/views/style.sass b/views/style.sass index b64b919..4977da1 100644 --- a/views/style.sass +++ b/views/style.sass @@ -18,6 +18,7 @@ body color: $ot_purple a:hover color: black + .headline .logo float: right @@ -55,6 +56,7 @@ body color: $bg_color a color: $text_color + .content background-color: $bg_color height: 100% @@ -102,6 +104,7 @@ body td padding: 0.5em border: 1px solid + .predictions text-align: center overflow: auto @@ -121,57 +124,87 @@ body img padding: 0 height: 100% + .lazar-predictions clear: both margin-top: 2% + .neighbors_navigation + font-size: x-small + #prev + @extend a + display: inline + #next + @extend a + display: inline + + dt + font-weight: bold table + width: 100% + //height: 100% + background-color: $bg_color2 border-spacing: 0 border-collapse: collapse margin: 0 + tbody + height: 10em + overflow: scroll th + text-align: center border: 1px solid color: $body_color background-color: $fg_color - //border: 1px solid margin: 0.5em + a + text-decoration: underline + font-weight: bold + color: $bg_color + + a:hover + color: $bg_color2 td border: 1px solid - background-color: $bg_color2 - padding: 0.5em + overflow: auto + ul + list-style-type: none + td.image + padding: 0 + width: 150px + height: 150px + table font-size: x-small td border: none td.selected background-color: blue - //img - padding: 0 - //height: 100% + //overflow-y: scroll; + .model padding: 0em 1em background-color: $bg_color2 border: 1px solid margin-top: 0.6em - dl - dt - width: 15em - font-weight: bold - float: left - clear: both - dd - clear: right - margin: 0.2em 0em - dl + dl + dt + width: 15em + font-weight: bold + float: left clear: both - padding: 0em - background-color: $bg_color2 - border: 0 - dt - white-space: nowrap - width: 16em - font-weight: bold - float: left - clear: right + dd + clear: right + margin: 0.2em 0em + dl + clear: both + padding: 0em + background-color: $bg_color2 + border: 0 + dt + white-space: nowrap + width: 16em + font-weight: bold + float: left + clear: right .footer margin: 0.5em @@ -183,6 +216,9 @@ body .inactive color: green +.inconclusive + color: yellow + .other color: black diff --git a/views/training_data.haml b/views/training_data.haml new file mode 100644 index 0000000..0593776 --- /dev/null +++ b/views/training_data.haml @@ -0,0 +1,7 @@ +%dl#training_data{ :style => "display: none;" } + %dt + Measured activity + ( + = hide_link "#training_data" + ) + %dd Experimental result(s) from the training dataset. -- cgit v1.2.3 From ce1e875e9ae85e6e0051bfd9b1b7393cf4a4bc8a Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 9 Aug 2010 10:01:32 +0200 Subject: some obsolete parts removed --- application.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/application.rb b/application.rb index 7bbbafb..5cd934f 100644 --- a/application.rb +++ b/application.rb @@ -122,7 +122,6 @@ post '/upload' do # create a new model redirect url_for('/create') end -=begin begin validation_task_uri = OpenTox::Validation.crossvalidation( :algorithm_uri => OpenTox::Algorithm::Lazar.uri, @@ -135,7 +134,6 @@ post '/upload' do # create a new model rescue flash[:notice] = "Model validation failed." end -=end =begin if parser.nr_compounds < 10 @@ -253,16 +251,6 @@ get %r{/compound/(.*)} do |inchi| OpenTox::Compound.new(:inchi => inchi).names.gsub(/\n/,', ') end -=begin -post "/neighbors" do - @neighbors = params[:neighbors] - @page = params[:page].to_i - LOGGER.debug @neighbors - LOGGER.debug @page - haml :neighbors -end -=end - delete '/?' do ToxCreateModel.auto_migrate! response['Content-Type'] = 'text/plain' -- cgit v1.2.3 From 2f92a51f65bc72926eb6a885e076f3e2a8178a6d Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 9 Aug 2010 10:03:11 +0200 Subject: opentox-api-wrapper bumped to 1.6.1 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 5cd934f..d74fbbe 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.6.0" +gem "opentox-ruby-api-wrapper", "= 1.6.1" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 9b60e3f7dd0c7c5bb07e420743014db0af95d47f Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 9 Aug 2010 17:47:05 +0200 Subject: logging removed --- application.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/application.rb b/application.rb index d74fbbe..4de2da5 100644 --- a/application.rb +++ b/application.rb @@ -181,7 +181,6 @@ post '/predict/?' do # post chemical name to model #LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) #prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) - LOGGER.debug prediction.to_yaml source = prediction.creator if prediction.data[@compound.uri] if source.to_s.match(/model/) # real prediction -- cgit v1.2.3 From 3469bfb52686ca69193df5a3321f8d25ba601186 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 9 Aug 2010 17:47:58 +0200 Subject: opentox-api-wrapper bumped to 1.6.2 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 4de2da5..f1c4232 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.6.1" +gem "opentox-ruby-api-wrapper", "= 1.6.2" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 2180bd0303d98ae003341264a44e785d45208873 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 18 Aug 2010 19:20:28 +0200 Subject: display of empty predictions fixed --- helper.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/helper.rb b/helper.rb index 9c4b04c..d100c9e 100644 --- a/helper.rb +++ b/helper.rb @@ -20,6 +20,8 @@ helpers do case activity.class.to_s when /Float/ haml ".other #{sprintf('%.03g', activity)}", :layout => false + when /String/ + haml ".other #{activity.to_s}", :layout => false else if activity #true haml ".active active", :layout => false -- cgit v1.2.3 From 942c7fba011c5f7c3224fe16a4d7ac32b29e4146 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 18 Aug 2010 19:48:37 +0200 Subject: display of empty predictions fixed --- application.rb | 5 ++--- views/prediction.haml | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/application.rb b/application.rb index f1c4232..3c7645d 100644 --- a/application.rb +++ b/application.rb @@ -207,7 +207,7 @@ post '/predict/?' do # post chemical name to model @predictions << {:title => model.name, :measured_activities => prediction} end else - @predictions << {:title => model.name, :prediction => "not available (no similar compounds in the training dataset)"} + @predictions << {:title => model.name, :prediction => "not available (not enough similar compounds in the training dataset)"} end end LOGGER.debug @predictions.inspect @@ -215,10 +215,9 @@ post '/predict/?' do # post chemical name to model haml :prediction end -post "/lazar/?" do +post "/lazar/?" do # get detailed prediction @page = 0 @page = params[:page].to_i if params[:page] - #@highlight = params[:highlight] @model_uri = params[:model_uri] @prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) @compound = OpenTox::Compound.new(:uri => params[:compound_uri]) diff --git a/views/prediction.haml b/views/prediction.haml index dd7d155..0140b5e 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -25,6 +25,8 @@ }); ) + - elsif p[:prediction].to_s.match(/not available/) + = p[:prediction] - else = activity_markup(p[:prediction]) - if p[:confidence] -- cgit v1.2.3 From 6b422d9c03a0f72785d4f7bde9bd384835e5ce5a Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 18 Aug 2010 19:52:09 +0200 Subject: opentox-api-wrapper bumped to 1.6.3 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 3c7645d..9f511e7 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.6.2" +gem "opentox-ruby-api-wrapper", "= 1.6.3" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From ab9a669b922b3a7c72a60e96e2bbf65c062b05ab Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 25 Aug 2010 12:28:39 +0200 Subject: initial version for quantitative features, some improvements suggested by david --- application.rb | 21 +-- model.rb | 81 ++++++++-- parser.rb | 2 +- public/javascripts/toxcreate.js | 2 +- views/classification.haml | 11 ++ views/classification_validation.haml | 87 ++++------- views/create.haml | 20 ++- views/endpoint.haml | 12 ++ views/help.haml | 5 +- views/layout.haml | 4 +- views/lazar_algorithm.haml | 6 + views/lazar_description.haml | 29 ++++ views/model.haml | 14 +- views/models.haml | 6 + views/regression.haml | 11 ++ views/regression_validation.haml | 36 ++--- views/style.sass | 13 +- views/unit.haml | 10 ++ views/validation.haml | 289 ++++------------------------------- 19 files changed, 270 insertions(+), 389 deletions(-) create mode 100644 views/classification.haml create mode 100644 views/endpoint.haml create mode 100644 views/lazar_description.haml create mode 100644 views/regression.haml create mode 100644 views/unit.haml diff --git a/application.rb b/application.rb index 9f511e7..0bca96f 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.6.3" +gem "opentox-ruby-api-wrapper", "= 1.6.4" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' @@ -49,21 +49,22 @@ end get '/model/:id/:view/?' do response['Content-Type'] = 'text/plain' model = ToxCreateModel.get(params[:id]) - model.process - model.save begin + model.process + model.save case params[:view] when "model" haml :model, :locals=>{:model=>model}, :layout => false when /validation/ - if model.type == "classification" - haml :classification_validation, :locals=>{:model=>model}, :layout => false - elsif model.type == "regression" - haml :regression_validation, :locals=>{:model=>model}, :layout => false - else - return "Unknown model type '#{model.type}'" - end + haml :validation, :locals=>{:model=>model}, :layout => false + #if model.type == "classification" + #haml :classification_validation, :locals=>{:model=>model}, :layout => false + #elsif model.type == "regression" + #haml :regression_validation, :locals=>{:model=>model}, :layout => false + #else + #return "Unknown model type '#{model.type}'" + #end else return "unable to render model: id #{params[:id]}, view #{params[:view]}" end diff --git a/model.rb b/model.rb index d10b95f..99d6ab3 100644 --- a/model.rb +++ b/model.rb @@ -11,6 +11,18 @@ class ToxCreateModel property :validation_report_uri, String, :length => 255 property :warnings, Text, :length => 2**32-1 property :nr_compounds, Integer + property :nr_predictions, Integer + property :true_positives, Integer + property :false_positives, Integer + property :true_negatives, Integer + property :false_negatives, Integer + property :correct_predictions, Integer + property :weighted_area_under_roc, Float + property :sensitivity, Float + property :specificity, Float + property :r_square, Float + property :root_mean_squared_error, Float + property :mean_absolute_error, Float property :type, String property :created_at, DateTime @@ -62,6 +74,7 @@ class ToxCreateModel end end +=begin def classification_validation begin uri = File.join(@validation_uri, 'statistics') @@ -83,17 +96,21 @@ class ToxCreateModel n += fp end end - { - :n => n, - :tp => tp, - :fp => fp, - :tn => tn, - :fn => fn, - :correct_predictions => sprintf("%.2f", 100*(tp+tn).to_f/n), - :weighted_area_under_roc => sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f), - :sensitivity => sprintf("%.3f", tp.to_f/(tp+fn)), - :specificity => sprintf("%.3f", tn.to_f/(tn+fp)) - } + @nr_predictions = n + @true_positives = tp + @false_positives = fp + @true_negatives = tn + @false_negatives = fn + @correct_predictions = 100*(tp+tn).to_f/n + @weighted_area_under_roc = v[:classification_statistics][:weighted_area_under_roc].to_f + @sensitivity = tp.to_f/(tp+fn) + @specificity = tn.to_f/(tn+fp) + save + #:correct_predictions => sprintf("%.2f", 100*(tp+tn).to_f/n), + #:weighted_area_under_roc => sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f), + #:sensitivity => sprintf("%.3f", tp.to_f/(tp+fn)), + #:specificity => sprintf("%.3f", tn.to_f/(tn+fp)) + #} rescue "Service offline" end @@ -104,10 +121,16 @@ class ToxCreateModel uri = File.join(@validation_uri, 'statistics') yaml = RestClient.get(uri).body v = YAML.load(yaml) + @nr_predictions = v[:num_instances] - v[:num_unpredicted] + @r_square = v[:regression_statistics][:r_square] + @root_mean_squared_error = v[:regression_statistics][:root_mean_squared_error] + @mean_absolute_error = v[:regression_statistics][:mean_absolute_error] + save rescue "Service offline" end end +=end def process @@ -129,6 +152,42 @@ class ToxCreateModel LOGGER.debug "Validation URI: #{@validation_uri}" update :validation_report_task_uri => RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @validation_uri).body LOGGER.debug "Validation Report Task URI: #{@validation_report_task_uri}" + uri = File.join(@validation_uri, 'statistics') + yaml = RestClient.get(uri).body + v = YAML.load(yaml) + case type + when "classification" + tp=0; tn=0; fp=0; fn=0; n=0 + v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell| + if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true" + tp = cell[:confusion_matrix_value] + n += tp + elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false" + tn = cell[:confusion_matrix_value] + n += tn + elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true" + fn = cell[:confusion_matrix_value] + n += fn + elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false" + fp = cell[:confusion_matrix_value] + n += fp + end + end + update :nr_predictions => n + update :true_positives => tp + update :false_positives => fp + update :true_negatives => tn + update :false_negatives => fn + update :correct_predictions => 100*(tp+tn).to_f/n + update :weighted_area_under_roc => v[:classification_statistics][:weighted_area_under_roc].to_f + update :sensitivity => tp.to_f/(tp+fn) + update :specificity => tn.to_f/(tn+fp) + when "regression" + update :nr_predictions => v[:num_instances] - v[:num_unpredicted] + update :r_square => v[:regression_statistics][:r_square] + update :root_mean_squared_error => v[:regression_statistics][:root_mean_squared_error] + update :mean_absolute_error => v[:regression_statistics][:mean_absolute_error] + end rescue LOGGER.warn "Cannot create Validation Report Task #{@validation_report_task_uri} for Validation URI #{@validation_uri} from Task #{@validation_task_uri}" end diff --git a/parser.rb b/parser.rb index 8754531..8468cea 100644 --- a/parser.rb +++ b/parser.rb @@ -93,7 +93,7 @@ class Parser def validate(smiles, act, row) compound = OpenTox::Compound.new(:smiles => smiles) - if compound.inchi == "" + if compound.nil? or compound.inchi.nil? or compound.inchi == "" @smiles_errors << "Row #{row}: " + [smiles,act].join(", ") return false end diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index 048bd46..d1ed490 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -80,7 +80,7 @@ $(function() { checkValidation = function() { var reload_id = ""; $("input.model_validation_report").each(function(){ - if($(this).val() != "Completed") { + if(!$(this).val().match(/Completed|Error/)) { reload_id = this.id.replace("model_validation_report_",""); if(/^\d+$/.test(reload_id)) loadModel(reload_id, 'validation'); }; diff --git a/views/classification.haml b/views/classification.haml new file mode 100644 index 0000000..5c739cf --- /dev/null +++ b/views/classification.haml @@ -0,0 +1,11 @@ +%dl#classification{ :style => "display: none;" } + %dt + Classification + ( + = hide_link "#classification" + ) + %dd + Prediction of + %em qualitative + properties, e.g. to distinguish between toxic and non-toxic compounds + diff --git a/views/classification_validation.haml b/views/classification_validation.haml index 26f0617..4a2d689 100644 --- a/views/classification_validation.haml +++ b/views/classification_validation.haml @@ -1,54 +1,33 @@ -%dl{:id => "model_validation_#{model.id}"} - %dt - Validation: - %input{ :id => "model_validation_report_#{model.id}", :type => "hidden", :value => "#{model.validation_report_status}", :class => "model_validation_report" } - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) - %dd - - if model.validation_uri - - v = model.classification_validation - - if v == "Service offline" - = v - - else - %dl - %dt Number of predictions: - %dd= v[:n] - %dt Correct predictions: - %dd - = v[:correct_predictions] - = '%' - %dt - %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: - %dd - = v[:weighted_area_under_roc] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: - %dd= v[:specificity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: - %dd= v[:sensitivity] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: - %dd - %table - %tr - %td{:colspan => 2, :rowspan => 2} - -#%td - %th{:colspan => 2} Measured - %tr - -#%td{:colspan => 2} - -#%th Predicted - %th{:bgcolor => "#CCD2DC"} active - %th{:bgcolor => "#CCD2DC"} inactive - %tr - %th{:rowspan => 2} Predicted - %th{:bgcolor => "#CCD2DC"} active - %td= v[:tp] - %td= v[:fp] - %tr - %th{:bgcolor => "#CCD2DC"} inactive - %td= v[:fn] - %td= v[:tn] - - else - = image_tag("/snake_transparent.gif") if model.validation_status == "Running" - %a{:href => model.validation_task_uri} #{model.validation_status} +%dt Correct predictions: +%dd + = sprintf("%.2f", model.correct_predictions) + = '%' +%dt + %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: +%dd + = sprintf("%.3f", model.weighted_area_under_roc) +%dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: +%dd= sprintf("%.3f", model.specificity) +%dt + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: +%dd= sprintf("%.3f", model.sensitivity) +%dt + %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: +%dd + %table + %tr + %td{:colspan => 2, :rowspan => 2} + %th{:colspan => 2} Measured + %tr + %th{:bgcolor => "#CCD2DC"} active + %th{:bgcolor => "#CCD2DC"} inactive + %tr + %th{:rowspan => 2} Predicted + %th{:bgcolor => "#CCD2DC"} active + %td= model.true_positives + %td= model.false_positives + %tr + %th{:bgcolor => "#CCD2DC"} inactive + %td= model.false_negatives + %td= model.true_negatives diff --git a/views/create.haml b/views/create.haml index 3cf05c1..20de401 100644 --- a/views/create.haml +++ b/views/create.haml @@ -4,13 +4,13 @@ This service creates %ul %li - %a{:href => 'http://lazar.in-silico.de'} lazar - %em classification - models (i.e. models that discriminate between toxic/nontoxic compounds) and + = toggle_link("#lazar_description","lazar") + %em= toggle_link("#classification","classification") + models and %li - %a{:href => 'http://lazar.in-silico.de'} lazar - %em regression - models (i.e. models that predict quantitative values, e.g. LC50's) + = toggle_link("#lazar_description","lazar") + %em= toggle_link("#regression","regression") + models from your uploaded datasets. Further modelling algorithms will be added in future versions. %p @@ -20,7 +20,7 @@ %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } %fieldset - %label{:for => 'endpoint'} 1. Enter endpoint name and unit (for regression): + %label{:for => 'endpoint'} 1. Enter #{toggle_link("#endpoint_description","endpoint")} name and #{toggle_link("#unit","unit")} (for #{toggle_link("#regression","regression")}): %input{:type => 'text', :name => 'endpoint', :id => 'endpoint', :size => '50'} %br %label{:for => 'file'} @@ -33,3 +33,9 @@ %input{ :type => "submit", :value => "Create model"} = link_to "Cancel", '/create' + -# explanations + = haml :lazar_description, :layout => false + = haml :classification, :layout => false + = haml :regression, :layout => false + = haml :endpoint, :layout => false + = haml :unit, :layout => false diff --git a/views/endpoint.haml b/views/endpoint.haml new file mode 100644 index 0000000..af06b80 --- /dev/null +++ b/views/endpoint.haml @@ -0,0 +1,12 @@ +%dl#endpoint_description{ :style => "display: none;" } + %dt + Endpoint + ( + = hide_link "#endpoint_description" + ) + %dd + Toxic effect that constitutes the outcome of an + %em in-vitro, + or + %em in-vivo + expriment, clinical trial or epidemiological study diff --git a/views/help.haml b/views/help.haml index 52339ce..eabf978 100644 --- a/views/help.haml +++ b/views/help.haml @@ -10,7 +10,10 @@ %dd Enter a quantitative value. For optimal performance you should %ul - %li use molar units + %li + use + %a{:href => "http://en.wikipedia.org/wiki/Molar_(concentration)"} molar + units %li enter non-logarithmic values (logarithms are taken internally) %li avoid 0 activities (will be ignored) %p diff --git a/views/layout.haml b/views/layout.haml index 6c9202b..a3db5e9 100644 --- a/views/layout.haml +++ b/views/layout.haml @@ -9,7 +9,9 @@ %link{:rel=>'stylesheet', :href=>'stylesheets/style.css', :type => "text/css"} %body - .logo= image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate', :align => "right" + .logo + = image_tag "/ToxCreate_rgb_72.png", :alt => 'ToxCreate', :align => 'right' + %br Create and evaluate models to predict toxicity .index %ul %li{:class => ("selected" if /\/create/ =~ request.path )} diff --git a/views/lazar_algorithm.haml b/views/lazar_algorithm.haml index 6322b17..b83de6b 100644 --- a/views/lazar_algorithm.haml +++ b/views/lazar_algorithm.haml @@ -19,9 +19,15 @@ %li a majority vote (weighted by compound similarity) for %em classification + ( + %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} original publication + ) %li a local QSAR model based on neighbors for %em regression + ( + %a{:href => "http://www.in-silico.de/articles/mh_tf.pdf"} original publication + ) %p = toggle_link "#significant_fragments", "Significant fragments" diff --git a/views/lazar_description.haml b/views/lazar_description.haml new file mode 100644 index 0000000..d870425 --- /dev/null +++ b/views/lazar_description.haml @@ -0,0 +1,29 @@ +%dl#lazar_description{ :style => "display: none;" } + %dt + %code lazar + ( + = hide_link "#lazar_description" + ) + %dd + %p + %code lazar + searches the training dataset for + = toggle_link "#similarity", "similar" + compounds + %em (neighbors) + and calculates the prediction from their measured activities. + %code lazar + calculates predictions using + %ul + %li + a majority vote (weighted by compound similarity) for + %em= toggle_link("#classification","classification") + ( + %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} original publication + ) + %li + a local QSAR model based on neighbors for + %em= toggle_link("#regression","regression") + ( + %a{:href => "http://www.in-silico.de/articles/mh_tf.pdf"} original publication + ) diff --git a/views/model.haml b/views/model.haml index 234dcc6..454423a 100644 --- a/views/model.haml +++ b/views/model.haml @@ -8,6 +8,7 @@ %div{:id => "model_#{model.id}"} %h2 = model.name + .model %dl %dt Status: @@ -31,9 +32,9 @@ - if model.status == 'Completed' %dt Algorithm: %dd - %a{:href => "http://www.in-silico.de/articles/modi020905.pdf"} #{File.basename model.algorithm} + = toggle_link("#lazar_description","lazar") %dt Type: - %dd= model.type + %dd= toggle_link("##{model.type}","#{model.type}") %dt Descriptors: %dd %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes @@ -56,10 +57,5 @@ %a{:href => "#{model.uri}.rdf"} RDF/XML , %a{:href => "#{model.uri}.yaml"} YAML - %em (experts, models cannot be exported in Excel) - - case model.type - - when "classification" - = haml :classification_validation, :locals=>{:model=>model}, :layout => false - -when "regression" - = haml :regression_validation, :locals=>{:model=>model}, :layout => false - + %em (experts, models cannot be represented in Excel) + = haml :validation, :locals=>{:model=>model}, :layout => false diff --git a/views/models.haml b/views/models.haml index 806a935..6712e3d 100644 --- a/views/models.haml +++ b/views/models.haml @@ -10,5 +10,11 @@ }); %p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. + +-# explanations += haml :lazar_description, :layout => false += haml :classification, :layout => false += haml :regression, :layout => false + - @models.each do |model| = haml :model, :locals=>{:model=>model}, :layout => false diff --git a/views/regression.haml b/views/regression.haml new file mode 100644 index 0000000..4866b08 --- /dev/null +++ b/views/regression.haml @@ -0,0 +1,11 @@ +%dl#regression{ :style => "display: none;" } + %dt + Regression + ( + = hide_link "#regression" + ) + %dd + Prediction of + %em quantitative + properties, e.g. LC50 values + diff --git a/views/regression_validation.haml b/views/regression_validation.haml index ac45307..00267a9 100644 --- a/views/regression_validation.haml +++ b/views/regression_validation.haml @@ -1,27 +1,9 @@ -%dl{:id => "model_validation_#{model.id}"} - %dt - Validation: - %input{ :id => "model_validation_report_#{model.id}", :type => "hidden", :value => "#{model.validation_report_status}", :class => "model_validation_report" } - - if model.validation_report_uri - %a{:href => model.validation_report_uri, :target => "_blank"} (more details) - %dd - - if model.validation_uri - - v = model.regression_validation - - if v == "Service offline" - = v - - else - %dl - %dt Number of predictions - %dd= v[:num_instances] - v[:num_unpredicted] - %dt - %a{:href => "http://en.wikipedia.org/wiki/R-squared"} R-squared - %dd= sprintf '%.03g', v[:regression_statistics][:r_square] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Root_mean_square_deviation"} Root Mean Square Error - %dd= sprintf '%.03g', v[:regression_statistics][:root_mean_squared_error] - %dt - %a{:href => "http://en.wikipedia.org/wiki/Mean_absolute_error"} Mean Absolute Error - %dd= sprintf '%.03g', v[:regression_statistics][:mean_absolute_error] - - else - = image_tag("/snake_transparent.gif") if model.validation_status == "Running" - %a{:href => model.validation_task_uri} #{model.validation_status} +%dt + %a{:href => "http://en.wikipedia.org/wiki/R-squared"} R-squared +%dd= sprintf '%.03g', model.r_square +%dt + %a{:href => "http://en.wikipedia.org/wiki/Root_mean_square_deviation"} Root Mean Square Error +%dd= sprintf '%.03g', model.root_mean_squared_error +%dt + %a{:href => "http://en.wikipedia.org/wiki/Mean_absolute_error"} Mean Absolute Error +%dd= sprintf '%.03g', model.mean_absolute_error diff --git a/views/style.sass b/views/style.sass index 4977da1..44917cc 100644 --- a/views/style.sass +++ b/views/style.sass @@ -19,9 +19,14 @@ body a:hover color: black - .headline - .logo - float: right + .logo + float: right + br + clear: both + //border-right: 90px + img + margin: 0 + padding: 0 .index clear: both @@ -85,7 +90,7 @@ body font-weight: bold color: $fg_color label - width: 25em + width: 30em display: block float: left br diff --git a/views/unit.haml b/views/unit.haml new file mode 100644 index 0000000..a352599 --- /dev/null +++ b/views/unit.haml @@ -0,0 +1,10 @@ +%dl#unit{ :style => "display: none;" } + %dt + Unit + ( + = hide_link "#unit" + ) + %dd + Unit of measurement, e.g. mmol or mmol/kg-bodyweight. For optimal performance you should use + %a{:href => "http://en.wikipedia.org/wiki/Molar_(concentration)"} molar + units. diff --git a/views/validation.haml b/views/validation.haml index d1af379..90150d1 100644 --- a/views/validation.haml +++ b/views/validation.haml @@ -1,264 +1,27 @@ -= "-> " -%a{ :href => "/validation/#{params[:id]}" } Validation +%dl{:id => "model_validation_#{model.id}"} + %dt + Validation: + %input{ :id => "model_validation_report_#{model.id}", :type => "hidden", :value => "#{model.validation_report_status}", :class => "model_validation_report" } + %dd + - if model.validation_uri + %dl + %dt + Detailed report: + %dd + - if model.validation_report_uri + %a{:href => model.validation_report_uri, :target => "_blank"} show + - else + = image_tag("/snake_transparent.gif") if model.validation_report_status == "Running" + %a{:href => model.validation_report_task_uri} #{model.validation_report_status} + %dt Number of predictions + %dd= model.nr_predictions + - case model.type + - when "classification" + = haml :classification_validation, :locals=>{:model=>model}, :layout => false + - when "regression" + = haml :regression_validation, :locals=>{:model=>model}, :layout => false + - else + = image_tag("/snake_transparent.gif") if model.validation_status == "Running" + %a{:href => model.validation_task_uri} #{model.validation_status} + -%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 -- cgit v1.2.3 From f55fe2217b845f70fcd1679a9cb84e905cf07bcb Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 25 Aug 2010 12:56:05 +0200 Subject: opentox-api-wrapper bumped to 1.6.5 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 0bca96f..9616841 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.6.4" +gem "opentox-ruby-api-wrapper", "= 1.6.5" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 2e5b069fa486859a654d8bd9e6b948e8922d84f1 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 25 Aug 2010 14:49:33 +0200 Subject: opentox-api-wrapper bumped to 1.6.6 --- application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application.rb b/application.rb index 9616841..da7e4eb 100644 --- a/application.rb +++ b/application.rb @@ -1,7 +1,7 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| require lib end -gem "opentox-ruby-api-wrapper", "= 1.6.5" +gem "opentox-ruby-api-wrapper", "= 1.6.6" require 'opentox-ruby-api-wrapper' gem 'sinatra-static-assets' require 'sinatra/static_assets' -- cgit v1.2.3 From 3afef01f3f757d9c58c24bf490edf695ad29c176 Mon Sep 17 00:00:00 2001 From: ch Date: Tue, 31 Aug 2010 17:13:57 +0200 Subject: css for neighbors table fixed --- views/style.sass | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/views/style.sass b/views/style.sass index 44917cc..ea9e65a 100644 --- a/views/style.sass +++ b/views/style.sass @@ -19,14 +19,9 @@ body a:hover color: black - .logo - float: right - br - clear: both - //border-right: 90px - img - margin: 0 - padding: 0 + .headline + .logo + float: right .index clear: both @@ -90,7 +85,7 @@ body font-weight: bold color: $fg_color label - width: 30em + width: 25em display: block float: left br @@ -138,9 +133,11 @@ body #prev @extend a display: inline + cursor: pointer #next @extend a display: inline + cursor: pointer dt font-weight: bold @@ -152,8 +149,7 @@ body border-collapse: collapse margin: 0 tbody - height: 10em - overflow: scroll + //height: 10em th text-align: center border: 1px solid -- cgit v1.2.3 From 5c5d66c2a9487687ba9032da04031ad59ab1de46 Mon Sep 17 00:00:00 2001 From: ch Date: Tue, 7 Sep 2010 12:06:35 +0200 Subject: display of failed validation results fixed --- views/classification_validation.haml | 50 ++++++++++++++++++------------------ views/validation.haml | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/views/classification_validation.haml b/views/classification_validation.haml index 4a2d689..94ba8f9 100644 --- a/views/classification_validation.haml +++ b/views/classification_validation.haml @@ -1,33 +1,33 @@ %dt Correct predictions: %dd - = sprintf("%.2f", model.correct_predictions) - = '%' + = sprintf("%.2f", model.correct_predictions) if model.correct_predictions + = '%' %dt - %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: + %a{:href => "http://en.wikipedia.org/wiki/Receiver_operating_characteristic", :target => "_blank"} Weighted area under ROC: %dd - = sprintf("%.3f", model.weighted_area_under_roc) + = sprintf("%.3f", model.weighted_area_under_roc) if model.weighted_area_under_roc %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: -%dd= sprintf("%.3f", model.specificity) + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Specificity: +%dd= sprintf("%.3f", model.specificity) if model.specificity %dt - %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: -%dd= sprintf("%.3f", model.sensitivity) + %a{:href => "http://en.wikipedia.org/wiki/Sensitivity_and_specificity", :target => "_blank"} Sensitivity: +%dd= sprintf("%.3f", model.sensitivity) if model.sensitivity %dt - %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: + %a{:href => "http://en.wikipedia.org/wiki/Confusion_matrix", :target => "_blank"} Confusion Matrix: %dd - %table - %tr - %td{:colspan => 2, :rowspan => 2} - %th{:colspan => 2} Measured - %tr - %th{:bgcolor => "#CCD2DC"} active - %th{:bgcolor => "#CCD2DC"} inactive - %tr - %th{:rowspan => 2} Predicted - %th{:bgcolor => "#CCD2DC"} active - %td= model.true_positives - %td= model.false_positives - %tr - %th{:bgcolor => "#CCD2DC"} inactive - %td= model.false_negatives - %td= model.true_negatives + %table + %tr + %td{:colspan => 2, :rowspan => 2} + %th{:colspan => 2} Measured + %tr + %th{:bgcolor => "#CCD2DC"} active + %th{:bgcolor => "#CCD2DC"} inactive + %tr + %th{:rowspan => 2} Predicted + %th{:bgcolor => "#CCD2DC"} active + %td= model.true_positives if model.true_positives + %td= model.false_positives if model.false_positives + %tr + %th{:bgcolor => "#CCD2DC"} inactive + %td= model.false_negatives if model.false_negatives + %td= model.true_negatives if model.true_negatives diff --git a/views/validation.haml b/views/validation.haml index 90150d1..bb44058 100644 --- a/views/validation.haml +++ b/views/validation.haml @@ -17,7 +17,7 @@ %dd= model.nr_predictions - case model.type - when "classification" - = haml :classification_validation, :locals=>{:model=>model}, :layout => false + = haml :classification_validation, :locals=>{:model=>model}, :layout => false if model.correct_predictions - when "regression" = haml :regression_validation, :locals=>{:model=>model}, :layout => false - else -- cgit v1.2.3 From d214692e1828471084b00af4115a06196c6578f7 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Mon, 13 Sep 2010 18:23:45 +0200 Subject: RDF/XML download disabled, QMRF report generation enabled --- application.rb | 7 ---- model.rb | 117 ++++++++++++++++++++++--------------------------------- views/model.haml | 14 ++++--- views/style.sass | 2 +- 4 files changed, 55 insertions(+), 85 deletions(-) diff --git a/application.rb b/application.rb index 9616841..7a18fd5 100644 --- a/application.rb +++ b/application.rb @@ -58,13 +58,6 @@ get '/model/:id/:view/?' do haml :model, :locals=>{:model=>model}, :layout => false when /validation/ haml :validation, :locals=>{:model=>model}, :layout => false - #if model.type == "classification" - #haml :classification_validation, :locals=>{:model=>model}, :layout => false - #elsif model.type == "regression" - #haml :regression_validation, :locals=>{:model=>model}, :layout => false - #else - #return "Unknown model type '#{model.type}'" - #end else return "unable to render model: id #{params[:id]}, view #{params[:view]}" end diff --git a/model.rb b/model.rb index 99d6ab3..da12f0b 100644 --- a/model.rb +++ b/model.rb @@ -1,15 +1,25 @@ class ToxCreateModel include DataMapper::Resource + property :id, Serial property :name, String, :length => 255 - property :uri, String, :length => 255 + property :warnings, Text, :length => 2**32-1 + property :type, String + property :created_at, DateTime + property :task_uri, String, :length => 255 + property :uri, String, :length => 255 + property :validation_task_uri, String, :length => 255 property :validation_uri, String, :length => 255 + property :validation_report_task_uri, String, :length => 255 property :validation_report_uri, String, :length => 255 - property :warnings, Text, :length => 2**32-1 + + property :validation_qmrf_task_uri, String, :length => 255 + property :validation_qmrf_uri, String, :length => 255 + property :nr_compounds, Integer property :nr_predictions, Integer property :true_positives, Integer @@ -23,8 +33,6 @@ class ToxCreateModel property :r_square, Float property :root_mean_squared_error, Float property :mean_absolute_error, Float - property :type, String - property :created_at, DateTime def status #begin @@ -50,6 +58,14 @@ class ToxCreateModel end end + def validation_qmrf_status + begin + RestClient.get(File.join(@validation_qmrf_task_uri, 'hasStatus')).body + rescue + "Service offline" + end + end + def algorithm begin RestClient.get(File.join(@uri, 'algorithm')).body @@ -74,64 +90,6 @@ class ToxCreateModel end end -=begin - def classification_validation - begin - uri = File.join(@validation_uri, 'statistics') - yaml = RestClient.get(uri).body - v = YAML.load(yaml) - tp=0; tn=0; fp=0; fn=0; n=0 - v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell| - if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true" - tp = cell[:confusion_matrix_value] - n += tp - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false" - tn = cell[:confusion_matrix_value] - n += tn - elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true" - fn = cell[:confusion_matrix_value] - n += fn - elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false" - fp = cell[:confusion_matrix_value] - n += fp - end - end - @nr_predictions = n - @true_positives = tp - @false_positives = fp - @true_negatives = tn - @false_negatives = fn - @correct_predictions = 100*(tp+tn).to_f/n - @weighted_area_under_roc = v[:classification_statistics][:weighted_area_under_roc].to_f - @sensitivity = tp.to_f/(tp+fn) - @specificity = tn.to_f/(tn+fp) - save - #:correct_predictions => sprintf("%.2f", 100*(tp+tn).to_f/n), - #:weighted_area_under_roc => sprintf("%.3f", v[:classification_statistics][:weighted_area_under_roc].to_f), - #:sensitivity => sprintf("%.3f", tp.to_f/(tp+fn)), - #:specificity => sprintf("%.3f", tn.to_f/(tn+fp)) - #} - rescue - "Service offline" - end - end - - def regression_validation - begin - uri = File.join(@validation_uri, 'statistics') - yaml = RestClient.get(uri).body - v = YAML.load(yaml) - @nr_predictions = v[:num_instances] - v[:num_unpredicted] - @r_square = v[:regression_statistics][:r_square] - @root_mean_squared_error = v[:regression_statistics][:root_mean_squared_error] - @mean_absolute_error = v[:regression_statistics][:mean_absolute_error] - save - rescue - "Service offline" - end - end -=end - def process if @uri.nil? and status == "Completed" @@ -148,13 +106,20 @@ class ToxCreateModel elsif @validation_uri.nil? and validation_status == "Completed" begin + update :validation_uri => RestClient.get(File.join(@validation_task_uri, 'resultURI')).body LOGGER.debug "Validation URI: #{@validation_uri}" + update :validation_report_task_uri => RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @validation_uri).body LOGGER.debug "Validation Report Task URI: #{@validation_report_task_uri}" + + update :validation_qmrf_task_uri => RestClient.post(File.join(@@config[:services]["opentox-validation"],"/reach_report/qmrf"), :model_uri => @uri).body + LOGGER.debug "QMRF Report Task URI: #{@validation_qmrf_task_uri}" + uri = File.join(@validation_uri, 'statistics') yaml = RestClient.get(uri).body v = YAML.load(yaml) + case type when "classification" tp=0; tn=0; fp=0; fn=0; n=0 @@ -192,15 +157,25 @@ class ToxCreateModel LOGGER.warn "Cannot create Validation Report Task #{@validation_report_task_uri} for Validation URI #{@validation_uri} from Task #{@validation_task_uri}" end - elsif @validation_report_uri.nil? and validation_report_status == "Completed" - begin - LOGGER.debug File.join(@validation_report_task_uri, 'resultURI') - LOGGER.debug "Report URI: "+RestClient.get(File.join(@validation_report_task_uri, 'resultURI')).body - update :validation_report_uri => RestClient.get(File.join(@validation_report_task_uri, 'resultURI')).body - rescue - LOGGER.warn "Cannot create Validation Report for Task URI #{@validation_report_task_uri} " - end - end + else + + if @validation_report_uri.nil? and validation_report_status == "Completed" + begin + update :validation_report_uri => RestClient.get(File.join(@validation_report_task_uri, 'resultURI')).body + rescue + LOGGER.warn "Cannot create Validation Report for Task URI #{@validation_report_task_uri} " + end + end + + if @validation_qmrf_uri.nil? and validation_qmrf_status == "Completed" + begin + update :validation_qmrf_uri => RestClient.get(File.join(@validation_qmrf_task_uri, 'resultURI')).body + rescue + LOGGER.warn "Cannot create QMRF Report for Task URI #{@validation_qmrf_task_uri} " + end + end + + end end diff --git a/views/model.haml b/views/model.haml index 454423a..0c8ea8f 100644 --- a/views/model.haml +++ b/views/model.haml @@ -42,20 +42,22 @@ %dd %a{:href => "#{model.training_dataset}.xls"} Excel sheet , - %a{:href => "#{model.training_dataset}.rdf"} RDF/XML - %em (experts) , + -#%a{:href => "#{model.training_dataset}.rdf"} RDF/XML + -#%em (experts) , %a{:href => "#{model.training_dataset}.yaml"} YAML %em (experts) %dt Feature dataset: %dd - %a{:href => "#{model.feature_dataset}.rdf"} RDF/XML - , + -#%a{:href => "#{model.feature_dataset}.rdf"} RDF/XML + -#, %a{:href => "#{model.feature_dataset}.yaml"} YAML %em (experts, dataset too large for Excel) %dt Model: %dd - %a{:href => "#{model.uri}.rdf"} RDF/XML - , + -#%a{:href => "#{model.uri}.rdf"} RDF/XML + -#, + - unless model.validation_qmrf_uri.nil? + %a{:href => File.join(model.validation_qmrf_uri,"editor")} QMRF Editor, %a{:href => "#{model.uri}.yaml"} YAML %em (experts, models cannot be represented in Excel) = haml :validation, :locals=>{:model=>model}, :layout => false diff --git a/views/style.sass b/views/style.sass index ea9e65a..5f362a3 100644 --- a/views/style.sass +++ b/views/style.sass @@ -85,7 +85,7 @@ body font-weight: bold color: $fg_color label - width: 25em + width: 28em display: block float: left br -- cgit v1.2.3 From 1952b3ed877e4791429512def5bd7102e4ba7a99 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 24 Nov 2010 13:10:52 +0100 Subject: opentox-ruby-api-wrapper renamed to opentox-ruby --- application.rb | 452 ++++++++++++++++++++++++---------------- helper.rb | 12 +- model.rb | 42 ++-- parser.rb | 119 ----------- public/javascripts/toxcreate.js | 3 +- views/compound_image.haml | 2 +- views/create.haml | 10 +- views/lazar.haml | 17 +- views/model.haml | 40 ++-- views/model_status.haml | 2 +- views/models.haml | 3 +- views/neighbors.haml | 15 +- views/neighbors_navigation.haml | 4 +- views/prediction.haml | 7 +- views/validation.haml | 30 ++- 15 files changed, 376 insertions(+), 382 deletions(-) delete mode 100644 parser.rb diff --git a/application.rb b/application.rb index 6b8de41..fe9b8b4 100644 --- a/application.rb +++ b/application.rb @@ -1,252 +1,350 @@ ['rubygems', "haml", "sass", "rack-flash"].each do |lib| - require lib + require lib end -gem "opentox-ruby-api-wrapper", "= 1.6.6" -require 'opentox-ruby-api-wrapper' +gem "opentox-ruby", "~> 0" +require 'opentox-ruby' gem 'sinatra-static-assets' require 'sinatra/static_assets' require 'ftools' require File.join(File.dirname(__FILE__),'model.rb') require File.join(File.dirname(__FILE__),'helper.rb') -require File.join(File.dirname(__FILE__),'parser.rb') +#require File.join(File.dirname(__FILE__),'parser.rb') use Rack::Flash set :sessions, true -get '/?' do - redirect url_for('/create') +helpers do + + def error(message) + @model.error_messages = message + LOGGER.error message + @model.status = "Error" + @model.save + #@dataset.delete + flash[:notice] = message + redirect url_for('/create') + end + end -get '/models/?' do - @models = ToxCreateModel.all(:order => [ :created_at.desc ]) - @models.each { |model| model.process } - haml :models +get '/?' do + redirect url_for('/create') end -delete '/model/:id/?' do - model = ToxCreateModel.get(params[:id]) - begin - RestClient.delete model.uri if model.uri - RestClient.delete model.task_uri if model.task_uri - model.destroy! - flash[:notice] = "#{model.name} model deleted." - rescue - flash[:notice] = "#{model.name} model delete error." - end - redirect url_for('/models') +get '/models/?' do + @models = ToxCreateModel.all(:order => [ :created_at.desc ]) + #@models.each { |model| model.process } + haml :models end get '/model/:id/status/?' do response['Content-Type'] = 'text/plain' - model = ToxCreateModel.get(params[:id]) - begin - haml :model_status, :locals=>{:model=>model}, :layout => false - rescue + model = ToxCreateModel.get(params[:id]) + begin + haml :model_status, :locals=>{:model=>model}, :layout => false + rescue return "unavailable" - end + end end get '/model/:id/:view/?' do response['Content-Type'] = 'text/plain' - model = ToxCreateModel.get(params[:id]) + model = ToxCreateModel.get(params[:id]) begin - model.process - model.save + #model.process + #model.save case params[:view] when "model" - haml :model, :locals=>{:model=>model}, :layout => false - when /validation/ + haml :model, :locals=>{:model=>model}, :layout => false + when /validation/ haml :validation, :locals=>{:model=>model}, :layout => false - else - return "unable to render model: id #{params[:id]}, view #{params[:view]}" - end - rescue + else + return "unable to render model: id #{params[:id]}, view #{params[:view]}" + end + rescue return "unable to render model: id #{params[:id]}, view #{params[:view]}" - end + end end get '/predict/?' do - @models = ToxCreateModel.all(:order => [ :created_at.desc ]) - @models = @models.collect{|m| m if m.status == 'Completed'}.compact - haml :predict + @models = ToxCreateModel.all(:order => [ :created_at.desc ]) + @models = @models.collect{|m| m if m.status == 'Completed'}.compact + haml :predict end get '/create' do - haml :create + haml :create end get '/help' do - haml :help + haml :help end get "/confidence" do - haml :confidence + haml :confidence +end + +# proxy to get data from compound service +# (jQuery load does not work with external URIs) +get %r{/compound/(.*)} do |inchi| + inchi = URI.unescape request.env['REQUEST_URI'].sub(/^\//,'').sub(/.*compound\//,'') + OpenTox::Compound.from_inchi(inchi).to_names.join(', ') end -post '/upload' do # create a new model - - if params[:endpoint] == '' - flash[:notice] = "Please enter an endpoint name." - redirect url_for('/create') - end - unless params[:endpoint] and params[:file] and params[:file][:tempfile] - flash[:notice] = "Please enter an endpoint name and upload a Excel or CSV file." - redirect url_for('/create') - end - - @model = ToxCreateModel.new - @model.name = params[:endpoint] - feature_uri = url_for("/feature#"+URI.encode(params[:endpoint]), :full) - parser = Parser.new params[:file], feature_uri - - unless parser.format_errors.empty? - flash[:notice] = "Incorrect file format. Please follow the instructions for #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} formats." - end - - if parser.dataset.compounds.empty? - flash[:notice] = "Dataset #{params[:file][:filename]} is empty." - redirect url_for('/create') - end - - begin - @model.task_uri = OpenTox::Algorithm::Lazar.create_model(:dataset_uri => parser.dataset_uri, :prediction_feature => feature_uri) - rescue - flash[:notice] = "Model creation failed. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." - redirect url_for('/create') - end +post '/models' do # create a new model - begin - validation_task_uri = OpenTox::Validation.crossvalidation( - :algorithm_uri => OpenTox::Algorithm::Lazar.uri, - :dataset_uri => parser.dataset_uri, - :prediction_feature => feature_uri, - :algorithm_params => "feature_generation_uri=#{OpenTox::Algorithm::Fminer.uri}" - ).uri - LOGGER.debug "Validation task: " + validation_task_uri - @model.validation_task_uri = validation_task_uri - rescue - flash[:notice] = "Model validation failed." + unless params[:file] and params[:file][:tempfile] #params[:endpoint] and + flash[:notice] = "Please upload a Excel or CSV file." + redirect url_for('/create') end -=begin - if parser.nr_compounds < 10 - flash[:notice] = "Too few compounds to create a prediction model. Did you provide compounds in SMILES format and classification activities as described in the #{link_to "instructions", "/excel_format"}? As a rule of thumb you will need at least 100 training compounds for nongeneric datasets. A lower number could be sufficient for congeneric datasets." - redirect url_for('/create') - end -=end + @model = ToxCreateModel.create(:name => params[:file][:filename].sub(/\..*$/,"")) + task = OpenTox::Task.create("Uploading dataset and creating lazar model",url_for("/models",:full)) do + + @model.update :status => "Uploading and saving dataset" + begin + @dataset = OpenTox::Dataset.create + # check format by extension - not all browsers provide correct content-type]) + case File.extname(params[:file][:filename]) + when ".csv" + csv = params[:file][:tempfile].read + LOGGER.debug csv + @dataset.load_csv(csv) + when ".xls", ".xlsx" + @dataset.load_spreadsheet(Excel.new params[:file][:tempfile].path) + else + error "#{params[:file][:filename]} has a unsupported file type." + end + rescue => e + error "Dataset creation failed with #{e.message}" + end + @dataset.save + if @dataset.compounds.size < 10 + error "Too few compounds to create a prediction model. Did you provide compounds in SMILES format and classification activities as described in the #{link_to "instructions", "/excel_format"}? As a rule of thumb you will need at least 100 training compounds for nongeneric datasets. A lower number could be sufficient for congeneric datasets." + end + if @dataset.features.keys.size != 1 + error "More than one feature in dataset #{params[:file][:filename]}. Please delete irrelvant columns and try again." + end + if @dataset.metadata[OT.Errors] + error "Incorrect file format. Please follow the instructions for #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} formats." + end + @model.training_dataset = @dataset.uri + @model.nr_compounds = @dataset.compounds.size + @model.warnings = @dataset.metadata[OT.Warnings] unless @dataset.metadata[OT.Warnings].empty? + @model.save - @model.nr_compounds = parser.nr_compounds - @model.warnings = '' + @model.update :status => "Creating prediction model" + begin + lazar = OpenTox::Model::Lazar.create(:dataset_uri => @dataset.uri) + rescue => e + error "Model creation failed with '#{e.message}'. Please check if the input file is in a valid #{link_to "Excel", "/excel_format"} or #{link_to "CSV", "/csv_format"} format." + end + LOGGER.debug lazar.metadata.to_yaml + @model.feature_dataset = lazar.metadata[OT.featureDataset] + @model.uri = lazar.uri + case lazar.metadata[OT.isA] + when /Classification/ + @model.type = "classification" + when /Regression/ + @model.type = "regression" + else + @model.type = "unknown" + end + @model.save - @model.warnings += "

Incorrect Smiles structures (ignored):

" + parser.smiles_errors.join("
") unless parser.smiles_errors.empty? - @model.warnings += "

Irregular activities (ignored):

" + parser.activity_errors.join("
") unless parser.activity_errors.empty? - duplicate_warnings = '' - parser.duplicates.each {|inchi,lines| duplicate_warnings += "

#{lines.join('
')}

" if lines.size > 1 } - @model.warnings += "

Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):

" + duplicate_warnings unless duplicate_warnings.empty? - @model.save + unless url_for("",:full).match(/localhost/) + @model.update :status => "Validating model" + begin + validation = OpenTox::Validation.create_crossvalidation( + :algorithm_uri => OpenTox::Algorithm::Lazar.uri, + :dataset_uri => lazar.parameter("dataset_uri"), + :prediction_feature => lazar.parameter("prediction_feature"), + :algorithm_params => "feature_generation_uri=#{lazar.parameter("feature_generation_uri")}" + ) + @model.update(:validation_uri => validation.uri) + LOGGER.debug "Validation URI: #{@model.validation_uri}" + rescue => e + LOGGER.debug "Model validation failed with #{e.message}." + @model.warnings += "Model validation failed with #{e.message}." + end - flash[:notice] = "Model creation and validation started - this may last up to several hours depending on the number and size of the training compounds." - redirect url_for('/models') + # create summary + validation.summary(@model.type).each{|k,v| eval "@model.#{k.to_s} = v"} + @model.save + + @model.update :status => "Creating validation report" + begin + @model.update(:validation_report_uri => validation.create_report) + rescue => e + LOGGER.debug "Validation report generation failed with #{e.message}." + @model.warnings += "Validation report generation failed with #{e.message}." + end - # TODO: check for empty model + @model.update :status => "Creating QMRF report" + begin + @model.update(:validation_qmrf_report_uri => validation.create_qmrf_report) + rescue => e + LOGGER.debug "Validation QMRF report generation failed with #{e.message}." + @model.warnings += "Validation QMRF report generation failed with #{e.message}." + end + end + + + + #@model.warnings += "

Incorrect Smiles structures (ignored):

" + parser.smiles_errors.join("
") unless parser.smiles_errors.empty? + #@model.warnings += "

Irregular activities (ignored):

" + parser.activity_errors.join("
") unless parser.activity_errors.empty? + #duplicate_warnings = '' + #parser.duplicates.each {|inchi,lines| duplicate_warnings += "

#{lines.join('
')}

" if lines.size > 1 } + #@model.warnings += "

Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):

" + duplicate_warnings unless duplicate_warnings.empty? + @model.update :status => "Completed" + lazar.uri + end + @model.update(:task_uri => task.uri) + @model.save + + flash[:notice] = "Model creation and validation started - this may last up to several hours depending on the number and size of the training compounds." + redirect url_for('/models') + +=begin +=end end post '/predict/?' do # post chemical name to model - @identifier = params[:identifier] - unless params[:selection] and params[:identifier] != '' - flash[:notice] = "Please enter a compound identifier and select an endpoint from the list." - redirect url_for('/predict') - end - begin - @compound = OpenTox::Compound.new(:name => params[:identifier]) - rescue - flash[:notice] = "Could not find a structure for '#{@identifier}'. Please try again." - redirect url_for('/predict') - end - @predictions = [] - params[:selection].keys.each do |id| - model = ToxCreateModel.get(id.to_i) - model.process unless model.uri - prediction = nil - confidence = nil - title = nil - db_activities = [] - #LOGGER.debug "curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}" - prediction = YAML.load(`curl -X POST -d 'compound_uri=#{@compound.uri}' -H 'Accept:application/x-yaml' #{model.uri}`) - #prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) - source = prediction.creator - if prediction.data[@compound.uri] - if source.to_s.match(/model/) # real prediction - prediction = prediction.data[@compound.uri].first.values.first - #LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")] - #LOGGER.debug prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] - if !prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")].nil? - @predictions << { + @identifier = params[:identifier] + unless params[:selection] and params[:identifier] != '' + flash[:notice] = "Please enter a compound identifier and select an endpoint from the list." + redirect url_for('/predict') + end + begin + @compound = OpenTox::Compound.from_name(params[:identifier]) + rescue + flash[:notice] = "Could not find a structure for '#{@identifier}'. Please try again." + redirect url_for('/predict') + end + @predictions = [] + params[:selection].keys.each do |id| + model = ToxCreateModel.get(id.to_i) + #model.process unless model.uri + prediction = nil + confidence = nil + title = nil + db_activities = [] + lazar = OpenTox::Model::Lazar.new model.uri + prediction_dataset_uri = lazar.run(:compound_uri => @compound.uri) + prediction_dataset = OpenTox::LazarPrediction.find(prediction_dataset_uri) + if prediction_dataset.metadata[OT.hasSource].match(/dataset/) + @predictions << { + :title => model.name, + :measured_activities => prediction_dataset.measured_activities(@compound) + } + else + predicted_feature = prediction_dataset.metadata[OT.dependentVariables] + prediction = OpenTox::Feature.find(predicted_feature) + LOGGER.debug prediction.to_yaml + if prediction.metadata[OT.error] + @predictions << { + :title => model.name, + :error => prediction.metadata[OT.error] + } + else + @predictions << { + :title => model.name, + :model_uri => model.uri, + :prediction => prediction.metadata[OT.prediction], + :confidence => prediction.metadata[OT.confidence] + } + end + end + # TODO failed/unavailable predictions +=begin + source = prediction.creator + if prediction.data[@compound.uri] + if source.to_s.match(/model/) # real prediction + prediction = prediction.data[@compound.uri].first.values.first + #LOGGER.debug prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#classification")] + #LOGGER.debug prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#confidence")] + if !prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#classification")].nil? + @predictions << { :title => model.name, :model_uri => model.uri, - :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#classification")], - :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] + :prediction => prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#classification")], + :confidence => prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#confidence")] } - elsif !prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")].nil? - @predictions << { + elsif !prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#regression")].nil? + @predictions << { :title => model.name, :model_uri => model.uri, - :prediction => prediction[File.join(@@config[:services]["opentox-model"],"lazar#regression")], - :confidence => prediction[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] + :prediction => prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#regression")], + :confidence => prediction[File.join(CONFIG[:services]["opentox-model"],"lazar#confidence")] } - end - else # database value - prediction = prediction.data[@compound.uri].first.values - @predictions << {:title => model.name, :measured_activities => prediction} - end - else - @predictions << {:title => model.name, :prediction => "not available (not enough similar compounds in the training dataset)"} - end - end - LOGGER.debug @predictions.inspect - - haml :prediction + end + else # database value + prediction = prediction.data[@compound.uri].first.values + @predictions << {:title => model.name, :measured_activities => prediction} + end + else + @predictions << {:title => model.name, :prediction => "not available (not enough similar compounds in the training dataset)"} + end +=end + end + LOGGER.debug @predictions.inspect + + haml :prediction end post "/lazar/?" do # get detailed prediction @page = 0 @page = params[:page].to_i if params[:page] @model_uri = params[:model_uri] - @prediction = YAML.load(OpenTox::Model::Lazar.predict(params[:compound_uri],params[:model_uri])) - @compound = OpenTox::Compound.new(:uri => params[:compound_uri]) - @title = @prediction.title - if @prediction.data[@compound.uri] - if @prediction.creator.to_s.match(/model/) # real prediction - p = @prediction.data[@compound.uri].first.values.first - if !p[File.join(@@config[:services]["opentox-model"],"lazar#classification")].nil? - feature = File.join(@@config[:services]["opentox-model"],"lazar#classification") - elsif !p[File.join(@@config[:services]["opentox-model"],"lazar#regression")].nil? - feature = File.join(@@config[:services]["opentox-model"],"lazar#regression") - end - @activity = p[feature] - @confidence = p[File.join(@@config[:services]["opentox-model"],"lazar#confidence")] - @neighbors = p[File.join(@@config[:services]["opentox-model"],"lazar#neighbors")] - @features = p[File.join(@@config[:services]["opentox-model"],"lazar#features")] - else # database value - @measured_activities = @prediction.data[@compound.uri].first.values - end - else - @activity = "not available (no similar compounds in the training dataset)" - end + lazar = OpenTox::Model::Lazar.new @model_uri + prediction_dataset_uri = lazar.run(:compound_uri => params[:compound_uri]) + @prediction = OpenTox::LazarPrediction.find(prediction_dataset_uri) + @compound = OpenTox::Compound.new(params[:compound_uri]) + #@title = prediction.metadata[DC.title] + # TODO dataset activity + #@activity = prediction.metadata[OT.prediction] + #@confidence = prediction.metadata[OT.confidence] + #@neighbors = [] + #@features = [] +# if @prediction.data[@compound.uri] +# if @prediction.creator.to_s.match(/model/) # real prediction +# p = @prediction.data[@compound.uri].first.values.first +# if !p[File.join(CONFIG[:services]["opentox-model"],"lazar#classification")].nil? +# feature = File.join(CONFIG[:services]["opentox-model"],"lazar#classification") +# elsif !p[File.join(CONFIG[:services]["opentox-model"],"lazar#regression")].nil? +# feature = File.join(CONFIG[:services]["opentox-model"],"lazar#regression") +# end +# @activity = p[feature] +# @confidence = p[File.join(CONFIG[:services]["opentox-model"],"lazar#confidence")] +# @neighbors = p[File.join(CONFIG[:services]["opentox-model"],"lazar#neighbors")] +# @features = p[File.join(CONFIG[:services]["opentox-model"],"lazar#features")] +# else # database value +# @measured_activities = @prediction.data[@compound.uri].first.values +# end +# else +# @activity = "not available (no similar compounds in the training dataset)" +# end haml :lazar end -# proxy to get data from compound service -# (jQuery load does not work with external URIs) -get %r{/compound/(.*)} do |inchi| - OpenTox::Compound.new(:inchi => inchi).names.gsub(/\n/,', ') +delete '/model/:id/?' do + model = ToxCreateModel.get(params[:id]) + begin + RestClient.delete model.uri if model.uri + RestClient.delete model.task_uri if model.task_uri + model.destroy + flash[:notice] = "#{model.name} model deleted." + rescue + flash[:notice] = "#{model.name} model delete error." + end + redirect url_for('/models') end delete '/?' do - ToxCreateModel.auto_migrate! - response['Content-Type'] = 'text/plain' - "All Models deleted." + DataMapper.auto_migrate! + response['Content-Type'] = 'text/plain' + "All Models deleted." end # SASS stylesheet diff --git a/helper.rb b/helper.rb index d100c9e..d691103 100644 --- a/helper.rb +++ b/helper.rb @@ -12,8 +12,16 @@ helpers do haml :js_link, :locals => {:name => name, :destination => destination, :method => "toggle"}, :layout => false end - def compound_image(compound,features) - haml :compound_image, :locals => {:compound => compound, :features => features}, :layout => false + def sort(descriptors) + features = {:activating => [], :deactivating => []} + + descriptors.each { |d| LOGGER.debug d.inspect; features[d[OT.effect].to_sym] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} } + LOGGER.debug features.to_yaml + features + end + + def compound_image(compound,descriptors) + haml :compound_image, :locals => {:compound => compound, :features => sort(descriptors)}, :layout => false end def activity_markup(activity) diff --git a/model.rb b/model.rb index da12f0b..9929ab0 100644 --- a/model.rb +++ b/model.rb @@ -5,19 +5,23 @@ class ToxCreateModel property :id, Serial property :name, String, :length => 255 property :warnings, Text, :length => 2**32-1 + property :error_messages, Text, :length => 2**32-1 # :errors interferes with datamapper validation property :type, String + property :status, String, :length => 255 property :created_at, DateTime property :task_uri, String, :length => 255 property :uri, String, :length => 255 - property :validation_task_uri, String, :length => 255 + property :training_dataset, String, :length => 255 + property :feature_dataset, String, :length => 255 + #property :validation_task_uri, String, :length => 255 property :validation_uri, String, :length => 255 - property :validation_report_task_uri, String, :length => 255 + #property :validation_report_task_uri, String, :length => 255 property :validation_report_uri, String, :length => 255 - property :validation_qmrf_task_uri, String, :length => 255 + #property :validation_qmrf_task_uri, String, :length => 255 property :validation_qmrf_uri, String, :length => 255 property :nr_compounds, Integer @@ -34,13 +38,16 @@ class ToxCreateModel property :root_mean_squared_error, Float property :mean_absolute_error, Float - def status +=begin +def status #begin RestClient.get(File.join(@task_uri, 'hasStatus')).body #rescue # "Service offline" #end end +=end +=begin def validation_status begin @@ -92,29 +99,23 @@ class ToxCreateModel def process + LOGGER.debug self.to_yaml + if @uri.nil? and status == "Completed" - update :uri => RestClient.get(File.join(@task_uri, 'resultURI')).body - lazar = YAML.load(RestClient.get(@uri, :accept => "application/x-yaml").body) - case lazar.dependentVariables - when /classification/ - update :type => "classification" - when /regression/ - update :type => "regression" - else - update :type => "unknown" - end + #update :uri => RestClient.get(File.join(@task_uri, 'resultURI')).body + #lazar = YAML.load(RestClient.get(@uri, :accept => "application/x-yaml").body) elsif @validation_uri.nil? and validation_status == "Completed" begin - update :validation_uri => RestClient.get(File.join(@validation_task_uri, 'resultURI')).body - LOGGER.debug "Validation URI: #{@validation_uri}" + #update :validation_uri => RestClient.get(File.join(@validation_task_uri, 'resultURI')).body + #LOGGER.debug "Validation URI: #{@validation_uri}" - update :validation_report_task_uri => RestClient.post(File.join(@@config[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @validation_uri).body - LOGGER.debug "Validation Report Task URI: #{@validation_report_task_uri}" + #update :validation_report_task_uri => RestClient.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @validation_uri).body + #LOGGER.debug "Validation Report Task URI: #{@validation_report_task_uri}" - update :validation_qmrf_task_uri => RestClient.post(File.join(@@config[:services]["opentox-validation"],"/reach_report/qmrf"), :model_uri => @uri).body - LOGGER.debug "QMRF Report Task URI: #{@validation_qmrf_task_uri}" + #update :validation_qmrf_task_uri => RestClient.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"), :model_uri => @uri).body + #LOGGER.debug "QMRF Report Task URI: #{@validation_qmrf_task_uri}" uri = File.join(@validation_uri, 'statistics') yaml = RestClient.get(uri).body @@ -178,6 +179,7 @@ class ToxCreateModel end end +=end end diff --git a/parser.rb b/parser.rb deleted file mode 100644 index 8468cea..0000000 --- a/parser.rb +++ /dev/null @@ -1,119 +0,0 @@ -require 'spreadsheet' -require 'roo' -class Parser - - attr_accessor :dataset, :format_errors, :smiles_errors, :activity_errors, :duplicates, :nr_compounds, :dataset_uri - - def initialize(file, endpoint_uri) - - @file = file - @dataset = OpenTox::Dataset.new - @feature_uri = endpoint_uri - @dataset.features << endpoint_uri - @dataset.title = URI.decode(endpoint_uri.split(/#/).last) - @format_errors = "" - @smiles_errors = [] - @activity_errors = [] - @duplicates = {} - @nr_compounds = 0 - @data = [] - @activities = [] - @type = "classification" - - # check format by extension - not all browsers provide correct content-type]) - case File.extname(@file[:filename]) - when ".csv" - self.csv - when ".xls", ".xlsx" - self.excel - else - @format_errors = "#{@file[:filename]} is a unsupported file type." - return false - end - - # create dataset - @data.each do |items| - @dataset.compounds << items[0] - @dataset.data[items[0]] = [] unless @dataset.data[items[0]] - case @type - when "classification" - case items[1].to_s - when TRUE_REGEXP - @dataset.data[items[0]] << {@feature_uri => true } - when FALSE_REGEXP - @dataset.data[items[0]] << {@feature_uri => false } - end - when "regression" - if items[1].to_f == 0 - @activity_errors << "Row #{items[2]}: Zero values not allowed for regression datasets - entry ignored." - else - @dataset.data[items[0]] << {@feature_uri => items[1].to_f} - end - end - end - @dataset_uri = @dataset.save - - end - - def csv - row = 0 - @file[:tempfile].each_line do |line| - row += 1 - unless line.chomp.match(/^.+[,;].*$/) # check CSV format - @format_errors = "#{@file[:filename]} is not a valid CSV file." - return false - end - items = line.chomp.gsub(/["']/,'').split(/\s*[,;]\s*/) # remove quotes - LOGGER.debug items.join(",") - input = validate(items[0], items[1], row) # smiles, activity - @data << input if input - end - end - - def excel - excel = 'tmp/' + @file[:filename] - File.mv(@file[:tempfile].path,excel) - begin - if File.extname(@file[:filename]) == ".xlsx" - book = Excelx.new(excel) - else - book = Excel.new(excel) - end - book.default_sheet = 0 - 1.upto(book.last_row) do |row| - input = validate( book.cell(row,1), book.cell(row,2), row ) # smiles, activity - @data << input if input - end - File.safe_unlink(@file[:tempfile]) - rescue - @format_errors = "#{@file[:filename]} is not a valid Excel input file." - return false - end - end - - def validate(smiles, act, row) - compound = OpenTox::Compound.new(:smiles => smiles) - if compound.nil? or compound.inchi.nil? or compound.inchi == "" - @smiles_errors << "Row #{row}: " + [smiles,act].join(", ") - return false - end - unless numeric?(act) or classification?(act) - @activity_errors << "Row #{row}: " + [smiles,act].join(", ") - return false - end - @duplicates[compound.inchi] = [] unless @duplicates[compound.inchi] - @duplicates[compound.inchi] << "Row #{row}: " + [smiles, act].join(", ") - @type = "regression" unless classification?(act) - @nr_compounds += 1 - [ compound.uri, act , row ] - end - - def numeric?(object) - true if Float(object) rescue false - end - - def classification?(object) - !object.to_s.strip.match(TRUE_REGEXP).nil? or !object.to_s.strip.match(FALSE_REGEXP).nil? - end - -end diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js index d1ed490..500b685 100755 --- a/public/javascripts/toxcreate.js +++ b/public/javascripts/toxcreate.js @@ -85,7 +85,8 @@ $(function() { if(/^\d+$/.test(reload_id)) loadModel(reload_id, 'validation'); }; }); - var validationCheck = setTimeout('checkValidation()',15000); + //var validationCheck = setTimeout('checkValidation()',15000); + var validationCheck = setTimeout('checkValidation()',5000); } }); diff --git a/views/compound_image.haml b/views/compound_image.haml index c6f962a..18944dc 100644 --- a/views/compound_image.haml +++ b/views/compound_image.haml @@ -1,2 +1,2 @@ -%img{:src => compound.display_smarts_uri(features[:activating].collect{|f| f[:smarts]},@features[:deactivating].collect{|f| f[:smarts]}), :alt => compound.smiles} +%img{:src => compound.matching_smarts_image_uri(features[:activating].collect{|f| f[:smarts]},features[:deactivating].collect{|f| f[:smarts]}), :alt => compound.to_smiles} diff --git a/views/create.haml b/views/create.haml index 20de401..6563494 100644 --- a/views/create.haml +++ b/views/create.haml @@ -18,13 +18,13 @@ = link_to "instructions for creating training datasets", '/help' before submitting. - %form{ :action => url_for('/upload'), :method => "post", :enctype => "multipart/form-data" } + %form{ :action => url_for('/models'), :method => "post", :enctype => "multipart/form-data" } %fieldset - %label{:for => 'endpoint'} 1. Enter #{toggle_link("#endpoint_description","endpoint")} name and #{toggle_link("#unit","unit")} (for #{toggle_link("#regression","regression")}): - %input{:type => 'text', :name => 'endpoint', :id => 'endpoint', :size => '50'} - %br + -#%label{:for => 'endpoint'} 1. Enter #{toggle_link("#endpoint_description","endpoint")} name and #{toggle_link("#unit","unit")} (for #{toggle_link("#regression","regression")}): + -#%input{:type => 'text', :name => 'endpoint', :id => 'endpoint', :size => '50'} + -#%br %label{:for => 'file'} - 2. Upload training data in + Select training dataset in = link_to "Excel", '/help' or = link_to "CSV", '/help' diff --git a/views/lazar.haml b/views/lazar.haml index 59d5396..a46f82c 100644 --- a/views/lazar.haml +++ b/views/lazar.haml @@ -12,22 +12,25 @@ %table %thead %tr - %th= @title.gsub(/_lazar_.*$/,' ').capitalize + %th= @prediction.title %th= toggle_link("#lazar_algorithm","Prediction") %th= toggle_link("#confidence","Confidence") %th Supporting information %tr - %td.image= compound_image(@compound,@features) - %td= activity_markup(@activity) - %td= sprintf('%.03g', @confidence.to_f.abs) if @confidence + -# %td + %img{:src => @compound.to_image_uri, :alt => @compound.to_smiles} + %td.image= compound_image(@compound,@prediction.descriptors(@compound)) + %td= activity_markup(@prediction.value(@compound)) + %td= sprintf('%.03g', @prediction.confidence(@compound)) + -#%td= @prediction.confidence(@compound) %td %ul %li %a{:href => "#prediction", :id => "show_names"} Names and synonyms :javascript $("a#show_names").click(function () { - $("#compound_names").load("#{File.join("compound",@compound.inchi)}"); + $("#compound_names").load("#{File.join("/compound",@compound.inchi)}"); $("tr#names").toggle(); }); %li= toggle_link("#fragments","Significant fragments") @@ -49,7 +52,7 @@ %tr#fragments{ :style => "display: none;" } %td{:colspan => '4'} = hide_link('#fragments') - = haml :feature_table, :locals => {:features => @features}, :layout => false + = haml :feature_table, :locals => {:features => sort(@prediction.descriptors(@compound))}, :layout => false %tbody#neighbors - = haml :neighbors, :locals => {:neighbors => @neighbors, :page => @page}, :layout => :false + = haml :neighbors, :locals => {:neighbors => @prediction.neighbors(@compound), :page => @page}, :layout => :false diff --git a/views/model.haml b/views/model.haml index 0c8ea8f..d34079d 100644 --- a/views/model.haml +++ b/views/model.haml @@ -8,7 +8,6 @@ %div{:id => "model_#{model.id}"} %h2 = model.name - .model %dl %dt Status: @@ -20,24 +19,25 @@ ) %dt Started: %dd= model.created_at.strftime("%m/%d/%Y - %I:%M:%S%p") - %dt Training compounds: - %dd= model.nr_compounds - %dt Warnings: - - if model.warnings == '' - %dd - - - else + - if model.nr_compounds + %dt Training compounds: + %dd= model.nr_compounds + - if model.error_messages + %dt Errors: + %dd= model.error_messages + - if model.warnings + %dt Warnings: %a{:href => "#", :id => "show_model_#{model.id}_warnings"} show %dd{:id => "model_#{model.id}_warnings", :style => "display: none;"}= model.warnings - - - if model.status == 'Completed' - %dt Algorithm: - %dd - = toggle_link("#lazar_description","lazar") + %dt Algorithm: + %dd= toggle_link("#lazar_description","lazar") + - if model.type %dt Type: %dd= toggle_link("##{model.type}","#{model.type}") - %dt Descriptors: - %dd - %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes + %dt Descriptors: + %dd + %a{:href => 'http://www.maunz.de/libfminer2-bbrc-doc/'} Fminer backbone refinement classes + - if model.training_dataset %dt Training dataset: %dd %a{:href => "#{model.training_dataset}.xls"} Excel sheet @@ -46,18 +46,22 @@ -#%em (experts) , %a{:href => "#{model.training_dataset}.yaml"} YAML %em (experts) + - if model.feature_dataset %dt Feature dataset: %dd -#%a{:href => "#{model.feature_dataset}.rdf"} RDF/XML -#, + %a{:href => "#{model.feature_dataset}.xls"} Excel sheet + , %a{:href => "#{model.feature_dataset}.yaml"} YAML - %em (experts, dataset too large for Excel) + %em (experts) + - if model.uri %dt Model: %dd -#%a{:href => "#{model.uri}.rdf"} RDF/XML -#, - - unless model.validation_qmrf_uri.nil? + - if model.validation_qmrf_uri %a{:href => File.join(model.validation_qmrf_uri,"editor")} QMRF Editor, %a{:href => "#{model.uri}.yaml"} YAML %em (experts, models cannot be represented in Excel) - = haml :validation, :locals=>{:model=>model}, :layout => false + = haml :validation, :locals=>{:model=>model}, :layout => false diff --git a/views/model_status.haml b/views/model_status.haml index 1357d99..897e792 100644 --- a/views/model_status.haml +++ b/views/model_status.haml @@ -1,2 +1,2 @@ -= image_tag("/snake_transparent.gif") if model.status.match(/running|started|created/i) +-#= image_tag("/snake_transparent.gif") if model.status.match(/running|started|created/i) = model.status diff --git a/views/models.haml b/views/models.haml index 6712e3d..17d9c8a 100644 --- a/views/models.haml +++ b/views/models.haml @@ -9,7 +9,8 @@ if(reload_validation) setTimeout('checkValidation()',15000); }); -%p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. +-# %p Get an overview about ToxCreate models. This page is refreshed every 15 seconds to update the model status. +%p Get an overview about ToxCreate models. This page is refreshed every 5 seconds to update the model status. -# explanations = haml :lazar_description, :layout => false diff --git a/views/neighbors.haml b/views/neighbors.haml index 82fafd2..87fef13 100644 --- a/views/neighbors.haml +++ b/views/neighbors.haml @@ -9,15 +9,14 @@ - first = 5*page - last = first+4 - neighbor_id = 0 -- neighbors.sort{|a,b| b.last[:similarity] <=> a.last[:similarity]}[first..last].each do |uri,data| +-# LOGGER.debug neighbors.to_yaml +- neighbors.sort{|a,b| b[OT.similarity] <=> a[OT.similarity]}[first..last].each do |neighbor| - neighbor_id += 1 - - compound = OpenTox::Compound.new(:uri => uri) + - compound = OpenTox::Compound.new(neighbor[OT.compound]) %tr - %td.image= compound_image(compound,data[:features]) - %td - - data[:activities].each do |act| - = activity_markup(act) - %td= sprintf('%.03g', data[:similarity]) + %td.image= compound_image(compound,@prediction.descriptors(compound)) + %td= activity_markup(neighbor[OT.activity]) + %td= sprintf('%.03g', neighbor[OT.similarity]) %td %ul %li @@ -41,5 +40,5 @@ %tr{:id => "fragments#{neighbor_id}", :style => "display: none;" } %td{:colspan => '4'} = hide_link("#fragments#{neighbor_id}") - = haml :feature_table, :locals => {:features => data[:features]}, :layout => false + = haml :feature_table, :locals => {:features => sort(@prediction.descriptors(compound))}, :layout => false diff --git a/views/neighbors_navigation.haml b/views/neighbors_navigation.haml index 43ec3ed..864a99f 100644 --- a/views/neighbors_navigation.haml +++ b/views/neighbors_navigation.haml @@ -7,9 +7,9 @@ #prev= "prev" unless @page.to_i == 0 - = "(#{5*@page+1}-#{5*@page+5}/#{@neighbors.size})" + = "(#{5*@page+1}-#{5*@page+5}/#{@prediction.neighbors(@compound).size})" - #next= "next" unless 5*@page.to_i+5 >= @neighbors.size + #next= "next" unless 5*@page.to_i+5 >= @prediction.neighbors(@compound).size :javascript $("#prev").click(function() { diff --git a/views/prediction.haml b/views/prediction.haml index 0140b5e..8498abc 100644 --- a/views/prediction.haml +++ b/views/prediction.haml @@ -7,8 +7,9 @@ = @identifier %tr %td - %img{:src => @compound.image_uri, :alt => @compound.smiles} + %img{:src => @compound.to_image_uri, :alt => @compound.to_smiles} - @predictions.each do |p| + - LOGGER.debug p.to_yaml %td %b = p[:title] + ":" @@ -25,8 +26,8 @@ }); ) - - elsif p[:prediction].to_s.match(/not available/) - = p[:prediction] + - elsif p[:error] + %br= p[:error] - else = activity_markup(p[:prediction]) - if p[:confidence] diff --git a/views/validation.haml b/views/validation.haml index bb44058..5fc7371 100644 --- a/views/validation.haml +++ b/views/validation.haml @@ -1,18 +1,14 @@ -%dl{:id => "model_validation_#{model.id}"} - %dt - Validation: - %input{ :id => "model_validation_report_#{model.id}", :type => "hidden", :value => "#{model.validation_report_status}", :class => "model_validation_report" } - %dd - - if model.validation_uri +- if model.validation_uri + %dl{:id => "model_validation_#{model.id}"} + %dt + Validation: + -# %input{ :id => "model_validation_report_#{model.id}", :type => "hidden", :value => "#{model.validation_report_status}", :class => "model_validation_report" } + %dd %dl - %dt - Detailed report: - %dd - - if model.validation_report_uri + - if model.validation_report_uri + %dt Detailed report: + %dd %a{:href => model.validation_report_uri, :target => "_blank"} show - - else - = image_tag("/snake_transparent.gif") if model.validation_report_status == "Running" - %a{:href => model.validation_report_task_uri} #{model.validation_report_status} %dt Number of predictions %dd= model.nr_predictions - case model.type @@ -20,8 +16,8 @@ = haml :classification_validation, :locals=>{:model=>model}, :layout => false if model.correct_predictions - when "regression" = haml :regression_validation, :locals=>{:model=>model}, :layout => false - - else - = image_tag("/snake_transparent.gif") if model.validation_status == "Running" - %a{:href => model.validation_task_uri} #{model.validation_status} - +-# else + = image_tag("/snake_transparent.gif") if model.validation_status == "Running" + %a{:href => model.validation_task_uri} #{model.validation_status} + -- cgit v1.2.3 From 1bcac85620afbccae1164a9a880a2290e360aa62 Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 24 Nov 2010 14:43:20 +0100 Subject: opentox-ruby gem in config.ru --- config.ru | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.ru b/config.ru index 78b1144..1616a96 100644 --- a/config.ru +++ b/config.ru @@ -1,5 +1,5 @@ require 'rubygems' -require 'opentox-ruby-api-wrapper' +require 'opentox-ruby' require 'config/config_ru' set :app_file, __FILE__ # to get the view path right run Sinatra::Application -- cgit v1.2.3