From 0c2554a5a2c3aebf3e99d70fee2075a9b99f9abe Mon Sep 17 00:00:00 2001 From: gebele Date: Mon, 4 Mar 2013 10:28:02 +0100 Subject: first commit --- .gitignore | 2 + Gemfile | 9 ++ application.rb | 58 +++++++++ config.rb | 20 ++++ config.ru | 5 + helper.rb | 218 +++++++++++++++++++++++++++++++++ public/JME.class | Bin 0 -> 26321 bytes public/JME.jar | Bin 0 -> 38760 bytes public/images/arrow_down_float.png | Bin 0 -> 618 bytes public/images/arrow_left_float.png | Bin 0 -> 647 bytes public/images/gray_jean.png | Bin 0 -> 13475 bytes public/javascripts/toxcreate.js | 240 +++++++++++++++++++++++++++++++++++++ public/stylesheets/screen.css | 1 + public/stylesheets/screen.sass | 124 +++++++++++++++++++ views/jme_help.html | 197 ++++++++++++++++++++++++++++++ views/js_link.haml | 5 + views/layout.haml | 35 ++++++ views/predict.haml | 84 +++++++++++++ views/prediction.haml | 26 ++++ 19 files changed, 1024 insertions(+) create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 application.rb create mode 100644 config.rb create mode 100644 config.ru create mode 100644 helper.rb create mode 100644 public/JME.class create mode 100644 public/JME.jar create mode 100644 public/images/arrow_down_float.png create mode 100644 public/images/arrow_left_float.png create mode 100644 public/images/gray_jean.png create mode 100644 public/javascripts/toxcreate.js create mode 100644 public/stylesheets/screen.css create mode 100644 public/stylesheets/screen.sass create mode 100644 views/jme_help.html create mode 100644 views/js_link.haml create mode 100644 views/layout.haml create mode 100644 views/predict.haml create mode 100644 views/prediction.haml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..49b161f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Gemfile.lock +.sass-cache/ diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c88c19a --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +source :rubygems + +gem "compass" +gem "sinatra" +gem "haml" +gem "sass" + +gem "opentox-client", :path => "../opentox-client" +gem "opentox-server", :path => "../opentox-server" diff --git a/application.rb b/application.rb new file mode 100644 index 0000000..bd1985c --- /dev/null +++ b/application.rb @@ -0,0 +1,58 @@ +require 'rubygems' +require 'compass' #must be loaded before sinatra +require 'sinatra' +require 'haml' #must be loaded after sinatra +require 'opentox-client' +require 'opentox-server' +require File.join(File.dirname(__FILE__),'helper.rb') +require File.join(ENV["HOME"],".opentox","config","lazar-gui.rb") + + +get '/?' do + redirect to('/predict') +end + +get '/predict/?' do + @models = [] + models = OpenTox::Model.all $model[:uri] + models.each do |model| + model.get + @models << model + end + haml :predict +end + +post '/predict/?' do + @identifier = params[:identifier] + @compound = OpenTox::Compound.from_smiles $compound[:uri], @identifier.to_s + @models = [] + @predictions = [] + lazar = OpenTox::Algorithm.new File.join($algorithm[:uri],"lazar") + + params[:selection].each do |model| + @mselected = model[0] + @mall = OpenTox::Model.all $model[:uri] + @mall.each do |m| + m.get + @models << m if m.title.match("#{@mselected}") + end + end + @models.each do |m| + @prediction_uri = m.run :compound_uri => "#{@compound.uri}" + prediction = OpenTox::Dataset.new @prediction_uri + @predictions << prediction + end + + @prediction_results = [] + @predictions.each{|p| @prediction_results << p.get} + + + haml :prediction +end + +get '/stylesheets/:name.css' do + content_type 'text/css', :charset => 'utf-8' + sass(:"stylesheets/#{params[:name]}", Compass.sass_engine_options ) +end + + diff --git a/config.rb b/config.rb new file mode 100644 index 0000000..fca7490 --- /dev/null +++ b/config.rb @@ -0,0 +1,20 @@ +# Require any additional compass plugins here. + +# Set this to the root of your project when deployed: +http_path = "/" +css_dir = "public/stylesheets" +sass_dir = "public/stylesheets" +images_dir = "public/images" +javascripts_dir = "public/javascripts" + +# You can select your preferred output style here (can be overridden via the command line): +# output_style = :expanded or :nested or :compact or :compressed +output_style = :compressed + +# To enable relative paths to assets via compass helper functions. Uncomment: +# relative_assets = true + +# To disable debugging comments that display the original location of your selectors. Uncomment: +line_comments = false + +preferred_syntax = :sass diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..4bb92c7 --- /dev/null +++ b/config.ru @@ -0,0 +1,5 @@ +SERVICE = "lazar-gui" +require 'bundler' +Bundler.require +require './application.rb' +run Sinatra::Application diff --git a/helper.rb b/helper.rb new file mode 100644 index 0000000..abcecd4 --- /dev/null +++ b/helper.rb @@ -0,0 +1,218 @@ +helpers do + + def is_authorized(uri, action) + if OpenTox::Authorization.server && session[:subjectid] != nil + return OpenTox::Authorization.authorized?(uri, action, session[:subjectid]) + else + return true + end + return false + end + + def is_aluist + OpenTox::Authorization.list_user_groups(session[:username], session[:subjectid]).include?("aluist") + end + + def hide_link(destination) + @link_id = 0 unless @link_id + @link_id += 1 + haml :js_link, :locals => {:name => "close", :destination => destination, :method => "hide"}, :layout => false + end + + def toggle_link(destination,name) + @link_id = 0 unless @link_id + @link_id += 1 + haml :js_link, :locals => {:name => name, :destination => destination, :method => "toggle"}, :layout => false + end + + def sort(descriptors,value_map) + features = {:activating => [], :deactivating => [], :pc_features => []} + if descriptors.kind_of?(Array) + descriptors.each do |d| + if !value_map.empty? + features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 2 + features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 1 + else + if d[OT.effect] =~ TRUE_REGEXP + features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} + elsif d[OT.effect] =~ FALSE_REGEXP + features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} + end + end + end + else + descriptors.each do |d,v| + features[:pc_features] << {:feature => d, :value => v} + end + end + features + end + + def compound_image(compound,descriptors,value_map) + haml :compound_image, :locals => {:compound => compound, :features => sort(descriptors,value_map)}, :layout => false + end + + def activity_markup(activity,value_map) + if value_map and !value_map.empty? + if value_map.size == 2 + activity = value_map.index(activity) if value_map.has_value? activity + if activity.to_i == 2 + haml ".active #{value_map[activity]}", :layout => false + elsif activity.to_i == 1 + haml ".inactive #{value_map[activity]}", :layout => false + else + haml ".other #{activity.to_s}", :layout => false + end + else + haml ".other #{activity.to_s}", :layout => false + end + elsif OpenTox::Algorithm::numeric? activity + haml ".other #{sprintf('%.03g', activity.to_f)}", :layout => false + else + haml ".other #{activity.to_s}", :layout => false + end +=begin + case activity.class.to_s + when /Float/ + haml ".other #{sprintf('%.03g', activity)}", :layout => false + when /String/ + case activity + when "true" + haml ".active active", :layout => false + when "false" + haml ".inactive inactive", :layout => false + else + haml ".other #{activity.to_s}", :layout => false + end + else + if activity #true + haml ".active active", :layout => false + elsif !activity # false + haml ".inactive inactive", :layout => false + else + haml ".other #{activity.to_s}", :layout => false + end + end +=end + end + + def neighbors_navigation + @page = 0 unless @page + haml :neighbors_navigation, :layout => false + end + + def models_navigation + @page = 0 unless @page + haml :models_navigation, :layout => false + end + + def models_navigation_bottom + @page = 0 unless @page + haml :models_navigation_bottom, :layout => false + end + + def endpoint_option_list(max_time=3600) + out = "" + tmpfile = File.join(TMP_DIR, 'endpoint_option_list') + if File.exists? tmpfile + if Time.now-File.mtime(tmpfile) <= max_time + f = File.open(tmpfile, 'r+') + f.each{|line| out << line} + return out + else + File.unlink(tmpfile) + end + end + result = endpoint_selection() + if result.lines.count > 3 + f = File.new(tmpfile,'w') + f.print result + f.close + end + result + end + + def endpoint_level(endpoint="Endpoints", level=1) + results = OpenTox::Ontology::Echa.echa_endpoints(endpoint) rescue results = [] + out = "" + out += "\n" if results.size > 0 + return out + end + + def endpoint_selection() + out = " \n +
\n" + out += "Please select:\n" + out += endpoint_level + js = "" + out += "
\n" + return out + end + + def logmmol_to_mg(value ,mw) + mg = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4) + return mg + end + + def logmg_to_mg(value) + mg = round_to(10**round_to(value.to_f, 2),4) + return mg + end + + def ptd50_to_td50(value ,mw) + td50 = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4) + return td50 + end + + def round_to(value, deci) + rounded = (value.to_f*(10**deci)).round / (10**deci).to_f + return rounded + end + + def calc_mw(compound_uri) + ds = OpenTox::Dataset.new() + ds.save(@subjectid) + ds.add_compound(compound_uri) + ds.save(@subjectid) + mw_algorithm_uri = File.join(CONFIG[:services]["opentox-algorithm"],"pc/MW") + mw_uri = OpenTox::RestClientWrapper.post(mw_algorithm_uri, {:dataset_uri=>ds.uri}) + ds.delete(@subjectid) + mw_ds = OpenTox::Dataset.find(mw_uri, @subjectid) + mw = mw_ds.data_entries[compound_uri][mw_uri.to_s + "/feature/MW"].first.to_f + mw_ds.delete(@subjectid) + return mw + end + + def transform(value, compound_uri, name, haml) + prediction_trans = nil + model_name = name.to_s.downcase + if model_name.include? "ptd50" + mw = calc_mw(compound_uri) + td50 = ptd50_to_td50(value, mw) + prediction_trans = "TD50: #{td50}" + elsif model_name.include? "loael" + if model_name.include? "mol" + mw = calc_mw(compound_uri) + mg = logmmol_to_mg(value, mw) + prediction_trans = "mg/kg bw/day: #{mg}" + elsif model_name.include? "mg" + mg = logmg_to_mg(value) + prediction_trans = "mg/kg bw/day: #{mg}" + end + end + if haml == true + haml ".other #{prediction_trans.to_s}", :layout => false + else + return prediction_trans + end + end +end diff --git a/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/images/arrow_down_float.png b/public/images/arrow_down_float.png new file mode 100644 index 0000000..2466c8f Binary files /dev/null and b/public/images/arrow_down_float.png differ diff --git a/public/images/arrow_left_float.png b/public/images/arrow_left_float.png new file mode 100644 index 0000000..07b7b14 Binary files /dev/null and b/public/images/arrow_left_float.png differ diff --git a/public/images/gray_jean.png b/public/images/gray_jean.png new file mode 100644 index 0000000..355fba2 Binary files /dev/null and b/public/images/gray_jean.png differ diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js new file mode 100644 index 0000000..ef2a953 --- /dev/null +++ b/public/javascripts/toxcreate.js @@ -0,0 +1,240 @@ +$(function() { + + jQuery.fn.toggleWarnings = function(id) { + var id = id; + this.bind("click", function() { + if($("a#show_model_" + id + "_warnings").html()=="show") { + $("div#model_" + id + "_warnings").slideDown("slow"); + $("a#show_model_" + id + "_warnings").html("hide"); + }else{ + $("div#model_" + id + "_warnings").slideUp("slow"); + $("a#show_model_" + id + "_warnings").html("show"); + } + return false; + }); + }; + + trim = function() { + return this.replace(/^\s+|\s+$/g, ''); + } + + checkStati = function(stati) { + stati = stati.split(", "); + $("body") + var newstati = new Array; + $.each(stati, function(){ + checkProgress(this); + 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 status_before = ""; + if ($("span#model_" + id + "_status") != null) status_before = $("span#model_" + id + "_status").html().trim(); + if (status_before == "Deleting") return -1; + var status_after = data.trim(); + $("span#model_" + id + "_status").animate({"opacity": "0.2"},1000); + $("span#model_" + id + "_status").animate({"opacity": "1"},1000); + if( status_before != status_after) { + $("span#model_" + id + "_status").html(data); + loadModel(id, 'model'); + if (status_after == "Completed" || status_after == "Error") id = -1; + } + }, + error: function(data) { + //alert("status check error"); + id = -1; + } + }); + return id; + }; + + + checkProgress = function(id) { + var task = $("input#model_" + id + "_task").attr('value'); + var opts = {action: task + "/percentageCompleted" , id: id}; + var progress_changed = $.ajax({ + url: opts.action, + async: false, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + var progress = data.trim(); + if (progress == "100") return -1; + $("div#model_" + id + "_progress").progressbar("value", parseInt(progress)); + $("div#model_" + id + "_progress").attr({title: parseInt(progress) + "%"}); + }, + error: function(data) { + id = -1; + } + }); + return id; + }; + + loadModel = function(id, view) { + if(id == "") return -1; + var opts = {method: 'get', action: 'model/' + id + '/' + view, view: view }; + var out = id; + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + if (view == "model") $("div#model_" + id).html(data); + if (view.match(/validation/)) $("dl#model_validation_" + id).html(data); + addExternalLinks(); + }, + error: function(data) { + //alert("loadModel error"); + } + }); + return false; + }; + +}); + +jQuery.fn.editModel = function(options) { + var defaults = { + method: 'get', + action: this.attr('href'), + trigger_on: 'click' + }; + var opts = $.extend(defaults, options); + this.bind(opts.trigger_on, function() { + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + $("div#model_" + opts.id + "_name").html(data); + $("input#model_" + opts.id + "_name").focus(); + }, + error: function(data) { + alert("model edit error!"); + } + }); + return false; + }); +}; + +jQuery.fn.cancelEdit = function(options) { + var defaults = { + method: 'get', + action: 'model/' + options.id + '/name?mode=show', + trigger_on: 'click' + }; + var opts = $.extend(defaults, options); + + this.bind(opts.trigger_on, function() { + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'get' + }, + success: function(data) { + $("div#model_" + opts.id + "_name").html(data); + }, + error: function(data) { + alert("model cancel error!"); + } + }); + return false; + }); +}; + +jQuery.fn.saveModel = function(options) { + var defaults = { + method: 'put', + action: 'model/' + options.id, + trigger_on: 'click' + }; + var opts = $.extend(defaults, options); + + this.bind(opts.trigger_on, function() { + var name = $("input#model_" + opts.id + "_name").val(); + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'put', + 'name': name + }, + success: function(data) { + $("div#model_" + opts.id + "_name").html(data); + }, + error: function(data) { + alert("model save 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)) { + $("div#model_" + opts.id).fadeTo("slow",0.5); + $("span#model_" + opts.id + "_status").html("Deleting"); + $("a#delete_" + opts.id).html(""); + $.ajax({ + type: opts.method, + url: opts.action, + dataType: 'html', + data: { + '_method': 'delete' + }, + success: function(data) { + $("div#model_" + opts.id).fadeTo("slow",0).slideUp("slow").remove(); + }, + error: function(data) { + $("span#model_" + opts.id + "_status").html("Delete Error"); + //alert("model delete error!"); + } + }); + } + return false; + }); +}; + +$(document).ready(function() { + addExternalLinks(); +}); + +addExternalLinks = function() { + $('A[rel="external"]').each(function() { + $(this).attr('alt', 'Link opens in new window.'); + $(this).attr('title', 'Link opens in new window.'); + $(this).attr('target', '_blank'); + }); +}; diff --git a/public/stylesheets/screen.css b/public/stylesheets/screen.css new file mode 100644 index 0000000..adc0596 --- /dev/null +++ b/public/stylesheets/screen.css @@ -0,0 +1 @@ +body{background-image:url("/images/gray_jean.png");background-color:#ccf;overflow:scroll;font-family:sans-serif;margin:1em;min-width:800px;min-heigth:600px}body a{text-decoration:none;font-weight:bold;color:#000}.logo{text-align:right;font-size:1.5em;text-shadow:#b9dcff 2px 2px}.info{background-color:#b9dcff;margin:1em 0;padding:10px;text-align:center;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;background-image:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(70%, #b9dcff));background-image:-webkit-linear-gradient(#ffffff,#b9dcff 70%);background-image:-moz-linear-gradient(#ffffff,#b9dcff 70%);background-image:-o-linear-gradient(#ffffff,#b9dcff 70%);background-image:linear-gradient(#ffffff,#b9dcff 70%);-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset}.content{background-image:url("/images/gray_jean.png")}.content h1{margin:0.3em;text-shadow:#fff 0 1px 0;font-size:x-large;font-family:monospace}.content h2{text-shadow:#fff 0 1px 0;font-size:x-large;font-family:monospace}.content .arrow{margin:5px 0px 5px 20px}.content .back{display:inline}.content .close{text-align:right}.content fieldset#top{border:0;margin-top:5em;padding:10px;background-color:#b9dcff;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset}.content fieldset#top draw{display:block}.content fieldset#middle{border:0;padding:10px;background-color:#b9dcff;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset}.content .model{display:inline;margin:1em}.content fieldset#bottom{border:0;background-color:#b9dcff;padding:10px;margin-bottom:5em;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.content .predictions{background-color:#b9dcff;padding:10px;text-align:justify;margin:0.3em;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.content .was{margin-top:2em;padding:1em;background-image:url("/images/gray_jean.png");-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.content .results{margin-top:2em;padding:1em;background-image:url("/images/gray_jean.png");-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.footer{margin:20px 0 20px 0} diff --git a/public/stylesheets/screen.sass b/public/stylesheets/screen.sass new file mode 100644 index 0000000..3c5e48c --- /dev/null +++ b/public/stylesheets/screen.sass @@ -0,0 +1,124 @@ +//@import compass/reset, compass/css3, compass/utilities, compass/layout +@import compass/css3 + +//$bg-color: #C5C1A4 +$bg-color: #CCCCFF +$bg-color-div: #C5C1E4 +//$border: 2px solid #C5C1A4 +$ist-blue: #B9DCFF + +body + background-image: url("/images/gray_jean.png") + background-color: $bg-color + overflow: scroll + font-family: sans-serif + margin: 1em + min-width: 800px + min-heigth: 600px + + a + text-decoration: none + font-weight: bold + color: black + +.logo + text-align: right + font-size: 1.5em + +text-shadow($ist-blue 2px 2px) + +.info + background-color: $ist-blue + margin: 1em 0 + padding: 10px + text-align: center + +border-bottom-left-radius(25px) + +border-bottom-right-radius(25px) + +background-image(linear-gradient(#FFFFFF, $ist-blue 70%)) + +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset) + +.content + + background-image: url("/images/gray_jean.png") + + h1 + margin: 0.3em + text-shadow: #FFF 0 1px 0 + font-size: x-large + font-family: monospace + + h2 + text-shadow: #FFF 0 1px 0 + font-size: x-large + font-family: monospace + + .arrow + margin: 5px 0px 5px 20px + + .back + display: inline + + .close + text-align: right + + fieldset#top + border: 0 + margin-top: 5em + padding: 10px + background-color: $ist-blue + +border-top-left-radius(25px) + +border-top-right-radius(25px) + +background-clip(border-box) + +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset) + draw + display: block + + fieldset#middle + border: 0 + padding: 10px + background-color: $ist-blue + +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset) + + .model + display: inline + margin: 1em + + fieldset#bottom + border: 0 + background-color: $ist-blue + padding: 10px + margin-bottom: 5em + +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset) + +border-bottom-left-radius(25px) + +border-bottom-right-radius(25px) + +background-clip(border-box) + + .predictions + background-color: $ist-blue + padding: 10px + text-align: justify + margin: 0.3em + +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset) + +border-left-radius(25px) + +border-right-radius(25px) + +background-clip(border-box) + + .was + margin-top: 2em + padding: 1em + background-image: url("/images/gray_jean.png") + +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset) + +border-left-radius(25px) + +border-right-radius(25px) + +background-clip(border-box) + + .results + margin-top: 2em + padding: 1em + background-image: url("/images/gray_jean.png") + +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset) + +border-left-radius(25px) + +border-right-radius(25px) + +background-clip(border-box) + +.footer + margin: 20px 0 20px 0 diff --git a/views/jme_help.html b/views/jme_help.html new file mode 100644 index 0000000..adf3e1f --- /dev/null +++ b/views/jme_help.html @@ -0,0 +1,197 @@ + + + + + + + + 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

