GCAT5.0 released

This commit is contained in:
Minh
2015-04-10 15:12:45 -05:00
commit 67544a10e6
257 changed files with 61661 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

@@ -0,0 +1,34 @@
/*
* Copyright 2012 The Board of Regents of the University of Wisconsin System.
* Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
* Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
*
* This file is part of GCAT.
*
* GCAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GCAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with GCAT. If not, see <http://www.gnu.org/licenses/>.
*/
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require yuiloader-min
//= require datatable-min
//= require jquery.loader-min
//= require_tree .
//= require bootstrap.min
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright 2012 The Board of Regents of the University of Wisconsin System.
* Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
* Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
*
* This file is part of GCAT.
*
* GCAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GCAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with GCAT. If not, see <http://www.gnu.org/licenses/>.
*/
$(document).ready(function(){
// Three blocks below for hiding the optional user input fields.
$(".user_enter1").on("change", function(){
$(".optional_input1").toggle($(this).hasClass("user_enter1_yes"));
});
$(".user_enter2").on("change", function(){
$(".optional_input2").toggle($(this).hasClass("user_enter2_yes"));
});
$(".user_enter3").on("change", function(){
$(".optional_input3").toggle($(this).hasClass("user_enter3_yes"));
});
// handle error redirect & browser back cases//////////////////////////////////////////
/****************************************************
* This function checks the radio box for the
* corresponding optional div with input field.
* If checked show else hide
* @return void
****************************************************/
function reset_optional_fields(radio, optional_box){
if(radio && optional_box){
var radio_ckd = radio.prop('checked');
if(radio_ckd){
optional_box.show();
}
else {
optional_box.hide();
}
} else{
console.error("Error: unknown selector in reset_optional_fields()");
}
}
reset_optional_fields($('#assay_plate_type_m'), $("#time"));
reset_optional_fields($("input#assay_blank_value_user"), $("div.optional_input3"));
reset_optional_fields($("input#assay_transformation_-1"), $("div.optional_input2"));
reset_optional_fields($("input#assay_model_-1"), $("div.optional_input1"));
//////////////////////////////////////////////////////////////////////////////////////
$('#new_assay').submit(function() {
$.loader();
});
$("input[name$='assay[plate_type]']").click(function(){
var value = $(this).val();
if(value=='s') {
$("#time").hide();
}
else if(value=='m') {
$("#time").show();
}
});
});
@@ -0,0 +1,32 @@
/*
* Copyright 2012 The Board of Regents of the University of Wisconsin System.
* Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
* Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
*
* This file is part of GCAT.
*
* GCAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GCAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with GCAT. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_self
*= require_tree .
*= require bootstrap.min
*/
//= require datatable
//= require jquery.loader-min
@@ -0,0 +1,3 @@
// Place all the styles related to the Assays controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright 2012 The Board of Regents of the University of Wisconsin System.
* Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
* Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
*
* This file is part of GCAT.
*
* GCAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GCAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with GCAT. If not, see <http://www.gnu.org/licenses/>.
*/
/*.yui-skin-sam .yui-dt-liner { white-space:nowrap; font-size: 8pt;}
.twoColLiqLtHdr #mainContent { margin:0;min-height:500px; } //Not used anymore NWD// */
body {
background: url("bkg-body.png") repeat-x scroll left top #FFFFFF;
background-color: #FFFFFF;
}
a:visited { color: #428bca !important;}
#nav-bar{
background:#B0C5D4;
border-bottom:1px solid #B0C5D4;
text-align:center;
h1{
font: 42px impact, sans-serif;
}
}
/*#copyright-stmt {
padding: 5px 25px;
width: 88%;
margin: 20px auto 0;
text-align: right;
}*/
#header h1 {
font-size: 32px;
color: #4F4F4F;
}
#results-container {
background-color: #FFFFFF;
border: 1px solid black;
margin: 20px auto 0;
padding: 120px;
width: 4000px;
}
#form-container {
background-color: #FFFFFF;
border: 1px solid black;
margin: 20px auto 0;
width: 1600px;
padding-left: 50px;
}
#contents {
padding: 5px 25px;
}
/*#mainContent{
margin:0;
min-height:500px;
}*/
/*#header {
background: #fffff;
font: 14px arial;
color: black;
height:50px;
text-align:left;
padding: 0px 10px;
border-bottom:1px solid #69B03F;
width: 1600px;
}*/
/*#flash_notice, #flash_error, #flash_alert, .notice, .error, .alert {
padding: 5px 8px;
margin: 10px 0;
}
#flash_notice, .notice {
background-color: #CFC;
border: solid 1px #6C6;
}
#flash_error, #flash_alert, .error, .alert {
background-color: #FCC;
border: solid 1px #C66;
}*/
@@ -0,0 +1,56 @@
body {
background-color: #fff;
color: #333;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px; }
p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px; }
pre {
background-color: #eee;
padding: 10px;
font-size: 11px; }
a {
color: #000;
&:visited {
color: #666; }
&:hover {
color: #fff;
background-color: #000; } }
div {
&.field, &.actions {
margin-bottom: 10px; } }
#notice {
color: green; }
.field_with_errors {
padding: 2px;
background-color: red;
display: table; }
#error_explanation {
width: 450px;
border: 2px solid red;
padding: 7px;
padding-bottom: 0;
margin-bottom: 20px;
background-color: #f0f0f0;
h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
margin-bottom: 0px;
background-color: #c00;
color: #fff; }
ul li {
font-size: 12px;
list-style: square; } }
+157
View File
@@ -0,0 +1,157 @@
/*
* Copyright 2012 The Board of Regents of the University of Wisconsin System.
* Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
* Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
*
* This file is part of GCAT.
*
* GCAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GCAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with GCAT. If not, see <http://www.gnu.org/licenses/>.
*/
/*.tooltip:hover:after { content: attr(data-tooltip);
position: absolute; white-space: nowrap; background: rgba(0, 0, 0, 0.85); padding: 3px 7px; color: #FFF; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; margin-left: 7px; margin-top: -3px;font-size:10px;}
*/
/* Make tooltip "links" have a different pointer (as the tooltip uses the "help" cursor by default) */
a[data-tooltip]
{
cursor:pointer !important;
}
/* Styles for elements having a data-tooltip attribute - using the star selector is processor intensive
so you may wish to change this to list a known, limited set of tags instead */
*[data-tooltip]
{
/* Relativly position the tooltip to enable us to position:absolute
the generated content */
position:relative;
/* Links inherit the !important cursor rule from above */
cursor:help;
/* Moz requires the text-decoration here (as it won't allow the use of
text-decoration:none on generated content) which is why I use the bottom
border to display a more accessible underline */
text-decoration:none;
border-bottom:1px dotted #aaa;
/* Remove the styles for IE7 and below - could be passed using conditional comments */
*text-decoration:inherit;
*border-bottom-width:inherit;
*border-bottom-style:inherit;
*cursor:inherit;
*position:inherit;
}
/* Default :before & :after values */
*[data-tooltip]:after,
*[data-tooltip]:before
{
content:"";
/* Don't show tooltip by default */
opacity:0;
/* Set a high z-index */
z-index:999;
/* Animations won't (yet) work on pseudo elements - shame really as this should fade the tooltip in
after one second - but I'll leave the rules for posterity */
-moz-transition-property: opacity;
-moz-transition-duration: 2s;
-moz-transition-delay: 1s;
-webkit-transition-property: opacity;
-webkit-transition-duration: 2s;
-webkit-transition-delay: 1s;
-o-transition-property: opacity;
-o-transition-duration: 2s;
-o-transition-delay: 1s;
transition-property: opacity;
transition-duration: 2s;
transition-delay: 1s;
/* -moz won't understand the text-decoration here but inherits the parent value of "none" successfully */
text-decoration:none !important;
outline:none;
}
/* Tooltip arrow - shown on hover or focus */
*[data-tooltip]:hover:before,
*[data-tooltip]:focus:before
{
/* Slightly opaque arrow */
opacity:0.94;
outline:none;
content:"";
display:block;
position:absolute;
top:20px;
left:50%;
margin:0 0 0 -5px;
width:0;
height:0;
line-height:0px;
font-size:0px;
/* This sets the tooptip pointer color */
border-bottom:5px solid #33acfc;
border-left:5px solid transparent;
border-right:5px solid transparent;
border-top:transparent;
/* Border gradient */
-webkit-border-image:-webkit-gradient(linear, left top, left bottom, from(#33ccff), to(#33acfc));
}
/* Tooltip body - shown on hover or focus */
*[data-tooltip]:hover:after,
*[data-tooltip]:focus:after
{
/* Slightly opaque tooltip */
opacity:0.94;
/* Set display to block (or inline-block) */
display:block;
/* Use the data-tooltip attribute to set the content*/
content:attr(data-tooltip);
/* Position the tooltip body under the arrow and in the middle of the text */
position:absolute;
top:25px;
left:50%;
margin:0 0 0 -150px;
/* Set the width */
width:290px;
/* Pad */
padding:5px;
/* Style the tooltip */
line-height:18px;
/* min-height */
min-height:18px;
/* Set font styles */
color:#fcfcfc;
font-size:16px;
font-weight:normal;
font-family:helvetica neue, calibri, verdana, arial, sans-serif;
/* Fallback background color */
background:#3198dd;
text-align:center;
outline:none;
/* Moz doesn't recognise the following... */
text-decoration:none !important;
/* Background gradient */
background:-webkit-gradient(linear, left top, left bottom, from(#33acfc), to(#3198dd));
background:-moz-linear-gradient(top,#33acfc,#3198dd);
/* Round the corners */
-moz-border-radius:10px;
-webkit-border-radius:10px;
border-radius:10px;
/* Add a drop shadow */
-moz-box-shadow:2px 2px 4px #ccc;
-webkit-box-shadow:2px 2px 4px #ccc;
box-shadow:2px 2px 4px #ccc;
/* Add a Text shadow */
text-shadow:#2187c8 0 1px 0px;
}
@@ -0,0 +1,23 @@
#
# Copyright 2012 The Board of Regents of the University of Wisconsin System.
# Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
# Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
#
# This file is part of GCAT.
#
# GCAT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GCAT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with GCAT. If not, see <http://www.gnu.org/licenses/>.
#
class ApplicationController < ActionController::Base
protect_from_forgery
end
@@ -0,0 +1,73 @@
include ApplicationHelper
include TableBuilder
#
# Copyright 2012 The Board of Regents of the University of Wisconsin System.
# Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
# Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
#
# This file is part of GCAT.
#
# GCAT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GCAT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with GCAT. If not, see <http://www.gnu.org/licenses/>.
#
class AssaysController < ApplicationController
def new
@assay= Assay.new
end
def create
#Lazy mass assign from form params
@assay = Assay.new(params[:assay])
if @assay.valid?
# Add the calls to methods to parse the form input in @assay and execute R script.
# return the results from R into a new instance variable and display results via show template
#reassign some parameters. Validate on form input params or after manipulations?
@assay = @assay.parse_form_params
#debugger
#execute R calculation and assign instance variable to display
@result = @assay.r_calculation
# no need to keep storing old data
#temp fix for pdfFiles see ticket #424. string of pdfFiles returned rather than array
unless @result[:pdfFiles].nil?
@result[:pdfFiles] = @result[:pdfFile].split('pdf')
@result[:pdfFiles].collect{|element| element + 'pdf'}
end
if ( @result.has_key? :error_message ) #h.has_key?("a") # @result.has_key? :error_message
flash.now[:error] = @result[:error_message] #.join("\n")
#do not allow bad guys to fill disc space with invalid files
FileUtils.rm @result[:path]
render :action => 'inputfile_error_message'
else
# parse the output text file into a hash in order to create a table in Assays#show
@table = output_table(@result, !@result[:layout_file].nil?)
remove_old_files(relative_path(@result[:zipfile]))
flash.now[:notice] = "Your assay processed!\nPlease click on any of plate diagrams to save your results to a zip archive."
render :action => 'show'
end
else
render :action => 'new'
end
end
end
+51
View File
@@ -0,0 +1,51 @@
#
# Copyright 2012 The Board of Regents of the University of Wisconsin System.
# Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
# Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
#
# This file is part of GCAT.
#
# GCAT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GCAT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with GCAT. If not, see <http://www.gnu.org/licenses/>.
#
module ApplicationHelper
def relative_path(fullpath)
fullpath.to_s.gsub(Rails.root.to_s + "/public","")
end
#find all directories in generatedFiles/ and remove
#any that are more than a day old
def remove_old_files(path)
cur_date = extract_date(path)
dirs = Dir.glob(Rails.root + "public/generatedFiles/*") + Dir.glob(Rails.root + "public/uploadedFiles/*")
dirs.compact.each do |dir|
date = extract_date(dir)
if(date != cur_date)
puts "Removing: " + dir #log deletions
%x[ rm -rf #{dir} ]
end
end
end
private
def extract_date(path)
part = "Files/"
segment = path.partition(part).last
date = segment.split(/-[0-9]+/).first
date.to_i
end
end
+29
View File
@@ -0,0 +1,29 @@
#
# Copyright 2012 The Board of Regents of the University of Wisconsin System.
# Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
# Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
#
# This file is part of GCAT.
#
# GCAT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GCAT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with GCAT. If not, see <http://www.gnu.org/licenses/>.
#
module AssaysHelper
def date_time_options
[['Y-m-d H:M:S', '%Y-%m-%d %H:%M:%S'],['Y-m-d H:M:S p', '%Y-%m-%d %I:%M:%S %p'],['m/d/y H:M:S','%m/%d/%y %H:%M:%S'],['m/d/y H:M:S p','%m/%d/%y %I:%M:%S %p'],['d/m/y H:M:S','%d/%m/%y %H:%M:%S'],['d/m/y H:M:S p','%d/%m/%y %I:%M:%S %p'],['m/d/Y H:M', '%m/%d/%Y %H:%M']]
end
end
+64
View File
@@ -0,0 +1,64 @@
module TableBuilder
# I decided to parse the output file produced by the R library
# and build an html table rather than using the YUI JS library
# previously implemented.
#
# This method takes the result hash returned by the R bridge routine and
# builds an array of row arrays
def output_table result, has_layout
# if the user submits a layout file, there will be more columns in the output file
offsets = {:pdf => -2, :page => -1}
if(has_layout)
offsets[:pdf] = -7
offsets[:page] = -6
end
rel_path = result[:txtFile]
pdf_path = File.dirname @result[:txtFile] #Rails.root.join("public/"+result[:pdfFile])
path = Rails.root.join("public/"+rel_path)
raise "File not found" unless File.exists? path
file = File.open path
output = []
file.each_line do |line|
if(output.empty?)
# the headers seem to be enclosed in quotations
# will need to parse a bit differently
l_ar = line.split "\"\t\""
l_ar.first.delete! "\""
l_ar.last.delete! "\"\n"
l_ar.collect! {|l| l.gsub ".", " "}
output << l_ar
else
l_ar = line.split "\t"
l_ar.last.delete! "\"\n"
break unless l_ar.size > 1
output << format_row(l_ar, pdf_path, offsets)
end
end
return output
end
# this method: removes quotations from strings, truncates floats to 2 sig. digits,
# and creates html links to PDF files
# params:
# l_ar--An array of the one row of data
# path--directory path where the pdf file is located
# offsets-- a hash containing the negative array offsets for cells needed to build pdf link
#
# returns: A formatted array of one row from the output.txt data
def format_row l_ar, path, offsets
result = l_ar.collect! do |entry|
if(entry.to_f.zero?)
entry.gsub "\"", ""
elsif(view_context.number_with_precision(entry.to_f, precision: 2, significant: true).size > 15)
"%E" % view_context.number_with_precision(entry.to_f, precision: 2, significant: true)
else
view_context.number_with_precision(entry.to_f, precision: 2, significant: true)
end
end
result[offsets[:page]] = result[offsets[:page]].to_i # page number
# result[-7] == pdf.name
result[0] = "<a href=\"#{path}/#{result[offsets[:pdf]]}?#page=#{result[offsets[:page]]}\" target='_blank'>#{result[0].to_i}</a>".html_safe # add pdf link to first row
return result
end
end
View File
View File
+393
View File
@@ -0,0 +1,393 @@
#
# Copyright 2012 The Board of Regents of the University of Wisconsin System.
# Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
# Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
#
# This file is part of GCAT.
#
# GCAT is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GCAT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with GCAT. If not, see <http://www.gnu.org/licenses/>.
#
require 'zip'
# require 'zip/zipfilesystem'
require 'fileutils'
include FileUtils
# single-plate timestamp
SECONDS = "1/3600".to_r.to_f
MAX_FILE_SIZE = 10000000.0
class Assay
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :input_file, :transformation, :transformation_input, :blank_value, :blank_value_input, :start_index, :remove_points, :remove_jumps, :plate_type,
:plate_dimensions_row, :plate_dimensions_column, :timestamp_format, :growth_threshold, :layout_file,:filename,:content_type, :model, :loess_input
# (1) Validation of input data file
validates_presence_of :input_file, :message => '- No input file was specified.'
#Either look for .csv as file extension, or in mime type (content_type). No need to validate if there is not filename
#validates_format_of :filename, :with => %r{\.(csv|xlsx)$}i, :message => "- You can only upload csv and xlsx files.", :unless => lambda { self.input_file == nil }
validates_format_of :filename, :with => %r{\.(csv)$}i, :message => "- You can only upload csv files.", :unless => lambda { self.input_file == nil }
def filename
unless self.input_file.nil?
self.filename = self.input_file.original_filename
end
end
def content_type
unless self.input_file.nil?
self.content_type = self.input_file.content_type
end
end
# (2)Validation of transformation
# if user input is chosen, the user should enter a valid Delta value (A Real Number)
validates_presence_of :transformation_input, :if => :user_input_r_value?, :message => '- Please Enter Your Delta Value.'
validates_numericality_of :transformation_input, :if => :user_input_r_value? , :greater_than_or_equal_to => 0 , :message => '- Invalid value for Delta. Please Enter a positive real number.'
def user_input_r_value?
transformation == "-1"
end
# (3) Validation of OD blank value
# if user input is chosen,, the user should enter a valid OD blank value(A Real Number)
#validates_inclusion_of :blank_value, :in => %w( default user ), :message => '- Invalid blank value. Please choose one of options'
validates_presence_of :blank_value_input, :if => :user_input?, :message => '- Please Enter Your OD Blank Value.'
validates_numericality_of :blank_value_input,:if => :user_input?, :message => '- Invalid OD blank value. Please Enter A Real Number.'
def user_input?
blank_value == "user"
end
# (4) Validation of start_index
# if user does not enter anything, the system uses the default value start_index = 2
validates_format_of :start_index,:with => /^[0-9 \s]*$/i, :unless => :default_value?,:message => '- Invalid value for start index. Please Enter A Positive Integer Number'
def default_value?
start_index == ''
end
# (5) Validation of remove_points
# if user does not enter anything, the system uses the default value remove_points = 0, that is an empty list
#validates_format_of :remove_points,:with => /^[0-9 \,\s]*$/i, :unless => :remove_points_default_value?, :message => '- Please Enter a comma-separated list of points. Example: 2,3,4,5 (Positive Integer Number)'
validates_format_of :remove_points,:with => /^(\d|\d+\s*,\s*)*$/i, :unless => :remove_points_default_value?, :message => '- Please Enter a comma-separated list of points. Example: 2,3,4,5 (Positive Integer Number)'
def remove_points_default_value?
remove_points == ''
end
# (6) Validation of growth threshold
validates_numericality_of :growth_threshold, :message => '- Please enter a number.'
#validate plate dimensions
#v1 not including custom plate dimensions
#validates :plate_dimensions_column, :numericality => { :only_integer => true, :greater_than => 0}
#validates :plate_dimensions_row, :numericality => { :only_integer => true, :greater_than => 0 }
#validate inoculation timepoint
validates :start_index, :numericality => { :only_integer => true, :greater_than => 0}
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted? #
false
end
def parse_form_params
# (1) input data file
# (2) transformation. N value (A Real Number)
if self.transformation == '-1'
self.transformation = Float(self.transformation_input)
else
self.transformation = self.transformation.to_i
end
# Soothing parameter for growth curve model. Applied for Loess model only.
if self.model == '-1' and self.loess_input != ""
self.loess_input = Float(self.loess_input)
end
# (3) blank value (A Real Number)
if self.blank_value == 'default'
self.blank_value = nil
else
self.blank_value = Float(self.blank_value_input)
end
# (4) start index (A Positive Integer Number)
if
start_index == ''
self.start_index = 2
else
self.start_index.gsub(/\s+/, "") # remove white spaces
self.start_index = self.start_index.to_i
end
# (5) remove points [a space-separated list of points. Example: 2 3 4 5 (Positive Integer Number)]
self.remove_points = self.remove_points.gsub(/\r/,"") # "Some text with a carriage return \r"
self.remove_points = self.remove_points.gsub(/\r\n/,"\n") # "Some text with a carriage return \r\n"
self.remove_points = self.remove_points.gsub(/\s+/, "") # remove white spaces
##collect! calls .to_i on each string in the array and replaces the string with the result of the conversion.
self.remove_points = self.remove_points.split(',').collect! {|n| n.to_i}
## (6) remove jumps (true/false)
if self.remove_jumps == 1
self.remove_jumps = true
else
self.remove_jumps = false
end
############################################################################################
return self
end # end of parse_form_params method
def pad_date(unit)
unit.to_i < 10 ? "0" + unit.to_s : unit.to_s
end
def r_calculation
# uniqueID = Process.pid.to_s + "-" + Time.now.to_i.to_s
#wanted the date to be easier to extract NWD 2/26/14
today = Time.now
uniqueID = today.year.to_s + pad_date(today.month) + pad_date(today.day) + "-" + today.to_i.to_s
# set working directories for uploaded and generated files
directoryPath = Rails.root + "public/uploadedFiles/" + uniqueID
outDir = Rails.root + "public/generatedFiles/" + uniqueID
out_dir_path = outDir.to_s
# make directory and set permission
FileUtils.mkdir_p(outDir)
FileUtils.chmod 0777, outDir
FileUtils.mkdir_p(directoryPath)
FileUtils.chmod 0777, directoryPath
# upload input data file from where it locates into web server via uri/url
fromfile = self.input_file
inputfile = directoryPath + fromfile.original_filename
FileUtils.copy( fromfile.tempfile.path, inputfile )
# upload layout data file from where it locates into web server via uri/url
unless self.layout_file.nil?
fromfile = self.layout_file
layout_file = directoryPath + fromfile.original_filename
FileUtils.copy( fromfile.tempfile.path, layout_file )
end
#do not massive files
if(File.size(inputfile) > MAX_FILE_SIZE)
return {:error_message => "Error: File too big. Maximum file size allowed is #{MAX_FILE_SIZE/(10**6)} MB.", :path => inputfile}
end
# use web interface parsed parameters to call R function/library via Rinruby
R.eval ('library(GCAT)')
R.assign "out.dir", out_dir_path
# That is for Single Plate case. Need modification for multiple plate case
#Use one set.constants call only!
if self.plate_type == 's'
R.assign 'single.plate', 'T'
timestamp_format = SECONDS #self.timestamp_format.to_r.to_f
elsif self.plate_type == 'm'
R.assign 'single.plate', 'F'
timestamp_format = ""+self.timestamp_format+""
end
#################for warringer data###########################################
# used for custom dims
#R.assign 'plate.nrow', 10
#R.assign 'plate.ncol', 20
##############################################################################
R.assign 'time.input', timestamp_format
#R.eval ("gcat.set.constants(time.format = #{timestamp_format}, plate.nrow = #{self.plate_dimensions_row}, plate.ncol = #{self.plate_dimensions_column})")
# assign type of file to load.type; ext determines function call by R
R.assign "load.type", "csv"
ext = "csv"
# (1) input data file
R.assign "file", inputfile.to_s
first_rows = ["Well positions", "Destination plate name", "Plate ID"]
begin
file_row = ""
File.open(inputfile) {|f| file_row = f.readline.split(",").first}
if(first_rows.include?(file_row) == false)
return {:error_message => "Error: Unknown file format.", :path => inputfile}
end
rescue
#bad encoding try to validate in R
first_rows.collect! {|r| r.gsub(" ", ".")} # convert to R format
R.eval("test.out <- read.csv(file)")
R.eval("first_entry <- names(test.out)[1]")
if(first_rows.include?(R.first_entry) == false)
return {:error_message => "Error: Unknown file format.", :path => inputfile}
end
end
# (2) transformation. N value (A Real Number)
R.assign "add.constant", self.transformation
# (3) blank value (A Real Number)
if (self.blank_value == nil)
R.eval "blank.value <- NULL"
else
R.assign "blank.value", self.blank_value
end
# (4) start index (A Positive Integer Number)
R.assign "start.index", self.start_index
# (5) remove points [a space-separated list of points. Example: 2,3,4,5 (Positive Integer Number)]
R.assign "points.to.remove", self.remove_points
R.assign "growth.cutoff", self.growth_threshold
if (self.layout_file ==nil)
R.eval "layout.file <- NULL"
else
R.assign "layout.file", layout_file.to_s
end
#debugger
#R.assign "plate.nrow", self.plate_dimensions_row
#R.assign "plate.ncol", self.plate_dimensions_column
## (6) remove jumps (true/false)
if (self.remove_jumps == true)
R.eval "remove.jumps <- T"
else
R.eval "remove.jumps <- F"
end
# Using growth curve model. By default if this if block
# is not taken then the Sigmund model is used.
if (self.model == -1.to_s)
R.assign 'use.loess', 'T'
if (self.loess_input != "")
R.assign 'smooth.param', self.loess_input
else
R.assign 'smooth.param', 0.1
end
R.assign 'use.linear.param', 'F'
elsif (self.model == 0.to_s)
# Currently not in use. May return someday... NWD 9/1
#R.assign 'use.linear.param', 'T'
R.assign 'use.linear.param', 'F' #must be false
R.assign 'use.loess', 'F'
else
# Initialize values for growth curve models.
R.assign 'use.loess', 'F'
R.assign 'use.linear.param', 'F'
R.assign 'smooth.param', 0.1 # default value
end
# This block evaluates the files (csv or xlsx, single.plate or multiple.plate)
R.eval ('R_file_return_value <- gcat.analysis.main(file, single.plate, layout.file, out.dir=out.dir, graphic.dir = out.dir, add.constant, blank.value,
start.index, growth.cutoff, use.linear.param=use.linear.param, use.loess=use.loess, smooth.param=smooth.param,
points.to.remove = points.to.remove, remove.jumps, time.input, plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"), single.column.headers = c("","A1"),
layout.sheet.headers = c("Strain", "Media Definition"), silent = T, verbose = F, return.fit = F, overview.jpgs = T)')
# good file returns a list of file path(length is more than 1), bad file returns error message string(array length = 1)
print R.R_file_return_value
R.eval ('R_array_return_length <- length(R_file_return_value)')
unless R.R_array_return_length == 1
puts R.R_file_return_value, "\n"
files = R.R_file_return_value # returns a list of file path
status = true
else
error_message = R.R_file_return_value
if(error_message.include? "Error in <remove.points>")
num_data_points = error_message.split("data has ").last.gsub("\n\n", "")
error_message = "Invalid 'Points to ignore'. Please select a value in the range (1-#{num_data_points})."
end
return {:error_message => error_message, :path => inputfile}
end
# process generated files
raise "no files generated" if files.empty?
#search for "_overview.jpg files" from Array of files
overviewFiles = ""
pdfFile = ""
txtFile = ""
files_Array_Size = files.size - 1
for i in 0..files_Array_Size
if files[i].include? "_overview.jpg"
overviewFiles = overviewFiles + files[i] + "\n"
end
if files[i].include? "_plots"
pdfFile = pdfFile + files[i] + "\n"
end
if files[i].include? ".txt"
txtFile = txtFile + files[i] + "\n"
end
end
unless pdfFile.empty?
#pdfFile = pdfFile.sub!(Rails.root.to_s + '/public/', '') #sub!(pattern, replacement) will return nil if no substitutions were performed
pdfFile = pdfFile.gsub(Rails.root.to_s + '/public/', '') #Oct. 04 2011 by Enhai
pdfFile = pdfFile.gsub(/\r/,"") # "Some text with a carriage return \r"
pdfFile = pdfFile.gsub(/\r\n/,"\n") # "Some text with a carriage return \r\n"
pdfFile = pdfFile.gsub(/\s+/, "") # remove white spaces
end
unless txtFile.empty?
#txtFile = txtFile.sub!(Rails.root.to_s + '/public/', '')#sub!(pattern, replacement) will return nil if no substitutions were performed
txtFile = txtFile.gsub(Rails.root.to_s + '/public/', '') #Oct. 04 2011 by Enhai
txtFile = txtFile.gsub(/\r/,"") # "Some text with a carriage return \r"
txtFile = txtFile.gsub(/\r\n/,"\n") # "Some text with a carriage return \r\n"
txtFile = txtFile.gsub(/\s+/, "") # remove white spaces
end
# build array named overviewFiles that contains "_overview.jpg files"
overviewFiles = overviewFiles.split("\n")
raise "no overview files generated" if overviewFiles.empty?
if self.plate_type == 'm'
zipfile = out_dir_path + "/multiplePlateAnalysis.zip"
else
zipfile = out_dir_path + "/singlePlateAnalysis.zip"
end
# create Zip files at current directory
Zip::File.open(zipfile, Zip::File::CREATE) { |zf|
files.each{|file| zf.add(File.basename(file), file)}
#files.each{|file| zf.add(file.sub(out_dir_path + "/", ""), file))}
}
#return results unless error
#zip files, jpg of overviews, txt file for datagrid, pdf file
{:status => status, :overviewFiles => overviewFiles, :zipfile => zipfile, :txtFile => txtFile, :pdfFile => pdfFile, :inputfile => inputfile, :layout_file => layout_file, :model => self.model}
end # end of r_calculation method
end # class Assay
+147
View File
@@ -0,0 +1,147 @@
<%= form_for @assay do |f| %>
<% if @assay.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@assay.errors.count, "error") %> prohibited this assay from being saved:</h2>
<ul>
<% @assay.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<h3>Plate Type</h3>
<%= f.radio_button(:plate_type, 's', :checked => true) %>
<%= f.label(:plate_type_single, "Single-plate") %><br />
<%= f.radio_button(:plate_type, 'm', :checked => false) %>
<%= f.label(:plate_type_single, "Multiple-plate") %><br />
<h3>Input Data File</h3>
Please specify a plate results file to upload for analysis:<br>
<div class="field">
<%= f.file_field :input_file %>
</div>
<h3><span data-tooltip="Optionally upload a companion .csv file containing identifying information for all wells in the experiments(s) to be analyzed, including strain identifiers and growth media (or growth environment) definitions, which are used for graphic output.">Plate Layout File</span></h3>
Optionally upload a plate layout file:<br>
<div class="field">
<%= f.file_field :layout_file %>
</div>
<div class="actions" style="margin-top:30px;">
<%= link_to "Single-Plate Example File","/resources/YPDAFEXglucoseTests_2-25-10.csv" %><br>
<%= link_to "Single-Plate Layout Example File","/resources/YPDAFEXglucoseTests_2-25-10_Layout.csv" %><br>
<%= link_to "Multi-Plate Example File","/resources/test_YYYY_MM_DD_HH_MM_SS.csv" %><br>
<%= link_to "Multi-Plate Layout Example File","/resources/MultiPlateLayout_plateID.csv" %>
</div>
<h3><span data-tooltip="OD value for blank well read. As the default option <NULL>, GCAT will automatically take the first OD reading of each well to be the blank.">Media background</span></h3>
<%= f.radio_button(:blank_value, "default", {:checked => true, :class => "user_enter3 user_enter3_no"}) %>
<%= f.label(:blank_value_blank_value_default, "Take the first OD reading of each well to be the blank") %><br />
<%= f.radio_button(:blank_value, "user", {:class => "user_enter3 user_enter3_yes"}) %>
<%= f.label(:blank_value_user, "User Input.") %>
<div class="field optional_input3" style="display:none">
<%= f.text_field :blank_value_input, :placeholder => 'Enter your OD blank value here' %>
</div>
<h3><span data-tooltip="GCAT transforms optical density (OD) to log(x+δ). x = OD Media background. Specify a value for n or choose from the defaults. Note: 0 is not recommended unless all wells contain many repeated measurements for initial density that can be used to accurately estimate the baseline density. See the user manual for more details.">OD Transform</span></h3>
<%= f.radio_button(:transformation, 1, {:checked => true, :class => "user_enter2 user_enter2_no"}) %>
<%= f.label(:transformation_one, "log(x + 0.1)") %><br />
<%= f.radio_button(:transformation, 0, {:class => "user_enter2 user_enter2_no"}) %>
<%= f.label(:transformation_zero, "log(x)") %><br />
<%= f.radio_button(:transformation, -1, {:class => "user_enter2 user_enter2_yes"}) %>
<%= f.label(:transformation_any, "log(x + δ)") %>
<div class="field optional_input2" style="display:none">
<%= f.text_field :transformation_input, :placeholder => 'Enter your n value here'%>
</div>
<h3><span data-tooltip="Choose the preferred growth curve model selection available below.">Growth curve model</span></h3>
<%= f.radio_button(:model, 1, {:checked => true, :class => "user_enter1 user_enter1_no"})%>
<%= f.label(:model_one, "Sigmoid curve") %>
<%#= f.radio_button(:model, 0, {:class => "user_enter1 user_enter1_no"}) %>
<%#= f.label(:model_zero, "Sigmoid + linear") %>
<%= f.radio_button(:model, -1, {:class => "user_enter1 user_enter1_yes"}) %>
<%= f.label(:model_any, "LOESS. The default smoothing value is 0.1.") %>
<div class="field optional_input1" style="display:none">
<%= f.text_field :loess_input, :placeholder => 'Enter the smoothing value here.'%>
</div>
<h3><span data-tooltip="Enter the index of the timepoint at which the wells were inoculated with the culture.
" >Inoculation timepoint</span></h3>
<div class="field">
<%= f.label :start_index, "Enter the timepoint index (positive integer only). The default value is 2. " %><br />
<%= f.text_field(:start_index, :type => 'number', :min =>'1', :size => '3', :value => '2') %>
</div>
<h3><span data-tooltip="Enter a threshold to determine the presence of a growing culture. GCAT rejects curves where the density measurements never reach this value above the specified inoculation timepoint." >Growth Threshold</span></h3>
<div class="field">
<%= f.label :growth_threshold, "Enter the growth threshold. The default value is 0.05. " %><br />
<%= f.text_field(:growth_threshold, :type => 'number', :min =>'0', :size => '3', :value => '0.05', :step => "0.01") %>
</div>
<h3><span data-tooltip="Enter indices (as a comma-separated list) of any erroneous reads that should be removed across the entire experiment. " >Points to ignore</span></h3>
<div class="field">
<%= f.label :remove_points,"Enter a comma-separated list of points. Example: 2,3,4,5 (positive integers only). The default is an empty list." %><br />
<%= f.text_field :remove_points %>
</div>
<!--<h3><span data-tooltip="GCAT automatically detects sudden changes in OD ('jumps'). Check this box if these instances should be removed when possible. If only one or two jumps are present GCAT will attempt to remove only the affected region." >Remove Jumps</span></h3>-->
<%#= f.check_box(:remove_jumps) %>
<%#= f.label(:remove_jumps, "Employ the jump detection algorithm to attempt to remove problematic points.") %>
<%
=begin %>
<h3><span data-tooltip="Enter the number of rows (letters) and columns (numbers) of wells on each of the plates of this experiment." >Plate Dimensions</span></h3>
<div class="field">
<%= f.label 'number of rows' %>
<%= f.text_field(:plate_dimensions_row, :type => 'number', :min =>'1', :size => '3', :value => '8') %>
</div>
<div class="field">
<%= f.label 'number of columns' %>
<%= f.text_field(:plate_dimensions_column, :type => 'number', :min =>'1', :size => '3', :value => '12') %>
</div>
<%
=end %>
<div id="time" class="field">
<h3><span data-tooltip="Select a correctly formatted timestamp (see user manual for details). The timestamp will be used to convert the time entries into the number of hours." >Timestamp format</span></h3>
<%= f.label :timestamp_format %><br />
<%#= f.text_field(:timestamp_format, :value => '1/3600', :id => 'adam') %>
<%= f.select :timestamp_format, options_for_select(date_time_options()) %>
</div>
<div class="actions" style="margin-top:30px;">
<%= f.submit %>
</div>
<div class="actions" style="margin-top:30px;">
<%= mail_to "gcat.help@glbrc.wisc.edu","Please Send Any Questions To The GLBRC Help Desk And Be Sure To Include 'GCAT' In Your Subject Title", :subject => "GCAT" %>
</div>
<div class="actions" style="margin-top:30px;">
<%= link_to "GCAT Users Manual","/resources/GCAT_users_manual.pdf" %>
</div>
<% end %>
@@ -0,0 +1,6 @@
<div id="form-container">
<h1>Error</h1>
<p>Please resubmit your file.</p>
<%= link_to 'New Assay', new_assay_path%>
<br><br><br>
</div>
+11
View File
@@ -0,0 +1,11 @@
<div id="form-container">
<h1>Growth Curve Analysis Tool</h1>
<div style="width:25%;">
This tool processes microbial growth curve data collected in a microtiter plate format and
generates a table of biologically meaningful growth curve characteristics, as well as relevant
plots. These characteristics can be used to select strains with optimal growth properties.
</div>
<%= render 'form' %>
</div>
+42
View File
@@ -0,0 +1,42 @@
<div id="results-container">
<% if flash[:notice] %>
<div class="alert alert-success alert-dismissible" role="alert" style="width:668px;">
<%= flash[:notice] %>
</div>
<% end %>
<% if flash[:alert] %>
<div class="alert alert-danger alert-dismissible" role="alert">
<%= flash[:alert] %>
</div>
<% end %>
<h1>Analysis Results</h1>
<p>
Uploaded file: <%=h @result[:inputfile].to_s %>
<br>
<% if @result[:layout_file] %>
Layout file: <%=h @result[:layout_file].to_s %>
<% end %>
</p>
<%= link_to 'New Assay', new_assay_path%>
<p>
<% @result[:overviewFiles].each do | overview_file | %>
<%= link_to image_tag(relative_path(overview_file),
:alt => "Your Submission",
:style => "vertical-align:middle;"),
relative_path(@result[:zipfile])%>
<% end %>
</p>
<br>
<h3><i>Analysis Results DataTable</i></h3>
<table class="table table-bordered table-striped table-condensed">
<% @table.each do |row| %>
<% i = 0 %>
<tr>
<% row.each do |cell| %>
<!-- don't round row # -->
<td><%= cell %></td>
<% end %>
</tr>
<% end %>
</table>
</div>
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>GCAT</title>
<%= favicon_link_tag "/favicon.ico" %>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<nav id="nav-bar" class="navbar navbar-default" role="navigation">
<h1>GCAT</h1>
</nav>
<div>
<div id='contents'>
<%= yield %>
</div>
<div id='footer' style='float:right; padding: 5px;'>
Copyright &copy; 2012 The Board of Regents of the University of Wisconsin System
<%= image_tag 'lgplv.jpg' %>
<%= image_tag 'GLBRC_horz_cmyk_small.jpg' %>
</div>
</div>
</body>
</html>