grada 2.2.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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