grada 2.2.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,297 +1,3 @@
1
1
  $:.unshift File.expand_path('..', __FILE__)
2
2
 
3
- require_relative 'grada/gnuplot'
4
-
5
- class Grada
6
- # Not valid the format of the object to construct the graph
7
- #
8
- class NotValidArrayError < RuntimeError; end
9
-
10
- # Not valid the content of the array you're passing to build the graph
11
- #
12
- class NotValidDataError < RuntimeError; end
13
-
14
- # Can't build the plot
15
- #
16
- class NoPlotDataError < RuntimeError; end
17
-
18
- attr_reader :x
19
- attr_reader :y
20
-
21
- DEFAULT_OPTIONS = {width: 1920,
22
- height: 1080,
23
- title: "Graph",
24
- x_label: "X",
25
- y_label: "Y",
26
- with: 'lines',
27
- graph_type: :default}
28
-
29
- #All styles you can specify for the plots
30
- #
31
- STYLES = [:linestyle, :linetype, :linewidth, :linecolor, :pointtype, :pointsize, :fill]
32
-
33
- #Graph offsets
34
- #
35
- LEFT = 0.05
36
- RIGHT = 0.05
37
- TOP = 0.05
38
- BOTTOM = 0.05
39
-
40
- # Hello GraDA
41
- #
42
-
43
- def self.hi
44
- puts "Hello GraDA"
45
- end
46
-
47
- # Initialize object with the data you want to plot.
48
- # It can vary depending on the type of graph.
49
- # The second argument is optional.
50
- #
51
- # Example:
52
- # >> radiation_levels_median_per_day = [0.001,0.01,1,10,1000]
53
- # >> radiation_days = [0,1,2,3,4]
54
- # >> grada = Grada.new(radiation_days, radiation_levels_median_per_day)
55
- # => #<Grada:0x007f962a8dc9b8 @x=[0, 1, 2, 3, 4], @y=[0.001, 0.01, 1, 10, 1000]>
56
- # Arguments:
57
- # x: (Array)
58
- # y: (Array) *optional*
59
-
60
- def initialize(x, y = nil)
61
- @x = validate(x)
62
- @y = y.nil? ? y : validate(y)
63
- end
64
-
65
- # Displays a graph in a X11 window.
66
- # You can specify all the options that you need:
67
- # *width* (Integer)
68
- # *height* (Integer)
69
- # *title* (Integer)
70
- # *x_label* (String)
71
- # *y_label* (String)
72
- # *graph_type* (:histogram, :heatmap) default: :default
73
- # *with* ('points', 'linespoints') default: 'lines'
74
- #
75
- # Also is important to know that you can interact with the graph:
76
- # * Zoom in => right click and drag the mouse to cover the area you want
77
- # or
78
- # use the scroll wheel
79
- #
80
- # * Zoom out => press key 'a'
81
- # or
82
- # if you want to go back to a previous state of zoom press key 'p'
83
- #
84
- # * Exit interactive mode => press key 'q'
85
- # or
86
- # just close the window
87
- #
88
- # * Save image => working on it
89
- #
90
- # Example:
91
- # >> grada.display
92
- # => ""
93
- # >> grada.display({ title: 'Atomic Device X', x_label: 'Day', y_label: 'smSv', with: 'points' })
94
- # => ""
95
- # Arguments:
96
- # opts: (Hash) *optional*
97
-
98
- def display(opts = {})
99
- @opts = DEFAULT_OPTIONS.merge(opts)
100
-
101
- if @opts[:graph_type] == :histogram
102
- population_data?(@x)
103
- return nil if @x.empty?
104
-
105
- plot_histogram do |plot|
106
- plot.set "terminal x11 size #{@opts[:width]},#{@opts[:height]}"
107
- plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
108
- end
109
- elsif @opts[:graph_type] == :heatmap
110
- Matrix.columns(@x) rescue raise NoPlotDataError
111
- @opts[:with] = 'image'
112
-
113
- plot_heat_map do |plot|
114
- plot.set "terminal x11 size #{@opts[:width]},#{@opts[:height]}"
115
- plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
116
- end
117
- else
118
- raise NoPlotDataError if @y.nil?
119
-
120
- plot_and do |plot|
121
- plot.set "terminal x11 size #{@opts[:width]},#{@opts[:height]}"
122
- plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
123
- end
124
- end
125
- end
126
-
127
- # Save the graph in a png file.
128
- # You can specify all the options that you need as _display_ but also need to specify the file root-name and extension.
129
- # The possible extensions you can use for saving a file are:
130
- # *png*
131
- # *gif*
132
- # *jpeg*
133
- # *svg* => default
134
- #
135
- # Example:
136
- # >> grada.save({ filename: 'secret/radiation_levels/ffa/zonex/devicex/radiation_level_malaga', ext: 'png' ,title: 'Atomic Device X', x_label: 'Day', y_label: 'smSv', with: 'points' })
137
- # => ""
138
- # Arguments:
139
- # opts: (Hash) *optional*
140
-
141
- def save(opts = {})
142
- @opts = DEFAULT_OPTIONS.merge(opts)
143
-
144
- return nil if @opts[:filename].nil?
145
-
146
- ext = @opts[:ext] || 'svg'
147
-
148
- if @opts[:graph_type] == :histogram
149
- population_data?(@x)
150
- return nil if @x.empty?
151
-
152
- plot_histogram do |plot|
153
- plot.output "#{@opts[:filename]}.#{ext}"
154
- plot.set "terminal #{ext} size #{@opts[:width]}, #{@opts[:height]} crop"
155
- plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
156
- end
157
- elsif @opts[:graph_type] == :heatmap
158
- Matrix.columns(@x) rescue raise NoPlotDataError
159
- @opts[:with] = 'image'
160
-
161
- plot_heat_map do |plot|
162
- plot.output "#{@opts[:filename]}.#{ext}"
163
- plot.set "terminal #{ext} size #{@opts[:width]}, #{@opts[:height]} crop"
164
- end
165
- else
166
- raise NoPlotDataError if @y.nil?
167
-
168
- plot_and do |plot|
169
- plot.output "#{@opts[:filename]}.#{ext}"
170
- plot.set "terminal #{ext} size #{@opts[:width]}, #{@opts[:height]} crop"
171
- plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
172
- end
173
- end
174
- end
175
-
176
- private
177
-
178
- def validate(l)
179
- raise NotValidArrayError if ! l.is_a?(Array)
180
-
181
- l.each do |elem|
182
- raise NotValidDataError if ! ( elem.is_a?(Float) || elem.is_a?(Integer) || elem.is_a?(Array) || elem.is_a?(Hash))
183
- end
184
- end
185
-
186
- def population_data?(l)
187
- raise NotValidArrayError if ! l.is_a?(Array)
188
-
189
- l.each do |elem|
190
- raise NotValidDataError if ! ( elem.is_a?(Float) || elem.is_a?(Integer))
191
- end
192
- end
193
-
194
- def multiple_data?(l)
195
- if l.is_a?(Array)
196
- l.each do |elem|
197
- return false if ! elem.is_a?(Hash)
198
- end
199
-
200
- return true
201
- end
202
-
203
- false
204
- end
205
-
206
- def plot_and(&block)
207
- Gnuplot.open do
208
- Gnuplot::Plot.construct do |plot|
209
- block.call plot if block
210
-
211
- plot.title @opts[:title]
212
-
213
- plot.xlabel @opts[:x_label]
214
- plot.ylabel @opts[:y_label]
215
-
216
- if multiple_data?(@y)
217
- @y.each_with_index do |dic, index|
218
- dic.each do |k, v|
219
- if ! STYLES.include?(k.to_sym) && k.to_sym != :with
220
- raise NoPlotDataError if ! v.nil? && @x.size != v.size
221
-
222
- style = Gnuplot::Style.new do |ds|
223
- ds.index = index
224
- STYLES.each do |style|
225
- ds.send("#{style}=", dic[style]) if dic[style]
226
- end
227
- end.to_s
228
-
229
- plot.data << Gnuplot::DataSet.new([@x,v]) do |ds|
230
- ds.with = dic[:with] || @opts[:with]
231
- ds.with += style
232
- ds.title = "#{k}"
233
- end
234
- end
235
- end
236
- end
237
- else
238
- raise NoPlotDataError if ! @y.nil? && @x.size != @y.size
239
-
240
- plot.data << Gnuplot::DataSet.new([@x,@y]) do |ds|
241
- ds.with = @opts[:with]
242
- end
243
- end
244
- end
245
- end
246
- end
247
-
248
- def plot_histogram(&block)
249
- Gnuplot.open do
250
- Gnuplot::Plot.construct do |plot|
251
- block.call plot if block
252
-
253
- width = ( @x.max - @x.min ) / @x.size
254
-
255
- plot.title @opts[:title]
256
-
257
- plot.set "style data histogram"
258
- plot.xlabel @opts[:x_label]
259
- plot.ylabel "Frequency"
260
- plot.set "style fill solid 0.5"
261
- plot.set "xrange [#{@x.min}:#{@x.max}]"
262
- plot.set "boxwidth #{ width * 0.1}"
263
- plot.set "xtics #{@x.min},#{(@x.max-@x.min)/5},#{@x.max}"
264
- plot.set "tics out nomirror"
265
-
266
- plot.data << Gnuplot::DataSet.new(@x) do |ds|
267
- ds.with = 'boxes'
268
- ds.title = @opts[:x_label]
269
- ds.using = '($1):(1.0)'
270
- ds.smooth = 'freq'
271
- end
272
- end
273
- end
274
- end
275
-
276
- def plot_heat_map(&block)
277
- Gnuplot.open do
278
- Gnuplot::Plot.construct do |plot|
279
- block.call plot if block
280
-
281
- plot.set "pm3d map"
282
- plot.set "palette color"
283
- plot.set "xrange [0:#{@x.size-1}]"
284
- plot.set "yrange [0:#{@x.size-1}]"
285
- plot.set "cbrange [#{@opts[:min]}:#{@opts[:max]}]"
286
- plot.set "cblabel \"#{@opts[:x_label]}\""
287
- plot.set "palette model RGB"
288
- plot.set "palette define"
289
-
290
- plot.title @opts[:title]
291
- plot.data << Gnuplot::DataSet.new(Matrix.columns(@x)) do |ds|
292
- ds.with = @opts[:with]
293
- end
294
- end
295
- end
296
- end
297
- end
3
+ require 'grada/graph'
@@ -0,0 +1,200 @@
1
+ require 'grada/types/default_base'
2
+ require 'grada/types/gnuplot'
3
+ require 'grada/types/histogram'
4
+ require 'grada/types/default'
5
+ require 'grada/types/heat_map'
6
+
7
+ module Grada
8
+ class Graph
9
+ # Not valid the format of the object to construct the graph
10
+ #
11
+ class NotValidArrayError < RuntimeError; end
12
+
13
+ # Not valid the content of the array you're passing to build the graph
14
+ #
15
+ class NotValidDataError < RuntimeError; end
16
+
17
+ # Can't build the plot
18
+ #
19
+ class NoPlotDataError < RuntimeError; end
20
+
21
+ attr_reader :x
22
+ attr_reader :y
23
+
24
+ DEFAULT_OPTIONS = {width: 1920,
25
+ height: 1080,
26
+ title: "Graph",
27
+ x_label: "X",
28
+ y_label: "Y",
29
+ with: 'lines',
30
+ graph_type: :default}
31
+
32
+ #Graph offsets
33
+ #
34
+ LEFT = 0.05
35
+ RIGHT = 0.05
36
+ TOP = 0.05
37
+ BOTTOM = 0.05
38
+
39
+ # Hello GraDA
40
+ #
41
+
42
+ def self.hi
43
+ puts "Hello GraDA"
44
+ end
45
+
46
+ # Initialize object with the data you want to plot.
47
+ # It can vary depending on the type of graph.
48
+ # The second argument is optional.
49
+ #
50
+ # Example:
51
+ # >> radiation_levels_median_per_day = [0.001,0.01,1,10,1000]
52
+ # >> radiation_days = [0,1,2,3,4]
53
+ # >> grada = Grada.new(radiation_days, radiation_levels_median_per_day)
54
+ # => #<Grada:0x007f962a8dc9b8 @x=[0, 1, 2, 3, 4], @y=[0.001, 0.01, 1, 10, 1000]>
55
+ # Arguments:
56
+ # x: (Array)
57
+ # y: (Array) *optional*
58
+
59
+ def initialize(x, y = nil)
60
+ @x = validate(x)
61
+ @y = y.nil? ? y : validate(y)
62
+ end
63
+
64
+ # Displays a graph in a X11 window.
65
+ # You can specify all the options that you need:
66
+ # *width* (Integer)
67
+ # *height* (Integer)
68
+ # *title* (Integer)
69
+ # *x_label* (String)
70
+ # *y_label* (String)
71
+ # *graph_type* (:histogram, :heatmap) default: :default
72
+ # *with* ('points', 'linespoints') default: 'lines'
73
+ #
74
+ # Also is important to know that you can interact with the graph:
75
+ # * Zoom in => right click and drag the mouse to cover the area you want
76
+ # or
77
+ # use the scroll wheel
78
+ #
79
+ # * Zoom out => press key 'a'
80
+ # or
81
+ # if you want to go back to a previous state of zoom press key 'p'
82
+ #
83
+ # * Exit interactive mode => press key 'q'
84
+ # or
85
+ # just close the window
86
+ #
87
+ # * Save image => working on it
88
+ #
89
+ # Example:
90
+ # >> grada.display
91
+ # => ""
92
+ # >> grada.display({ title: 'Atomic Device X', x_label: 'Day', y_label: 'smSv', with: 'points' })
93
+ # => ""
94
+ # Arguments:
95
+ # opts: (Hash) *optional*
96
+
97
+ def display(opts = {})
98
+ @opts = DEFAULT_OPTIONS.merge(opts)
99
+
100
+ if @opts[:graph_type] == :histogram
101
+ population_data?(@x)
102
+ return nil if @x.empty?
103
+
104
+ Histogram.plot(@x, @opts) do |plot|
105
+ plot.set "terminal x11 size #{@opts[:width]},#{@opts[:height]}"
106
+ plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
107
+ end
108
+ elsif @opts[:graph_type] == :heatmap
109
+ Matrix.columns(@x) rescue raise NoPlotDataError
110
+ @opts[:with] = 'image'
111
+
112
+ HeatMap.plot(@x, @opts) do |plot|
113
+ plot.set "terminal x11 size #{@opts[:width]},#{@opts[:height]}"
114
+ plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
115
+ end
116
+ else
117
+ raise NoPlotDataError if @y.nil?
118
+
119
+ Default.plot(@x, @y, @opts) do |plot|
120
+ plot.set "terminal x11 size #{@opts[:width]},#{@opts[:height]}"
121
+ plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
122
+ end
123
+ end
124
+ end
125
+
126
+ # Save the graph in a png file.
127
+ # You can specify all the options that you need as _display_ but also need to specify the file root-name and extension.
128
+ # The possible extensions you can use for saving a file are:
129
+ # *png*
130
+ # *gif*
131
+ # *jpeg*
132
+ # *html* (not valid for heatmaps)
133
+ # *svg* => default (not valid for heatmaps)
134
+ #
135
+ # Example:
136
+ # >> grada.save({ filename: 'secret/radiation_levels/ffa/zonex/devicex/radiation_level_malaga', ext: 'png' ,title: 'Atomic Device X', x_label: 'Day', y_label: 'smSv', with: 'points' })
137
+ # => ""
138
+ # Arguments:
139
+ # opts: (Hash) *optional*
140
+
141
+ def save(opts = {})
142
+ @opts = DEFAULT_OPTIONS.merge(opts)
143
+
144
+ return nil if @opts[:filename].nil?
145
+
146
+ ext = @opts[:ext] || 'svg'
147
+
148
+ if @opts[:graph_type] == :histogram
149
+ population_data?(@x)
150
+ return nil if @x.empty?
151
+
152
+ return Histogram.plot_html(@x, @opts) if ext == 'html'
153
+
154
+ Histogram.plot(@x, @opts) do |plot|
155
+ plot.output "#{@opts[:filename]}.#{ext}"
156
+ plot.set "terminal #{ext} size #{@opts[:width]}, #{@opts[:height]} crop"
157
+ plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
158
+ end
159
+ elsif @opts[:graph_type] == :heatmap
160
+ Matrix.columns(@x) rescue raise NoPlotDataError
161
+ @opts[:with] = 'image'
162
+
163
+ ext = 'png' if ext == 'html' || ext == 'svg'
164
+
165
+ HeatMap.plot(@x, @opts) do |plot|
166
+ plot.output "#{@opts[:filename]}.#{ext}"
167
+ plot.set "terminal #{ext} size #{@opts[:width]}, #{@opts[:height]} crop"
168
+ end
169
+ else
170
+ raise NoPlotDataError if @y.nil?
171
+
172
+ return Default.plot_html(@x, @y, @opts) if ext == 'html'
173
+
174
+ Default.plot(@x, @y, @opts) do |plot|
175
+ plot.output "#{@opts[:filename]}.#{ext}"
176
+ plot.set "terminal #{ext} size #{@opts[:width]}, #{@opts[:height]} crop"
177
+ plot.set "offset graph #{LEFT},#{RIGHT},#{TOP},#{BOTTOM}"
178
+ end
179
+ end
180
+ end
181
+
182
+ private
183
+
184
+ def validate(l)
185
+ raise NotValidArrayError if ! l.is_a?(Array)
186
+
187
+ l.each do |elem|
188
+ raise NotValidDataError if ! ( elem.is_a?(Float) || elem.is_a?(Integer) || elem.is_a?(Array) || elem.is_a?(Hash))
189
+ end
190
+ end
191
+
192
+ def population_data?(l)
193
+ raise NotValidArrayError if ! l.is_a?(Array)
194
+
195
+ l.each do |elem|
196
+ raise NotValidDataError if ! ( elem.is_a?(Float) || elem.is_a?(Integer))
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,62 @@
1
+ module Grada
2
+ class Default < DefaultBase
3
+ def self.plot(x, y, opts, &block)
4
+ Gnuplot.open do
5
+ Gnuplot::Plot.construct do |plot|
6
+ block.call plot if block
7
+
8
+ plot.title opts[:title]
9
+
10
+ plot.xlabel opts[:x_label]
11
+ plot.ylabel opts[:y_label]
12
+
13
+ if multiple_data?(y)
14
+ y.each_with_index do |dic, index|
15
+ dic.each do |k, v|
16
+ if ! Grada::STYLES.include?(k.to_sym) && k.to_sym != :with
17
+ raise NoPlotDataError if ! v.nil? && x.size != v.size
18
+
19
+ style = Gnuplot::Style.new do |ds|
20
+ ds.index = index
21
+ Grada::STYLES.each do |style|
22
+ ds.send("#{style}=", dic[style]) if dic[style]
23
+ end
24
+ end.to_s
25
+
26
+ plot.data << Gnuplot::DataSet.new([x,v]) do |ds|
27
+ ds.with = dic[:with] || opts[:with]
28
+ ds.with += style
29
+ ds.title = "#{k}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ else
35
+ raise NoPlotDataError if ! y.nil? && x.size != y.size
36
+
37
+ plot.data << Gnuplot::DataSet.new([x,y]) do |ds|
38
+ ds.with = opts[:with]
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ def self.plot_html(x, y, opts)
46
+ opts[:filename] = create_html_dir(opts[:filename])
47
+
48
+ create_grada_json(opts, x, y)
49
+
50
+ File.open("#{opts[:filename]}.html",'w') do |f|
51
+ f << html_head
52
+ f << "<body>\n"
53
+ f << " <div class=grada_main>\n"
54
+ f << html_title(opts[:title])
55
+ f << html_graph
56
+ f << html_panel
57
+ f << " </div>"
58
+ f << "</body>"
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,123 @@
1
+ require 'json'
2
+
3
+ module Grada
4
+ #All styles you can specify for the plots
5
+ #
6
+ STYLES = [:linestyle, :linetype, :linewidth, :linecolor, :pointtype, :pointsize, :fill]
7
+
8
+ class DefaultBase
9
+
10
+ protected
11
+
12
+ JQUERY_JS = 'https://rawgithub.com/emfigo/flot/master/jquery.js'
13
+ FLOT_EXCANVAS_JS = 'https://rawgithub.com/emfigo/flot/master/excanvas.min.js'
14
+ FLOT_JS = 'https://rawgithub.com/emfigo/flot/master/jquery.flot.js'
15
+ FLOT_SELECTION_JS = 'https://rawgithub.com/emfigo/flot/master/jquery.flot.selection.js'
16
+ FLOT_SYMBOL_JS = 'https://rawgithub.com/emfigo/flot/master/jquery.flot.symbol.js'
17
+ FLOT_THRESHOLD_JS = 'https://rawgithub.com/emfigo/flot/master/jquery.flot.threshold.js'
18
+ GRADA_JS = 'https://rawgithub.com/emfigo/grada/master/assets/javascripts/grada.js'
19
+
20
+ TITLE_CSS = 'https://rawgithub.com/emfigo/grada/master/assets/stylesheets/grada_title.css'
21
+ BODY_CSS = 'https://rawgithub.com/emfigo/grada/master/assets/stylesheets/grada_body.css'
22
+
23
+ def self.multiple_data?(l)
24
+ if l.is_a?(Array)
25
+ l.each do |elem|
26
+ return false if ! elem.is_a?(Hash)
27
+ end
28
+
29
+ return true
30
+ end
31
+
32
+ false
33
+ end
34
+
35
+ def self.create_html_dir(path)
36
+ path.split("/").tap do |dirs|
37
+ last_dir = dirs.pop
38
+
39
+ dirs << "#{last_dir}_grada_html"
40
+ FileUtils.mkdir_p(dirs.join("/"))
41
+ dirs << last_dir
42
+ end.join('/')
43
+ end
44
+
45
+ def self.create_grada_json(opts, x, y = nil)
46
+ filename = opts[:filename].split("/").tap do |file|
47
+ hidden_file = file.pop
48
+
49
+ file << ".grada_#{opts[:graph_type]}"
50
+ end.join("/")
51
+
52
+
53
+ File.open("#{filename}.json",'w') do |f|
54
+ f << generate_grada_json(opts, x, y)
55
+ end
56
+ end
57
+
58
+ def self.html_head
59
+ "<head>
60
+ <script src='#{JQUERY_JS}' type='text/javascript'></script>
61
+ <script src='#{FLOT_EXCANVAS_JS}' type='text/javascript'></script>
62
+ <script src='#{FLOT_JS}' type='text/javascript'></script>
63
+ <script src='#{FLOT_SELECTION_JS}' type='text/javascript'></script>
64
+ <script src='#{FLOT_SYMBOL_JS}' type='text/javascript'></script>
65
+ <script src='#{FLOT_THRESHOLD_JS}' type='text/javascript'></script>
66
+ <script src='#{GRADA_JS}' type='text/javascript'></script>
67
+
68
+ <link href='#{TITLE_CSS}' rel='stylesheet' type='text/css' />
69
+ <link href='#{BODY_CSS}' rel='stylesheet' type='text/css' />
70
+ </head>\n"
71
+ end
72
+
73
+ def self.html_title(title)
74
+ " <div class='grada_title'>
75
+ <h2>#{title}</h2>
76
+ </div>\n"
77
+ end
78
+
79
+ def self.html_graph
80
+ " <div class='grada_body'>
81
+ <div id='grada_graph'></div>
82
+ </div>\n"
83
+ end
84
+
85
+ def self.html_panel
86
+ " <div class='grada_panel'>
87
+ <span id='reset'>Reset Zoom</span>
88
+ </div>\n"
89
+ end
90
+
91
+ private
92
+
93
+ def self.compose_grada_json_data(x, y)
94
+ if y.nil?
95
+ x.sort.group_by{ |elem| elem }.map{ |k,v| { x: k, y: v.size } }
96
+ else
97
+ x.zip(y).map do |comp|
98
+ { x: comp.first, y: comp.last }
99
+ end
100
+ end
101
+ end
102
+
103
+ def self.generate_grada_json(opts, x, y = nil)
104
+ json = []
105
+
106
+ if multiple_data?(y)
107
+ y.each do |dic|
108
+ dic.each do |k, v|
109
+ if ! Grada::STYLES.include?(k.to_sym) && k.to_sym != :with
110
+ raise NoPlotDataError if ! v.nil? && x.size != v.size
111
+
112
+ json << { data: compose_grada_json_data(x, v), label: "#{k}", style: dic[:with] || opts[:with] }
113
+ end
114
+ end
115
+ end
116
+ else
117
+ json << { data: compose_grada_json_data(x, y), label: opts[:title], style: opts[:with] }
118
+ end
119
+
120
+ JSON.pretty_generate(json)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,246 @@
1
+ require 'matrix'
2
+ require 'open3'
3
+
4
+ module Grada
5
+ class NoGnuPlotExecutableFound < RuntimeError; end
6
+
7
+ class Gnuplot
8
+ def self.candidate?(candidate)
9
+ return candidate if File::executable? candidate
10
+
11
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
12
+ possible_candidate = File::join dir, candidate.strip
13
+
14
+ return possible_candidate if File::executable? possible_candidate
15
+ end
16
+
17
+ nil
18
+ end
19
+
20
+ def self.find_exec(bin)
21
+ bin_list = RUBY_PLATFORM =~ /mswin|mingw/ ? [bin, "#{bin}.exe"] : [bin]
22
+
23
+ bin_list.each do |c|
24
+ exec = candidate?(c)
25
+ return exec if exec
26
+ end
27
+
28
+ nil
29
+ end
30
+
31
+ def self.gnuplot
32
+ gnu_exec = find_exec( ENV['RB_GNUPLOT'] || 'gnuplot' )
33
+ raise Grada::NoGnuPlotExecutableFound unless gnu_exec
34
+ gnu_exec
35
+ end
36
+
37
+ def self.open(persist = true, &block)
38
+ gnuplot_cmd = gnuplot
39
+
40
+ commands = yield
41
+
42
+ output = StringIO.new
43
+ Open3::popen3(gnuplot_cmd, '-persist') do |data_in, data_out, stderr, wait_th|
44
+ data_in << commands[:plot_settings]
45
+ data_in << commands[:plot_data]
46
+
47
+ data_in.flush
48
+ sleep 1
49
+
50
+ while true do
51
+ window = IO::popen('xprop -name "Gnuplot" WM_NAME 2>/dev/null').gets
52
+ break unless window
53
+ sleep 1
54
+ end
55
+ data_in.close
56
+ data_out.close
57
+ stderr.close
58
+
59
+ output.write(wait_th.value.exitstatus)
60
+ end
61
+
62
+ output.string
63
+ end
64
+ end
65
+
66
+ class Gnuplot::Plot
67
+ attr_accessor :cmd, :data, :settings, :styles, :arbitrary_lines
68
+
69
+ QUOTED_METHODS = [ "title", "output", "xlabel", "x2label", "ylabel", "y2label", "clabel", "cblabel", "zlabel" ]
70
+
71
+ def initialize
72
+ @settings = []
73
+ @arbitrary_lines = []
74
+ @data = []
75
+ @styles = []
76
+ end
77
+
78
+ def self.construct(&block)
79
+ plot = new
80
+
81
+ block.call plot if block_given?
82
+
83
+ { plot_settings: plot.to_gplot, plot_data: plot.store_datasets }
84
+ end
85
+
86
+ def method_missing(meth, *args)
87
+ set meth.id2name, *args
88
+ end
89
+
90
+ def set ( var, value = "" )
91
+ value = "\"#{value}\"" if QUOTED_METHODS.include? var unless value =~ /^'.*'$/
92
+ @settings << [ :set, var, value ]
93
+ end
94
+
95
+ def unset (var)
96
+ @settings << [ :unset, var ]
97
+ end
98
+
99
+ def to_gplot(io = '')
100
+ @settings.each { |setting| io += setting.map(&:to_s).join(' ') + "\n" }
101
+ @styles.each{ |style| io += style.to_s + "\n" }
102
+ @arbitrary_lines.each{ |line| io += line + "\n" }
103
+
104
+ io
105
+ end
106
+
107
+ def store_datasets(io = '')
108
+ if @data.size > 0
109
+ io += 'plot' + " #{ @data.map { |element| element.plot_args }.join(', ') } \n"
110
+ io += @data.map { |ds| ds.to_gplot }.compact.join("\n") + "\n"
111
+ end
112
+
113
+ io
114
+ end
115
+ end
116
+
117
+ class Gnuplot::Style
118
+ attr_accessor :linestyle, :linetype, :linewidth, :linecolor, :pointtype, :pointsize, :fill, :index
119
+
120
+ alias :ls :linestyle
121
+ alias :lt :linetype
122
+ alias :lw :linewidth
123
+ alias :lc :linecolor
124
+ alias :pt :pointtype
125
+ alias :ps :pointsize
126
+ alias :fs :fill
127
+
128
+ alias :ls= :linestyle=
129
+ alias :lt= :linetype=
130
+ alias :lw= :linewidth=
131
+ alias :lc= :linecolor=
132
+ alias :pt= :pointtype=
133
+ alias :ps= :pointsize=
134
+ alias :fs= :fill=
135
+
136
+ STYLES = [:ls, :lt, :lw, :lc, :pt, :ps, :fs]
137
+
138
+ def self.increment_index
139
+ @index ||= 0
140
+ @index += 1
141
+ end
142
+
143
+ def initialize
144
+ STYLES.each do |style|
145
+ send("#{style}=", nil)
146
+ end
147
+
148
+ yield self if block_given?
149
+
150
+ end
151
+
152
+ def to_s
153
+ str = ' '
154
+
155
+ STYLES.each do |style|
156
+ str += " #{style} #{send(style)}" if send(style)
157
+ end
158
+
159
+ str == ' ' ? '' : str
160
+ end
161
+ end
162
+
163
+ class Gnuplot::DataSet
164
+ attr_accessor :title, :with, :using, :data, :linewidth, :linecolor, :matrix, :smooth, :axes, :index, :linestyle
165
+
166
+ alias :ls :linestyle
167
+
168
+ def initialize(data = nil)
169
+ @data = data
170
+ @linestyle = nil
171
+ @title = nil
172
+ @with = nil
173
+ @using = nil
174
+ @linewidth = nil
175
+ @linecolor = nil
176
+ @matrix = nil
177
+ @smooth = nil
178
+ @axes = nil
179
+ @index = nil
180
+
181
+ yield self if block_given?
182
+ end
183
+
184
+ def notitle
185
+ '"No Title"'
186
+ end
187
+
188
+ def plot_args(io = '')
189
+ io += @data.is_a?(String) ? @data : "'-'"
190
+ #io += " index #{@index}" if @index
191
+ io += " using #{@using}" if @using
192
+ io += " axes #{@axes}" if @axes
193
+ io += " title #{@title ? "\"#{@title}\"" : notitle}"
194
+ io += " matrix #{@matrix}" if @matrix
195
+ io += " smooth #{@smooth}" if @smooth
196
+ io += " with #{@with}" if @with
197
+ io += " linecolor #{@linecolor}" if @linecolor
198
+ io += " line #{@index} linewidth #{@linewidth}" if @linewidth
199
+ io += " linestyle #{@linestyle.index}" if @linestyle
200
+
201
+ io
202
+ end
203
+
204
+ def to_gplot
205
+ return nil if @data.nil? || @data.is_a?(String)
206
+
207
+ @data.to_gplot
208
+ end
209
+ end
210
+ end
211
+
212
+ class Array
213
+ def to_gplot
214
+ if number_series?(self)
215
+ series_for_plot = ''
216
+ self.each { |elem| series_for_plot += "#{elem}\n" }
217
+ series_for_plot + 'e'
218
+ else
219
+ self[0].zip(self[1]).map{ |elem| elem.join(' ') }.join("\n") + "\ne\n"
220
+ end
221
+ end
222
+
223
+ private
224
+
225
+ def number_series?(data)
226
+ data.each do |elem|
227
+ return false unless elem.is_a?(Numeric)
228
+ end
229
+
230
+ true
231
+ end
232
+ end
233
+
234
+ class Matrix
235
+ def to_gplot
236
+ matrix_for_plot = ''
237
+
238
+ (0...self.column_size).each do |j|
239
+ (0...self.row_size).each do |i|
240
+ matrix_for_plot += "#{i} #{j} #{self[j,i]}\n" if self[j,i]
241
+ end
242
+ end
243
+
244
+ matrix_for_plot
245
+ end
246
+ end
@@ -0,0 +1,25 @@
1
+ module Grada
2
+ class HeatMap
3
+ def self.plot(x, opts, &block)
4
+ Gnuplot.open do
5
+ Gnuplot::Plot.construct do |plot|
6
+ block.call plot if block
7
+
8
+ plot.set "pm3d map"
9
+ plot.set "palette color"
10
+ plot.set "xrange [0:#{x.size-1}]"
11
+ plot.set "yrange [0:#{x.size-1}]"
12
+ plot.set "cbrange [#{opts[:min]}:#{opts[:max]}]"
13
+ plot.set "cblabel \"#{opts[:x_label]}\""
14
+ plot.set "palette model RGB"
15
+ plot.set "palette define"
16
+
17
+ plot.title opts[:title]
18
+ plot.data << Gnuplot::DataSet.new(Matrix.columns(x)) do |ds|
19
+ ds.with = opts[:with]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ module Grada
2
+ class Histogram < DefaultBase
3
+ def self.plot(x, opts, &block)
4
+ Gnuplot.open do
5
+ Gnuplot::Plot.construct do |plot|
6
+ block.call plot if block
7
+
8
+ width = ( x.max - x.min ) / x.size
9
+
10
+ plot.title opts[:title]
11
+
12
+ plot.set "style data histogram"
13
+ plot.xlabel opts[:x_label]
14
+ plot.ylabel "Frequency"
15
+ plot.set "style fill solid 0.5"
16
+ plot.set "xrange [#{x.min}:#{x.max}]"
17
+ plot.set "boxwidth #{ width * 0.1}"
18
+ plot.set "xtics #{x.min},#{(x.max-x.min)/5},#{x.max}"
19
+ plot.set "tics out nomirror"
20
+
21
+ plot.data << Gnuplot::DataSet.new(x) do |ds|
22
+ ds.with = 'boxes'
23
+ ds.title = opts[:x_label]
24
+ ds.using = '($1):(1.0)'
25
+ ds.smooth = 'freq'
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.plot_html(x, opts)
32
+ opts[:filename] = create_html_dir(opts[:filename])
33
+
34
+ create_grada_json(opts, x)
35
+
36
+ File.open("#{opts[:filename]}.html",'w') do |f|
37
+ f << html_head
38
+ f << "<body>\n"
39
+ f << " <div class=grada_main>\n"
40
+ f << html_title(opts[:title])
41
+ f << html_graph
42
+ f << html_panel
43
+ f << " </div>"
44
+ f << "</body>"
45
+ end
46
+ end
47
+ end
48
+ 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: 2.2.2
4
+ version: 3.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-20 00:00:00.000000000 Z
12
+ date: 2013-08-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -50,7 +50,12 @@ extensions: []
50
50
  extra_rdoc_files: []
