grada 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/grada/gnuplot.rb +226 -0
  2. data/lib/grada.rb +32 -32
  3. metadata +2 -17
@@ -0,0 +1,226 @@
1
+ require 'matrix'
2
+
3
+ class NoGnuPlotExecutableFound < RuntimeError; end
4
+
5
+ class Gnuplot
6
+ def self.candidate?(candidate)
7
+ return candidate if File::executable? candidate
8
+
9
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
10
+ possible_candidate = File::join dir, candidate.strip
11
+
12
+ return possible_candidate if File::executable? possible_candidate
13
+ end
14
+
15
+ nil
16
+ end
17
+
18
+ def self.find_exec(bin)
19
+ bin_list = RUBY_PLATFORM =~ /mswin|mingw/ ? [bin, "#{bin}.exe"] : [bin]
20
+
21
+ bin_list.each do |c|
22
+ exec = candidate?(c)
23
+ return exec if exec
24
+ end
25
+
26
+ nil
27
+ end
28
+
29
+ def self.gnuplot(persist)
30
+ gnu_exec = find_exec( ENV['RB_GNUPLOT'] || 'gnuplot' )
31
+
32
+ raise NoGnuPlotExecutableFound unless gnu_exec
33
+
34
+ "#{gnu_exec} #{'-persist' if persist}"
35
+ end
36
+
37
+ def self.open(persist = true)
38
+ output = nil
39
+ gnuplot_cmd = gnuplot(persist)
40
+
41
+ IO::popen( gnuplot_cmd, 'w+' ) do |io|
42
+ yield io
43
+ io.close_write
44
+ output = io.read
45
+ end
46
+
47
+ output
48
+ end
49
+ end
50
+
51
+ class Plot
52
+ attr_accessor :cmd, :data, :settings, :arbitrary_lines
53
+
54
+ QUOTED_METHODS = [ "title", "output", "xlabel", "x2label", "ylabel", "y2label", "clabel", "cblabel", "zlabel" ]
55
+
56
+ def initialize(io = nil, cmd = 'plot')
57
+ @cmd = cmd
58
+ @settings = []
59
+ @arbitrary_lines = []
60
+ @data = []
61
+ @styles = []
62
+ yield self if block_given?
63
+
64
+ if io
65
+ io << to_gplot
66
+ io << store_datasets
67
+ end
68
+ end
69
+
70
+ def method_missing(meth, *args)
71
+ set meth.id2name, *args
72
+ end
73
+
74
+ def set ( var, value = "" )
75
+ value = "\"#{value}\"" if QUOTED_METHODS.include? var unless value =~ /^'.*'$/
76
+ @settings << [ :set, var, value ]
77
+ end
78
+
79
+ def unset (var)
80
+ @settings << [ :unset, var ]
81
+ end
82
+
83
+ def to_gplot(io = '')
84
+ @settings.each { |setting| io += setting.map(&:to_s).join(' ') + "\n" }
85
+ @styles.each{ |style| io += style.to_s + "\n" }
86
+ @arbitrary_lines.each{ |line| io += line + "\n" }
87
+
88
+ io
89
+ end
90
+
91
+ def store_datasets(io = '')
92
+ if @data.size > 0
93
+ io += @cmd + " #{ @data.map { |element| element.plot_args }.join(', ') } \n"
94
+ io += @data.map { |ds| ds.to_gplot }.compact.join("e\n")
95
+ end
96
+
97
+ io
98
+ end
99
+
100
+ def style(&blk)
101
+ @styles << Style.new(&blk)
102
+ end
103
+
104
+ class Style
105
+ attr_accessor :linestyle, :linetype, :linewidth, :linecolor, :pointtype, :pointsize, :fill, :index
106
+
107
+ alias :ls :linestyle
108
+ alias :lt :linetype
109
+ alias :lw :linewidth
110
+ alias :lc :linecolor
111
+ alias :pt :pointtype
112
+ alias :ps :pointsize
113
+ alias :fs :fill
114
+
115
+ STYLES = [:ls, :lt, :lw, :lc, :pt, :ps, :fs]
116
+
117
+ def self.increment_index
118
+ @index ||= 0
119
+ @index += 1
120
+ end
121
+
122
+ def initialize
123
+ STYLES.each do |style|
124
+ send("#{style}=", nil)
125
+ end
126
+
127
+ yield self if block_given?
128
+
129
+ self.increment_index
130
+ end
131
+
132
+ def to_s
133
+ str = "set style line #{@index}"
134
+
135
+ STYLES.each do |style|
136
+ str += " #{send(style)} #{style}" if send(style)
137
+ end
138
+
139
+ str
140
+ end
141
+ end
142
+ end
143
+
144
+ class DataSet
145
+ attr_accessor :title, :with, :using, :data, :linewidth, :linecolor, :matrix, :smooth, :axes, :index, :linestyle
146
+
147
+ alias :ls :linestyle
148
+
149
+ def initialize(data = nil)
150
+ @data = data
151
+ @linestyle = nil
152
+ @title = nil
153
+ @with = nil
154
+ @using = nil
155
+ @linewidth = nil
156
+ @linecolor = nil
157
+ @matrix = nil
158
+ @smooth = nil
159
+ @axes = nil
160
+ @index = nil
161
+
162
+ yield self if block_given?
163
+ end
164
+
165
+ def notitle
166
+ '"No Title"'
167
+ end
168
+
169
+ def plot_args(io = '')
170
+ io += @data.is_a?(String) ? @data : "'-'"
171
+ io += " index #{@index}" if @index
172
+ io += " using #{@using}" if @using
173
+ io += " axes #{@axes}" if @axes
174
+ io += " title #{@title ? "\"#{@title}\"" : notitle}"
175
+ io += " matrix #{@matrix}" if @matrix
176
+ io += " smooth #{@smooth}" if @smooth
177
+ io += " with #{@with}" if @with
178
+ io += " linecolor #{@linecolor}" if @linecolor
179
+ io += " linewidth #{@linewidth}" if @linewidth
180
+ io += " linestyle #{@linestyle.index}" if @linestyle
181
+
182
+ io
183
+ end
184
+
185
+ def to_gplot
186
+ return nil if @data.nil? || @data.is_a?(String)
187
+
188
+ @data.to_gplot
189
+ end
190
+ end
191
+
192
+ class Array
193
+ def to_gplot
194
+ if number_series?(self)
195
+ series_for_plot = ''
196
+ self.each { |elem| series_for_plot += "#{elem}\n" }
197
+ series_for_plot + 'e'
198
+ else
199
+ self[0].zip(self[1]).map{ |elem| elem.join(' ') }.join("\n") + "\ne"
200
+ end
201
+ end
202
+
203
+ private
204
+
205
+ def number_series?(data)
206
+ data.each do |elem|
207
+ return false unless elem.is_a?(Numeric)
208
+ end
209
+
210
+ true
211
+ end
212
+ end
213
+
214
+ class Matrix
215
+ def to_gplot
216
+ matrix_for_plot = ''
217
+
218
+ (0...self.column_size).each do |j|
219
+ (0...self.row_size).each do |i|
220
+ matrix_for_plot += "#{i} #{j} #{self[j,i]}\n" if self[j,i]
221
+ end
222
+ end
223
+
224
+ matrix_for_plot
225
+ end
226
+ end
data/lib/grada.rb CHANGED
@@ -1,23 +1,23 @@
1
- require 'gnuplot'
1
+ require 'grada/gnuplot'
2
2
 
