#!/usr/bin/env ruby # # This program produces depth range plots from tables exported from the database gene_sample # # 2009-06-01 Michael Matschiner # # run this script with a table produced by the below SQL query. Copy the part between # =begin and =end into the Command window of Sequel Pro and press 'Run All'. Then use # the Sequel Pro menu to export the results table in CSV format (File > Export > Custom # Query Result > CSV file... ). =begin SELECT organism.latin_name, ROUND(MIN(station.min_water_depth + (station.max_water_depth-station.min_water_depth)/2.0),1), ROUND(MAX(station.min_water_depth + (station.max_water_depth-station.min_water_depth)/2.0),1) , ROUND(MIN(station.mean_water_depth),1), ROUND(MAX(station.mean_water_depth),1) FROM organism INNER JOIN specimen ON specimen.organism_id = organism.id INNER JOIN station ON specimen.station_id = station.id GROUP BY organism.latin_name =end # Run this script by typing # 'ruby depth_range_plotter.rb input_filename' # in the Terminal # Class "Array2" is used to build a two-dimensional matrix which stores # organism names and water depths as given in the CSV file. # class Array2 def initialize @store = [[]] end def [](a,b) if @store[a]==nil || @store[a][b]==nil return nil else return @store[a][b] end end def []=(a,b,x) @store[a] = [] if @store[a]==nil @store[a][b] = x end end # The method to_s() is added to class Float for economical output. This way, # the number of decimals included in floats can be chosen. class Float alias_method :orig_to_s, :to_s def to_s(arg = nil) if arg.nil? orig_to_s else sprintf("%.#{arg}f", self) end end end # The main program starts here. A number of default values is set. See below for dimX. progName = "depth_range_plotter.rb" vertTicks = true vertTickLength = 3 horiTickLength = 3 strokeWidth = 1.0 barwidth = 10 # change this value to stretch the whole plot in x direction. fontSize = 10 # change this value to increase or decrease the font size. rightMargin = 100 topMargin = 120 bottomMargin = fontSize/2 dimY = 400 # The input file is the first command line argument. fileIn = ARGV[0] # The input file is read as a single string. Line endings are detected, # and used to split the string into an array of strings. # str = IO.read( fileIn ) ary = str.split(/\n/) if str.include?("\n") # The header line is deleted # ary.shift # The dimensions of the table is detected. # rowNum = ary.size colNum = 5 inquotes = false mat = Array2.new rowNum.times do |r| tmpstr = ary[r] commapositions = [] tmpstr.length.times do |l| if tmpstr[l..l] == '"' if inquotes == false inquotes = true else inquotes = false end elsif tmpstr[l..l] == "," commapositions << l if inquotes == false end end mat[r,0] = tmpstr[0..commapositions[0]-1].delete '"' mat[r,1] = tmpstr[commapositions[0]+1..commapositions[1]-1] mat[r,2] = tmpstr[commapositions[1]+1..commapositions[2]-1] mat[r,3] = tmpstr[commapositions[2]+1..commapositions[3]-1] mat[r,4] = tmpstr[commapositions[3]+1..tmpstr.length].chomp end organism_names = [] depth_range_min = [] depth_range_max = [] rowNum.times do |r| organism_names << mat[r,0] potential_mins = [] potential_mins << mat[r,1].to_f unless mat[r,1] == "NULL" potential_mins << mat[r,2].to_f unless mat[r,2] == "NULL" potential_mins << mat[r,3].to_f unless mat[r,3] == "NULL" potential_mins << mat[r,4].to_f unless mat[r,4] == "NULL" depth_range_min << potential_mins.min potential_maxs = [] potential_maxs << mat[r,1].to_f unless mat[r,1] == "NULL" potential_maxs << mat[r,2].to_f unless mat[r,2] == "NULL" potential_maxs << mat[r,3].to_f unless mat[r,3] == "NULL" potential_maxs << mat[r,4].to_f unless mat[r,4] == "NULL" depth_range_max << potential_maxs.max end # Organism names and depth ranges are sorted. # i = 0 while i < organism_names.size-1 do if (depth_range_min[i] + depth_range_max[i]) > (depth_range_min[i+1] + depth_range_max[i+1]) organism_names[i],organism_names[i+1] = organism_names[i+1],organism_names[i] depth_range_min[i],depth_range_min[i+1] = depth_range_min[i+1],depth_range_min[i] depth_range_max[i],depth_range_max[i+1] = depth_range_max[i+1],depth_range_max[i] i -= 1 unless i == 0 else i += 1 end end depth_range_max_max = depth_range_max.max if depth_range_max_max > 1000 y_axis_max = ((depth_range_max_max/1000).ceil)*1000 elsif depth_range_max_max > 100 y_axis_max = ((depth_range_max_max/100).ceil)*100 elsif depth_range_max_max > 10 y_axis_max = ((depth_range_max_max/10).ceil)*10 else y_axis_max = depth_range_max_max.ceil end dimX = (rowNum)*2*barwidth + rightMargin # The SVG output is prepared. # svgOutput = String.new svgOutput << "\n" svgOutput << "\n" svgOutput << "\n\n" svgOutput << "\n" svgOutput << "\n\n" #svgOutput << "\n" #rowNum.times do |r| # clustNum.times do |c| # svgOutput << "\n" # sum += mat[r,c+5].to_f # end #end #svgOutput << "\n\n" # svgOutput << "\n" rowNum.times do |r| if depth_range_max[r]-depth_range_min[r] > y_axis_max/100 svgOutput << "\n" else svgOutput << "\n" end end svgOutput << "\n\n" svgOutput << "\n" rowNum.times do |r| svgOutput << "#{organism_names[r]}" end svgOutput << "\n\n" svgOutput << "\n" svgOutput << "0" if y_axis_max > 3000 (y_axis_max/1000).times do |j| svgOutput << "\n" unless j+1 == (y_axis_max/1000) svgOutput << "#{(j+1)*1000}" end elsif y_axis_max > 300 (y_axis_max/100).times do |j| svgOutput << "\n" unless j+1 == (y_axis_max/100) svgOutput << "#{(j+1)*100}" end elsif y_axis_max > 300 (y_axis_max/10).times do |j| svgOutput << "\n" unless j+1 == (y_axis_max/10) svgOutput << "#{(j+1)*10}" end else y_axis_max.times do |j| svgOutput << "\n" unless j+1 == y_axis_max svgOutput << "#{j+1}" end end svgOutput << "\n\n" svgOutput << "\n" svgOutput << "Depth (m)" #if vertTicks # svgOutput << "\n" # (rowNum-1).times do |r| # unless mat[r,3].to_i < mat[r+1,3].to_i # svgOutput << "\n" # svgOutput << "\n" # end # end # svgOutput << "\n\n" #end svgOutput << "\n" svgOutput << "\n" svgOutput << "\n\n" svgOutput << "" # The string "output" is written to a new file with the same name as the input file, # but with "_depth_range.svg" added to the name. # fileOutName = fileIn.scan(/\w+./)[0].chomp(".") + "_depth_range" + ".svg" fileOut = File.new(fileOutName, "w") fileOut.print svgOutput.to_s puts "depth range plot written to \"#{fileOutName}\""