|
| 1 | +#!/usr/bin/ruby1.8 |
| 2 | +# svg_roc_plot method - svg_roc_plot_method.rb |
| 3 | +# |
| 4 | +# Copyright 2010 vorgrimmler <dv(a_t)fdm.uni-freiburg.de> |
| 5 | +# This ruby method (svg_roc_plot) exports input data(from true-positive-rate and false-positive-rate arrays) to a *.svg file using gnuplot. Depending on the amount of input data is possible to create 1 to n curves in one plot. |
| 6 | +# Gnuplot is needed. Please install befor using svg_roc_plot. "sudo apt-get install gnuplot" (on debian systems). |
| 7 | +# Usage: See below. |
| 8 | + |
| 9 | +module RubyPlot |
| 10 | + |
| 11 | + def self.plot_lines(svg_path, title, x_lable, y_lable, names, x_values, y_values, faint=nil) |
| 12 | + |
| 13 | + data = [] |
| 14 | + (0..x_values.size-1).each do |i| |
| 15 | + data << y_values[i] |
| 16 | + data << x_values[i] |
| 17 | + end |
| 18 | + |
| 19 | + #Main |
| 20 | + STDOUT.sync = true |
| 21 | + # ----------------------------------------------------- |
| 22 | + # checking input |
| 23 | + # ----------------------------------------------------- |
| 24 | + # check parameters |
| 25 | + status=false |
| 26 | + LOGGER.debug "#{names.length} algs entered" |
| 27 | + |
| 28 | + #LOGGER.debug names.inspect |
| 29 | + #LOGGER.debug data.inspect |
| 30 | + |
| 31 | + if names.length != data.length/2 |
| 32 | + status=true |
| 33 | + end |
| 34 | + |
| 35 | + if status |
| 36 | + raise "Usage: svg_roc_plot (svg_path(?), title(string), x-lable(string), y-lable(sting), algorithms(array), true_pos_data1(array), false_pos_data1(array), ..., true_pos_data_n(array), false_pos_data_n(array))\n"+ |
| 37 | + " Only pairs of data are allowed but at least one.\n"+ |
| 38 | + " Each data array has to provide one float/int number from 0 to 100 per entry." |
| 39 | + end |
| 40 | + |
| 41 | + # gnuplot check |
| 42 | + gnuplot=`which gnuplot | grep -o gnuplot` |
| 43 | + if gnuplot == "gnuplot\n" |
| 44 | + LOGGER.debug "Gnuplot is already installed." |
| 45 | + else |
| 46 | + raise "Please install gnuplot.\n"+ |
| 47 | + "sudo apt-get install gnuplot" |
| 48 | + end |
| 49 | + |
| 50 | + dat_number=0 |
| 51 | + |
| 52 | + output_dat_arr = Array.new |
| 53 | + |
| 54 | + |
| 55 | + # ----------------------------------------------------- |
| 56 | + # create *.dat files of imported data for gnuplot |
| 57 | + # ----------------------------------------------------- |
| 58 | + # write true/false arrays to one array |
| 59 | + for i in 0..names.length-1#/2-1 |
| 60 | + true_pos_arr = data[i*2] |
| 61 | + false_pos_arr = data[i*2+1] |
| 62 | + #check length of input files |
| 63 | + if true_pos_arr.length == false_pos_arr.length |
| 64 | + #LOGGER.debug "Same length!" |
| 65 | + for j in 0..true_pos_arr.length-1 |
| 66 | + #check if array entries are float format and between 0.0 and 100.0 |
| 67 | + if numeric?(true_pos_arr[j].to_s.tr(',', '.')) && true_pos_arr[j].to_s.tr(',', '.').to_f <= 100 && true_pos_arr[j].to_s.tr(',', '.').to_f >= 0 |
| 68 | + if numeric?(false_pos_arr[j].to_s.tr(',', '.')) && false_pos_arr[j].to_s.tr(',', '.').to_f <= 100 && false_pos_arr[j].to_s.tr(',', '.').to_f >= 0 |
| 69 | + output_dat_arr[j] = "#{true_pos_arr[j]} #{false_pos_arr[j]}" |
| 70 | + else |
| 71 | + raise "The data of #{names[i]} has not the right formatin at position #{j}\n"+ |
| 72 | + "The right format is one float/int from 0 to 100 each line (e.g. '0'; '23,34'; '65.87' or '99')" |
| 73 | + end |
| 74 | + else |
| 75 | + raise "The data of #{names[i]} has not the right formatin at position #{j}+\n" |
| 76 | + "The right format is one float/int from 0 to 100 each line (e.g. '0'; '23,34'; '65.87' or '99')" |
| 77 | + end |
| 78 | + end |
| 79 | + #----------------------------------------------------- |
| 80 | + #write *.dat files |
| 81 | + #----------------------------------------------------- |
| 82 | + #write output_dat_arr content in new *.dat file |
| 83 | + File.open( "data#{i}.dat", "w" ) do |the_file| |
| 84 | + the_file.puts output_dat_arr |
| 85 | + end |
| 86 | + LOGGER.debug "data#{i}.dat created." |
| 87 | + output_dat_arr.clear |
| 88 | + |
| 89 | + else |
| 90 | + raise "Data pair of #{names[i]} have no the same number of elements." |
| 91 | + end |
| 92 | + end |
| 93 | + |
| 94 | + # ----------------------------------------------------- |
| 95 | + # create *.plt file for gnuplot |
| 96 | + # ----------------------------------------------------- |
| 97 | + # |
| 98 | + output_plt_arr = Array.new |
| 99 | + output_plt_arr.push "# Specifies encoding and output format" |
| 100 | + output_plt_arr.push "set encoding default" |
| 101 | + output_plt_arr.push "set terminal svg" |
| 102 | + output_plt_arr.push "set output '#{svg_path}'" |
| 103 | + output_plt_arr.push "" |
| 104 | + output_plt_arr.push "# Specifies the range of the axes and appearance" |
| 105 | + |
| 106 | + output_plt_arr.push "set xrange [0:100]" |
| 107 | + output_plt_arr.push "set yrange [0:100]" |
| 108 | + output_plt_arr.push "set grid lw 0.5" |
| 109 | + output_plt_arr.push "set title \"#{title}\"" |
| 110 | + output_plt_arr.push "set key invert reverse Left outside" |
| 111 | + output_plt_arr.push "set xlabel \"#{x_lable}\"" |
| 112 | + output_plt_arr.push "set ylabel \"#{y_lable}\"" |
| 113 | + output_plt_arr.push "set arrow from 0,0 to 100,100 nohead" |
| 114 | + output_plt_arr.push "" |
| 115 | + output_plt_arr.push "" |
| 116 | + output_plt_arr.push "" |
| 117 | + output_plt_arr.push "" |
| 118 | + output_plt_arr.push "# Draws the plot and specifies its appearance ..." |
| 119 | + output_plt_arr.push "plot \\"#'random_0.dat' using 1:2 title 'random' with lines lw 1, \\" |
| 120 | + i = 0 |
| 121 | + for i in 0..names.length-1 |
| 122 | + |
| 123 | + #style = grey[i] ? "lw 1.5 lt 0" : "lw 3" |
| 124 | + style = faint!=nil && faint[i] ? "lw 2" : "lw 4" |
| 125 | + |
| 126 | + if i == names.length-1 |
| 127 | + output_plt_arr.push " 'data#{i}.dat' using 2:1 title '#{names[i]}' with lines #{style}" |
| 128 | + else |
| 129 | + output_plt_arr.push " 'data#{i}.dat' using 2:1 title '#{names[i]}' with lines #{style}, \\" |
| 130 | + end |
| 131 | + end |
| 132 | + output_plt_arr.push "" |
| 133 | + output_plt_arr.push "" |
| 134 | + |
| 135 | + # ----------------------------------------------------- |
| 136 | + # write *.plt files |
| 137 | + # ----------------------------------------------------- |
| 138 | + # write output_dat_arr content in new *.dat file |
| 139 | + File.open( "config.plt", "w" ) do |the_file| |
| 140 | + the_file.puts output_plt_arr |
| 141 | + end |
| 142 | + LOGGER.debug "config.plt created, running gnuplot" |
| 143 | + |
| 144 | + # start gnuplot with created *.plt file |
| 145 | + cmd = "gnuplot config.plt 2>&1" |
| 146 | + response = "" |
| 147 | + IO.popen(cmd) do |f| |
| 148 | + while line = f.gets |
| 149 | + response += line |
| 150 | + end |
| 151 | + end |
| 152 | + raise "gnuplot failes (cmd: "+cmd.to_s+", out: "+response.to_s+")" unless $?==0 |
| 153 | + |
| 154 | + LOGGER.debug "#{svg_path} created. " |
| 155 | + |
| 156 | + # ----------------------------------------------------- |
| 157 | + # remove *.plt and *.dat files |
| 158 | + # ----------------------------------------------------- |
| 159 | + `rm config.plt` |
| 160 | + LOGGER.debug "config.plt removed." |
| 161 | + for i in 0..names.length-1 |
| 162 | + `rm data#{i}.dat` |
| 163 | + LOGGER.debug "data#{i}.dat removed." |
| 164 | + end |
| 165 | + end |
| 166 | + |
| 167 | + def self.test_plot_lines |
| 168 | + plot_lines("/tmp/result.svg" , "name of title", "x-values", "y-values", ["name", "test", "bla"], [[20,60,80], [10,25,70,95], [12,78,99]], [[15,50,90],[20,40,50,70],[34,89,89]],[true,false,true]) |
| 169 | + end |
| 170 | + |
| 171 | + private |
| 172 | + # float check |
| 173 | + def self.numeric?(object) |
| 174 | + true if Float(object) rescue false |
| 175 | + end |
| 176 | +end |
| 177 | + |
0 commit comments