51
51
  files:
52
52
  - lib/grada.rb
53
- - lib/grada/gnuplot.rb
53
+ - lib/grada/graph.rb
54
+ - lib/grada/types/default_base.rb
55
+ - lib/grada/types/default.rb
56
+ - lib/grada/types/gnuplot.rb
57
+ - lib/grada/types/heat_map.rb
58
+ - lib/grada/types/histogram.rb
54
59
  homepage: https://github.com/emfigo/grada
55
60
  licenses:
56
61
  - MIT
@@ -1,244 +0,0 @@
1
- require 'matrix'
2
- require 'open3'
3
-
4
- class NoGnuPlotExecutableFound < RuntimeError; end
5
-
6
- class Gnuplot
7
- def self.candidate?(candidate)
8
- return candidate if File::executable? candidate
9
-
10
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
11
- possible_candidate = File::join dir, candidate.strip
12
-
13
- return possible_candidate if File::executable? possible_candidate
14
- end
15
-
16
- nil
17
- end
18
-
19
- def self.find_exec(bin)
20
- bin_list = RUBY_PLATFORM =~ /mswin|mingw/ ? [bin, "#{bin}.exe"] : [bin]
21
-
22
- bin_list.each do |c|
23
- exec = candidate?(c)
24
- return exec if exec
25
- end
26
-
27
- nil
28
- end
29
-
30
- def self.gnuplot
31
- gnu_exec = find_exec( ENV['RB_GNUPLOT'] || 'gnuplot' )
32
- raise NoGnuPlotExecutableFound unless gnu_exec
33
- gnu_exec
34
- end
35
-
36
- def self.open(persist = true, &block)
37
- gnuplot_cmd = gnuplot
38
-
39
- commands = yield
40
-
41
- output = StringIO.new
42
- Open3::popen3(gnuplot_cmd, '-persist') do |data_in, data_out, stderr, wait_th|
43
- data_in << commands[:plot_settings]
44
- data_in << commands[:plot_data]
45
-
46
- data_in.flush
47
- sleep 1
48
-
49
- while true do
50
- window = IO::popen('xprop -name "Gnuplot" WM_NAME 2>/dev/null').gets
51
- break unless window
52
- sleep 1
53
- end
54
- data_in.close
55
- data_out.close
56
- stderr.close
57
-
58
- output.write(wait_th.value.exitstatus)
59
- end
60
-
61
- output.string
62
- end
63
- end
64
-
65
- class Gnuplot::Plot
66
- attr_accessor :cmd, :data, :settings, :styles, :arbitrary_lines
67
-
68
- QUOTED_METHODS = [ "title", "output", "xlabel", "x2label", "ylabel", "y2label", "clabel", "cblabel", "zlabel" ]
69
-
70
- def initialize
71
- @settings = []
72
- @arbitrary_lines = []
73
- @data = []
74
- @styles = []
75
- end
76
-
77
- def self.construct(&block)
78
- plot = new
79
-
80
- block.call plot if block_given?
81
-
82
- { plot_settings: plot.to_gplot, plot_data: plot.store_datasets }
83
- end
84
-
85
- def method_missing(meth, *args)
86
- set meth.id2name, *args
87
- end
88
-
89
- def set ( var, value = "" )
90
- value = "\"#{value}\"" if QUOTED_METHODS.include? var unless value =~ /^'.*'$/
91
- @settings << [ :set, var, value ]
92
- end
93
-
94
- def unset (var)
95
- @settings << [ :unset, var ]
96
- end
97
-
98
- def to_gplot(io = '')
99
- @settings.each { |setting| io += setting.map(&:to_s).join(' ') + "\n" }
100
- @styles.each{ |style| io += style.to_s + "\n" }
101
- @arbitrary_lines.each{ |line| io += line + "\n" }
102
-
103
- io
104
- end
105
-
106
- def store_datasets(io = '')
107
- if @data.size > 0
108
- io += 'plot' + " #{ @data.map { |element| element.plot_args }.join(', ') } \n"
109
- io += @data.map { |ds| ds.to_gplot }.compact.join("\n") + "\n"
110
- end
111
-
112
- io
113
- end
114
- end
115
-
116
- class Gnuplot::Style
117
- attr_accessor :linestyle, :linetype, :linewidth, :linecolor, :pointtype, :pointsize, :fill, :index
118
-
119
- alias :ls :linestyle
120
- alias :lt :linetype
121
- alias :lw :linewidth
122
- alias :lc :linecolor
123
- alias :pt :pointtype
124
- alias :ps :pointsize
125
- alias :fs :fill
126
-
127
- alias :ls= :linestyle=
128
- alias :lt= :linetype=
129
- alias :lw= :linewidth=
130
- alias :lc= :linecolor=
131
- alias :pt= :pointtype=
132
- alias :ps= :pointsize=
133
- alias :fs= :fill=
134
-
135
- STYLES = [:ls, :lt, :lw, :lc, :pt, :ps, :fs]
136
-
137
- def self.increment_index
138
- @index ||= 0
139
- @index += 1
140
- end
141
-
142
- def initialize
143
- STYLES.each do |style|
144
- send("#{style}=", nil)
145
- end
146
-
147
- yield self if block_given?
148
-
149
- end
150
-
151
- def to_s
152
- str = ' '
153
-
154
- STYLES.each do |style|
155
- str += " #{style} #{send(style)}" if send(style)
156
- end
157
-
158
- str == ' ' ? '' : str
159
- end
160
- end
161
-
162
- class Gnuplot::DataSet
163
- attr_accessor :title, :with, :using, :data, :linewidth, :linecolor, :matrix, :smooth, :axes, :index, :linestyle
164
-
165
- alias :ls :linestyle
166
-
167
- def initialize(data = nil)
168
- @data = data
169
- @linestyle = nil
170
- @title = nil
171
- @with = nil
172
- @using = nil
173
- @linewidth = nil
174
- @linecolor = nil
175
- @matrix = nil
176
- @smooth = nil
177
- @axes = nil
178
- @index = nil
179
-
180
- yield self if block_given?
181
- end
182
-
183
- def notitle
184
- '"No Title"'
185
- end
186
-
187
- def plot_args(io = '')
188
- io += @data.is_a?(String) ? @data : "'-'"
189
- #io += " index #{@index}" if @index
190
- io += " using #{@using}" if @using
191
- io += " axes #{@axes}" if @axes
192
- io += " title #{@title ? "\"#{@title}\"" : notitle}"
193
- io += " matrix #{@matrix}" if @matrix
194
- io += " smooth #{@smooth}" if @smooth
195
- io += " with #{@with}" if @with
196
- io += " linecolor #{@linecolor}" if @linecolor
197
- io += " line #{@index} linewidth #{@linewidth}" if @linewidth
198
- io += " linestyle #{@linestyle.index}" if @linestyle
199
-
200
- io
201
- end
202
-
203
- def to_gplot
204
- return nil if @data.nil? || @data.is_a?(String)
205
-
206
- @data.to_gplot
207
- end
208
- end
209
-
210
- class Array
211
- def to_gplot
212
- if number_series?(self)
213
- series_for_plot = ''
214
- self.each { |elem| series_for_plot += "#{elem}\n" }
215
- series_for_plot + 'e'
216
- else
217
- self[0].zip(self[1]).map{ |elem| elem.join(' ') }.join("\n") + "\ne\n"
218
- end
219
- end
220
-
221
- private
222
-
223
- def number_series?(data)
224
- data.each do |elem|
225
- return false unless elem.is_a?(Numeric)
226
- end
227
-
228
- true
229
- end
230
- end
231
-
232
- class Matrix
233
- def to_gplot
234
- matrix_for_plot = ''
235
-
236
- (0...self.column_size).each do |j|
237
- (0...self.row_size).each do |i|
238
- matrix_for_plot += "#{i} #{j} #{self[j,i]}\n" if self[j,i]
239
- end
240
- end
241
-
242
- matrix_for_plot
243
- end
244
- end