+ + + +

Keyboard Shortcuts

+ +

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

+ + + +

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/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 new file mode 100644 index 0000000..14e9689 --- /dev/null +++ b/views/layout.haml @@ -0,0 +1,35 @@ +!!! +%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"} + %head + %meta{'http-equiv' => 'Content-Type', :content => 'text/html; charset=UTF-8'} + %meta{'http-equiv' => "X-UA-Compatible", :content => "chrome=1"} + %title Lazar Toxicity Predictions + %link{ :href=>"/stylesheets/screen.css", :media=>"screen, projection", :rel=>"stylesheet", :type=>"text/css"} + -#%link{ :type=>"text/javascript", :src=>"/sketcher/jquery-ui-1.9.2.custom.css"} + -#%link{ :href=>"/stylesheets/css/print.css", :media=>"print", :rel=>"stylesheet", :type=>"text/css"} + -#%link{ :href=>"/stylesheets/css/ie.css", :media=>"screen, projection", :rel=>"stylesheet", :type=>"text/css"} + -#%link{:rel=>"stylesheet", :href=>"http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css"} + %script{:src=>"http://code.jquery.com/jquery-1.8.3.js"} + -#%script{ :type=>"text/javascript", :src=>"/javascripts/ChemDoodleWeb-libs.js"} + -#%script{ :type=>"text/javascript", :src=>"/javascripts/ChemDoodleWeb.js"} + -#%script{ :type=>"text/javascript", :src=>"/sketcher/jquery-ui-1.9.2.custom.min.js"} + -#%script{ :type=>"text/javascript", :src=>"/sketcher/ChemDoodleWeb-sketcher.js"} + -#%script{:src=>"http://kemia.github.com/js/kemia.js"} + -#%script{:src=>"http://code.jquery.com/ui/1.9.2/jquery-ui.js"} + -#%script{:type => "text/javascript", :src => "#{to('/javascripts/toxcreate.js')}"} + + + + %body + .logo + %h1 Lazar Toxicity Predictions + + .info + This is a placeholder for informations about this IST application. In 3 steps to your prediction. + + .content + = yield + + .footer + © + %a{:href => 'http://www.in-silico.ch', :rel => "external"} in-silico toxicology gmbh 2004-2013 diff --git a/views/predict.haml b/views/predict.haml new file mode 100644 index 0000000..2de8b75 --- /dev/null +++ b/views/predict.haml @@ -0,0 +1,84 @@ +:javascript + function getsmiles() { + if (document.JME.smiles() != '') { + document.form.identifier.value = document.JME.smiles() ; + } + } + +%form{:name => "form", :action => to('/predict'), :method => "post", :enctype => "multipart/form-data" } + %fieldset#top + %a{:href => "#insert", :id => "linkInsert#{p.object_id}"} + %h1 1. Draw or insert your compound + :javascript + $("a#linkInsert#{p.object_id}").click(function () { + $("#insert").toggle(); + document.location = document.location + "#" + "insert"; + }); + #insert{ :style => "display: none" } + %p + %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. + %span{:style=>"font-size:75%"} + © + %a{:href => 'http://www.molinspiration.com/jme/index.html', :rel => "external"} JME Editor + courtesy of Peter Ertl, Novartis + %br + %label{:for => 'identifier'} + or enter the + %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification", :rel => "external"} SMILES + string + %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'} + + .close + = hide_link "#insert" + + .arrow + %img{:src=>"/images/arrow_down_float.png", :alt=>"arrow", :class=> "arrow"} + + + %fieldset#middle + %a{:href => "#models", :id => "linkModels#{p.object_id}"} + %h1 2. Select one or more toxic endpoints + + :javascript + $("a#linkModels#{p.object_id}").click(function () { + $("#models").toggle(); + document.location = document.location + "#" + "models"; + }); + + #models{ :style => "display: none;"} + %p Description about these models. + %br + - @models.each do |model| + %input{:type => 'checkbox', :name => "selection[#{model.title}]", :value => "#{model.metadata}", :uri => "#{model.uri}", :disabled => false} + %model= model.title + %p= model.metadata["#{RDF::DC.modified}"] + %br + + .close + = hide_link "#models" + + .arrow + %img{:src=>"/images/arrow_down_float.png", :alt=>"arrow", :class=> "arrow"} + + + %fieldset#bottom + %a{:href => "#predict", :id => "linkPredict#{p.object_id}"} + %h1 3. Predict + + :javascript + $("a#linkPredict#{p.object_id}").click(function () { + $("#predict").toggle(); + document.location = document.location + "#" + "predict"; + }); + + #predict{ :style => "display: none;"} + %p Display the prediction including neighbours and sort mechanism + %br + %input{ :type => "submit", :value => "Predict", :onclick => "getsmiles();"} + + .close + = hide_link "#predict" diff --git a/views/prediction.haml b/views/prediction.haml new file mode 100644 index 0000000..1286d52 --- /dev/null +++ b/views/prediction.haml @@ -0,0 +1,26 @@ +.predictions + .back + %h1 + %img{:src=>"/images/arrow_left_float.png", :alt=>"arrow"} + %a{:href => to('/predict')} New Prediction + + .was + %h2= "Compound image: " + %img{:src=>"#{@compound.uri}/image", :alt=>@compound.uri, :width=>"100px"} + %br + %h2= "Compound SMILES string: " + %p= @identifier + + .results + %h2= "Selected Entpoints: " + - @models.each do |m| + %p= m.inspect + %br + %h2= "Prediction Uri: " + - @predictions.each do |p| + %p= p.uri + %br + %h2= "Prediction Results: " + - @prediction_results.each do |r| + %p= r + -- cgit v1.2.3