Matt Maycock
10/10/2004 8:55:00 PM
> Can you show us error reproducing "whole" script?
> I don't think of any reason of your problem from your code chunk.
>
> matz.
You asked for it :-)
Here's the script, with all code it calls being included (thus, really
long post)
#------------------------------------------------------------#
#--- COMMAND LINE Script I Use --- #
#--- requires ext/default_plotter and --- #
#--- ext/enum_from - they follow --- #
# reads in a list of csv files that my boss gave me, and takes out
# some experiment data, and adds it into the default plotter to make
# graphs! Not really that complicated.
ls *.csv | ruby -r ext/default_plotter -r ext/enum_from -ne '
lines = File.readlines(chomp).map {|i| i.chomp.split(/\t/)}
header = lines.shift
plotter = `which gnuplot`.chomp
lines.inject([]) {|arr, line|
arr << header.inject(Hash.new) {|h, f| h[f] = line.shift; h}
}.each {|row|
id = row["cloneid"].gsub(/\//, "_")
file = "../../results/#{chomp.gsub(/\.csv$/, "")}/#{id}.png"
Dir.mkdir(File.dirname(file)) unless FileTest.exists?(File.dirname(file))
control, deprived = * %w{CON DEP}.map {|tag|
[0, *[3,6,9,12].map {|i| row["#{i}_#{tag}"].to_f - row["0_CON"].to_f}]
}
xlabel, ylabel, xtics, ytics, xrange, yrange = nil
xlabel = ["Gene Title", "Gene Symbol"].map {|k| "#{k}: #{row[k]}"}
xlabel << ""
table = [%w{Time Control Deprived}]
[0, 3, 6, 9, 12].each_with_index {|e, i|
table << [e.to_s.rjust(3), control[i], deprived[i]].map {|i| i.to_s}
}
frac = /^(-?\d*)(\.?\d*)$/
ilens = (1..2).map {|i|
table.map {|a| a[i] =~ frac ? $1.length : 0}.max
}
flens = (1..2).map {|i|
table.map {|a| a[i] =~ frac ? $2.length : 0}.max
}
(1..2).each {|i|
table.each {|a|
a[i] = "#{$1.rjust(ilens[i-1])}#{$2.ljust(flens[i-1])}" if a[i] =~ frac
}
}
lens = (0...(table[0].length)).map {|i| table.map {|a| a[i].length}.max}
dlens = (0...(table[0].length)).map {|i| table.from(1).map {|a|
a[i].length}.max}
table.each_with_index {|arr, ai|
index = 0
if ai == 0 then
xlabel << arr.map {|item|
actualmax = lens[index]
item.center(actualmax+2)
}.join(" ")
next
end
xlabel << arr.map {|item|
actualmax = lens[index]
datamax = dlens[index]
v = item.rjust(datamax+1)
v.center(actualmax+1)
index += 1
v
}.join(" ")
}
xlabel = xlabel.join("\\n")
DefaultPlotter.data {|files|
[control, deprived].each {|arr|
files.add {|filehandle|
arr.each_with_index {|e, i|
filehandle.puts(e, i*3)
}
}
}
DefaultPlotter.plot(file, plotter, id, xlabel, ylabel, xtics,
ytics, xrange, yrange, "png") {|plot|
files.each_path_with_index {|path, idx|
plot.add(File.expand_path(path), %w{Control Deprived}[idx],
"lines", "2:1")
}
}
}
}
'
#------------------------------------------------------------#
#--- ext/enum_from --- #
# Allows you to take a nth tail...
module Enumerable
def from(index)
result = []
self.each_with_index {|e, i|
next unless i >= index
yield e if block_given?
result << e
}
result
end
end
#------------------------------------------------------------#
#--- ext/default_plotter ---#
#--- requires ext/gnuplot - which follows ---#
# Just an alias for a `plotting' object.
require "ext/gnuplot"
DefaultPlotter = GnuPlot
#------------------------------------------------------------#
#--- ext/gnuplot ---#
#--- requires ext/plot and ext/singleton_class - which follow ---#
# Set up to use gnuplot to make wonderful graphs.
require 'ext/plot'
require 'ext/singleton_class'
require 'tempfile'
module GnuPlot
end
# Take an output (`file' to write to, basically)
# a title (what to call graph)
# an xlabel (what to call x-axis)
# a ylabel (what to call y-axis)
# an xtics (how to mark x-axis)
# a ytics (how to mark y-axis)
# an xrange (what part of x-axis to show)
# a yrange (what part of y-axis to show)
# a format (what to write `as' - png, gif, eps, etc)
# block - takes the `plot' object and interacts with it.
#
# the plot object the block gets has the following methods:
# close : closes the plot command file - now useable for making gnuplots!
# add(path, title, style, use) : add the data from the file with
path, use title and style, with columns use
# path : gives the path of the file containing the gnuplot commands
def GnuPlot.plotter(output, title=nil, xlabel=nil, ylabel=nil,
xtics=nil, ytics=nil, xrange=nil, yrange=nil, format=nil, &block)
raise ArgumentException, "No block given" if block.nil?
if Hash === output then
h = output
syms = [:output, :title, :xlabel, :ylabel, :xtics, :ytics,
:xrange, :yrange, :format]
make_gnuplot(*syms.map {|sym| h[sym]}, &block)
end
raise ArgumentException, "Cannot accept nil output destination." if
output.nil?
gpcmd = Tempfile.new('run_gnuplot_cmds_script')
[["set terminal #{format}", false],
["set output \"#{output}\"", false],
["set pointsize 1.4", false],
["set title \"#{title}\"", title.nil?],
["set xlabel \"#{xlabel}\"", xlabel.nil?],
["set ylabel \"#{ylabel}\"", ylabel.nil?],
["set xrange [#{xrange}]", xrange.nil?],
["set yrange [#{yrange}]", yrange.nil?],
["set xtics (#{xtics})", xtics.nil?],
["set ytics (#{ytics})", ytics.nil?]].each {|str, skip|
gpcmd.puts str unless skip
}
handle = Object.new
closed = false
gpcmds = []
handle.singleton_def(:close) {
next if closed
closed = true
index = 0
space = ' ' * 'plot'.length
cmds = []
gpcmds.each_with_index {|c, i|
cmds << "#{i == 0 ? 'plot' : space} #{c}"
}
gpcmd.puts cmds.join(",\\\n")
gpcmd.close
}
handle.singleton_def(:add) {|path, title, style, using|
cmd = path.inspect
if using.nil? then
cmd += ' using 1:2'
else
cmd += " using #{using}"
end
if title.nil? then
cmd += ' notitle'
else
cmd += " title #{title.inspect}"
end
cmd += " with #{style}" unless style.nil?
gpcmds << cmd
}
handle.singleton_def(:path) {
gpcmd.path
}
result = nil
begin
result = block[handle]
gpcmd.unlink
rescue Exception
begin
gpcmd.unlink
rescue Exception
end
raise
end
result
end
# Turns a set of points into something gnuplot understands as separate
coordinates.
def GnuPlot.make_point(*points)
points.join("\t")
end
# Make GnuPlot a plot!
GnuPlot.extend(Plot)
# Make a gnuplot range! here, we have a name for the range (x?, y?),
and the ends.
# the ends can be numbers, or nolow nohigh...
def GnuPlot.make_range(name, a, b, errorp=nil)
error = errorp.nil? ? Proc.new{|exc, msg|
raise exc, msg
} : Proc.new {|exc, msg|
errorp[exc, msg]
return
}
a = a.strip.downcase
b = b.strip.downcase
error[ArgumentError, "#{name}: both points are #{a.upcase}."] if a
=~ /^no(low|high)$/ && a == b
return make_range[name, b, a] if b == 'nolow' || a == 'nohigh'
floata, floatb = *[a, b].map {|c|
!(/^(-|\+)?(\d+)?\.?(\d+)?$/.match(c).nil? || /\d/.match(c).nil?)}
noa, nob = *[a, b].map {|c| ['nolow', 'nohigh'].include?(c)}
error[ArgumentError, "Invalid points: #{a}, #{b}."] if !(floata ||
noa) && !(floatb || nob)
a = (a == 'nolow') ? '' : a.to_f
b = (b == 'nohigh') ? '' : b.to_f
a, b = b, a if Float === a && Float === b && b < a
a, b = a.to_s, b.to_s
"#{a}:#{b}"
end
#------------------------------------------------------------#
#--- ext/plot ---#
#--- requires ext/singleton_class - which follows ---#
require 'tempfile'
require 'ext/singleton_class'
module Plot
# Output is `where' to go with the graph (file)
# plotter is the actual command to invoke.
# the rest, except errorp and debugp are the same as gnuplot.plotter args
# errorp and debugp are procs toc all with error and debug information.
#
# Needs a block - that block is passed a plot object who's sole method is add,
# which is the same as the add method from the object yieled by
plotter's block.
def plot(output, plotter, title=nil, xlabel=nil, ylabel=nil,
xtics=nil, ytics=nil, xrange=nil, yrange=nil, format=nil, errorp=nil,
debugp=nil)
error = errorp.nil? ? Proc.new{|exc, msg|
raise exc, msg
} : Proc.new {|exc, msg|
errorp[exc, msg]
return
}
debug = debugp.nil? ? Proc.new {} : debugp
error[ArgumentError, 'Block not given for Plot # plot. A block is
required.'] unless block_given?
plotargs = [output, title, xlabel, ylabel, xtics, ytics, xrange,
yrange, format]
plotblock = Proc.new {|plot_handle|
yield(Object.new.singleton_def(:add) {|*args| plot_handle.add(*args)})
plot_handle.close
debug[:command_file, File.readlines(plot_handle.path).map {|i| i.chomp}]
`#{plotter} #{plot_handle.path}`
}
plotter(*plotargs, &plotblock)
end
# Basically, make an object that is a database of plotting files.
# errorp and debugp are the same as above.
# Takes a block - this block gets the `database'
# this database has the following methods:
# add - calling this gets you a filehandle back in the block add gets
# this filehandle can be given points to add, and when the block
# is done, the file gets added to the end of the list of data files
# use_file(fname) - adds fname to the end of the list of data files
# each_path_with_index - use block to go over each file in the list of
# of data files and have the index in the list, too
# each_path - same as above, no index
# at the end of the block, the database's files are `cleared'
def data(errorp=nil, debugp=nil)
error = errorp.nil? ? Proc.new{|exc, msg|
raise exc, msg
} : Proc.new {|exc, msg|
errorp[exc, msg]
return
}
debug = debugp.nil? ? Proc.new {} : debugp
error[ArgumentError, 'Block not given for Plot # data. A block is
required.'] unless block_given?
handle = Object.new
files = []
done = Proc.new {files.each {|f| f.unlink}}
add = Proc.new {|file| files << file}
enum = Proc.new {|block, index|
files.each_with_index {|f, i|
block[f.path, i] if index
block[f.path] unless index
}
}
point = Proc.new {|*args| make_point(*args)}
handle.instance_eval {
@done, @add, @enum,
@error, @debug, @point = done, add, enum,
error, debug, point
}
def handle.add
unless block_given? then
@done[]
@error[ArgumentError, 'Block not given for Plot # data #
handle.add. A block is required.']
end
file = Tempfile.new('plotdata')
filehandle, point = Object.new, @point
filehandle.singleton_def(:puts) {|*points|
file.puts(point[*points])
}
yield filehandle
file.close(false)
@debug[:data_file, File.readlines(file.path).map {|l| l.chomp}]
@add[file]
end
def handle.use_file(fname)
@error[ArgumentError, "File #{fname} does not exist."] unless
FileTest.exists?(fname)
@error[ArgumentError, "File #{fname} isn't a file."] unless
FileTest.file?(fname)
@error[ArgumentError, "File #{fname} isn't readable."] unless
FileTest.readable?(fname)
@add[File.open(fname).singleton_def(:unlink) {self.close}]
end
def handle.each_path_with_index(&block)
if block.nil? then
@done[]
@error[ArgumentError, 'Block not given for Plot # data #
handle.each_path_with_index. A block is required']
end
@enum[block, true]
end
def handle.each_path(&block)
if block.nil? then
@done[]
@error[ArgumentError, 'Block not given for Plot # data #
handle.each_path. A block is required']
end
@enum[block, false]
end
yield handle
files.each {|f| f.unlink}
files.clear
nil
end
end
#------------------------------------------------------------#
#--- ext/singleton_class ---#
class Object
def singleton_class
class << self
self
end
end
def singleton_def(sym, &block)
self.singleton_class.send(:define_method, sym, &block)
self
end
end
--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.