3
3
  class Grada
4
4
  # Not valid the format of the object to construct the graph
5
5
  #
6
6
  class NotValidArrayError < RuntimeError; end
7
-
7
+
8
8
  # Not valid the content of the array you're passing to build the graph
9
9
  #
10
10
  class NotValidDataError < RuntimeError; end
11
-
11
+
12
12
  # Can't build the plot
13
13
  #
14
14
  class NoPlotDataError < RuntimeError; end
15
-
15
+
16
16
  attr_reader :x
17
17
  attr_reader :y
18
-
19
- DEFAULT_OPTIONS = {width: 1600,
20
- height: 400,
18
+
19
+ DEFAULT_OPTIONS = {width: 1920,
20
+ height: 1080,
21
21
  title: "Graph",
22
22
  x_label: "X",
23
23
  y_label: "Y",
@@ -26,7 +26,7 @@ class Grada
26
26
 
27
27
  # Hello GraDA
28
28
  #
29
-
29
+
30
30
  def self.hi
31
31
  puts "Hello GraDA"
32
32
  end
@@ -45,11 +45,10 @@ class Grada
45
45
  # y: (Array) *optional*
46
46
 
47
47
  def initialize(x, y = nil)
48
-
49
48
  @x = validate(x)
50
49
  @y = y.nil? ? y : validate(y)
51
50
  end
52
-
51
+
53
52
  # Displays a graph in a window.
54
53
  # You can specify all the options that you need:
55
54
  # *width* (Integer)
@@ -68,7 +67,7 @@ class Grada
68
67
  # => ""
69
68
  # Arguments:
70
69
  # opts: (Hash) *optional*
71
-
70
+
72
71
  def display(opts = {})
73
72
  @opts = DEFAULT_OPTIONS.merge(opts)
74
73
 
@@ -91,7 +90,7 @@ class Grada
91
90
  end
92
91
  end
93
92
  end
94
-
93
+
95
94
  # Save the graph in a png file.
96
95
  # You can specify all the options that you need as _display_ but also need to specify the file
97
96
  #
@@ -111,7 +110,7 @@ class Grada
111
110
 
112
111
  plot_histogram do |plot|
113
112
  plot.output @opts[:filename]
114
- plot.set "terminal x11 size #{@opts[:width]},#{@opts[:height]}"
113
+ plot.set "terminal png size #{@opts[:width]}, #{@opts[:height]} crop"
115
114
  plot.terminal 'png'
116
115
  end
117
116
  elsif @opts[:graph_type] == :heatmap
@@ -120,6 +119,7 @@ class Grada
120
119
 
121
120
  plot_heat_map do |plot|
122
121
  plot.output @opts[:filename]
122
+ plot.set "terminal png size #{@opts[:width]}, #{@opts[:height]} crop"
123
123
  plot.terminal 'png'
124
124
  end
125
125
  else
@@ -127,7 +127,7 @@ class Grada
127
127
 
128
128
  plot_and do |plot|
129
129
  plot.output @opts[:filename]
130
- plot.set "terminal x11 size #{@opts[:width]*10},#{@opts[:height]}"
130
+ plot.set "terminal png size #{@opts[:width]}, #{@opts[:height]} crop"
131
131
  plot.terminal 'png'
132
132
  end
133
133
  end
@@ -137,7 +137,7 @@ class Grada
137
137
 
138
138
  def validate(l)
139
139
  raise NotValidArrayError if ! l.is_a?(Array)
140
-
140
+
141
141
  l.each do |elem|
142
142
  raise NotValidDataError if ! ( elem.is_a?(Float) || elem.is_a?(Integer) || elem.is_a?(Array) || elem.is_a?(Hash))
143
143
  end
@@ -145,7 +145,7 @@ class Grada
145
145
 
146
146
  def population_data?(l)
147
147
  raise NotValidArrayError if ! l.is_a?(Array)
148
-
148
+
149
149
  l.each do |elem|
150
150
  raise NotValidDataError if ! ( elem.is_a?(Float) || elem.is_a?(Integer))
151
151
  end
@@ -156,7 +156,7 @@ class Grada
156
156
  l.each do |elem|
157
157
  return false if ! elem.is_a?(Hash)
158
158
  end
159
-
159
+
160
160
  return true
161
161
  end
162
162
 
@@ -164,22 +164,22 @@ class Grada
164
164
  end
165
165
 
166
166
  def plot_and(&block)
167
- ::Gnuplot.open do |gp|
168
- ::Gnuplot::Plot.new(gp) do |plot|
167
+ Gnuplot.open do |gp|
168
+ Gnuplot::Plot.new(gp) do |plot|
169
169
  block[plot] if block
170
-
170
+
171
171
  plot.title @opts[:title]
172
172
 
173
173
  plot.xlabel @opts[:x_label]
174
174
  plot.ylabel @opts[:y_label]
175
-
175
+
176
176
  if multiple_data?(@y)
177
177
  @y.each do |dic|
178
178
  dic.each do |k, v|
179
179
  if k.to_sym != :with
180
180
  raise NoPlotDataError if ! v.nil? && @x.size != v.size
181
181
 
182
- plot.data << ::Gnuplot::DataSet.new([@x,v]) do |ds|
182
+ plot.data << Gnuplot::DataSet.new([@x,v]) do |ds|
183
183
  ds.with = dic[:with] || @opts[:with]
184
184
  ds.title = "#{k}"
185
185
  end
@@ -189,7 +189,7 @@ class Grada
189
189
  else
190
190
  raise NoPlotDataError if ! @y.nil? && @x.size != @y.size
191
191
 
192
- plot.data << ::Gnuplot::DataSet.new([@x,@y]) do |ds|
192
+ plot.data << Gnuplot::DataSet.new([@x,@y]) do |ds|
193
193
  ds.with = @opts[:with]
194
194
  end
195
195
  end
@@ -198,19 +198,19 @@ class Grada
198
198
  end
199
199
 
200
200
  def plot_histogram(&block)
201
- ::Gnuplot.open do |gp|
202
- ::Gnuplot::Plot.new(gp) do |plot|
201
+ Gnuplot.open do |gp|
202
+ Gnuplot::Plot.new(gp) do |plot|
203
203
  block[plot] if block
204
-
204
+
205
205
  plot.title @opts[:title]
206
206
 
207
207
  plot.set "style data histogram"
208
208
  plot.xlabel @opts[:x_label]
209
209
  plot.ylabel "Frecuency"
210
-
210
+
211
211
  x = @x.sort.group_by { |xi| xi }.map{|k,v| v.count }
212
212
 
213
- plot.data << ::Gnuplot::DataSet.new(x) do |ds|
213
+ plot.data << Gnuplot::DataSet.new(x) do |ds|
214
214
  ds.with = @opts[:with]
215
215
  end
216
216
  end
@@ -218,8 +218,8 @@ class Grada
218
218
  end
219
219
 
220
220
  def plot_heat_map(&block)
221
- ::Gnuplot.open do |gp|
222
- ::Gnuplot::Plot.new(gp) do |plot|
221
+ Gnuplot.open do |gp|
222
+ Gnuplot::Plot.new(gp) do |plot|
223
223
  block[plot] if block
224
224
 
225
225
  plot.set "pm3d map"
@@ -232,9 +232,9 @@ class Grada
232
232
  plot.set "palette define"
233
233
 
234
234
  plot.title @opts[:title]
235
- plot.data = [::Gnuplot::DataSet.new(Matrix.columns(@x)) do |ds|
235
+ plot.data << Gnuplot::DataSet.new(Matrix.columns(@x)) do |ds|
236
236
  ds.with = @opts[:with]
237
- end]
237
+ end
238
238
  end
239
239
  end
240
240
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grada
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 2.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -43,22 +43,6 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: gnuplot
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: 2.6.2
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: 2.6.2
62
46
  description: Graphic Data Analysis gem
63
47
  email: hard_rock15@msn.com
64
48
  executables: []
@@ -66,6 +50,7 @@ extensions: []
66
50
  extra_rdoc_files: []
67
51
  files:
68
52
  - lib/grada.rb
53
+ - lib/grada/gnuplot.rb
69
54
  homepage: https://github.com/emfigo/grada
70
55
  licenses: []
71
56
  post_install_message: