semin-ulla 0.9.3

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.
@@ -0,0 +1,245 @@
1
+ require 'rubygems'
2
+ require 'narray'
3
+ require 'facets'
4
+
5
+ begin
6
+ require 'rvg/rvg'
7
+ include Magick
8
+ rescue
9
+ $logger.warn "A RubyGems package, 'rmagick' is not found, so heat maps cannot be generated."
10
+ $no_rmagick = true
11
+ end
12
+
13
+ module NMatrixExtensions
14
+
15
+ def pretty_string(options={})
16
+ opts = {:col_header => nil,
17
+ :row_header => nil }.merge(options)
18
+
19
+ ("%-3s" % "#") + opts[:col_header].inject("") { |s, a|
20
+ s + ("%7s" % a)
21
+ } + "\n" + self.to_a.map_with_index { |a, i|
22
+ ("%-3s" % opts[:row_header][i]) + a.inject("") { |s, v|
23
+ if v.is_a? Float
24
+ s + ("%7.2f" % v)
25
+ else
26
+ s + ("%7d" % v)
27
+ end
28
+ }
29
+ }.join("\n")
30
+ end
31
+
32
+ def heatmap(options={})
33
+ if $no_rmagick
34
+ return nil
35
+ end
36
+
37
+ opts = {:col_header => 'ACDEFGHIKLMNPQRSTVWYJ'.split(''),
38
+ :row_header => 'ACDEFGHIKLMNPQRSTVWYJ'.split(''),
39
+ :max_val => self.max,
40
+ :mid_val => (self.max - self.min) / 2.0,
41
+ :min_val => self.min,
42
+ :dpi => 100,
43
+ :margin_width => 30,
44
+ :rvg_width => nil,
45
+ :rvg_height => nil,
46
+ :canvas_width => nil,
47
+ :canvas_height => nil,
48
+ :cell_width => 20,
49
+ :cell_height => 20,
50
+ :cell_border_color => '#888888',
51
+ :cell_border_width => 1,
52
+ :table_border_color => '#000000',
53
+ :table_border_width => 2,
54
+ :header_height => 100,
55
+ :footer_height => 50,
56
+ :print_gradient => true,
57
+ :gradient_width => 300,
58
+ :gradient_height => 30,
59
+ :gradient_beg_color => '#FFFFFF',
60
+ :gradient_mid_color => nil,
61
+ :gradient_end_color => '#FF0000',
62
+ :gradient_border_width => 1,
63
+ :gradient_border_color => '#000000',
64
+ :font_scale => 0.9,
65
+ :font_family => 'san serif',
66
+ :small_gap_width => 2,
67
+ :title? => true,
68
+ :title => '',
69
+ :title_font_size => 35,
70
+ :print_value => false,
71
+ :key_font_size => 15,
72
+ :value_font_size => 8,
73
+ :background => '#FFFFFF'}.merge(options)
74
+
75
+ RVG::dpi = opts[:dpi]
76
+
77
+ rvg = RVG.new(opts[:rvg_width], opts[:rvg_height]) do |canvas|
78
+ title_x = (opts[:canvas_width] - opts[:title].length * opts[:title_font_size] * 0.6) / 2.0
79
+ title_y = opts[:header_height] - opts[:title_font_size] * 0.7
80
+
81
+ canvas.viewbox(0, 0, opts[:canvas_width], opts[:canvas_height])
82
+ canvas.background_fill = opts[:background]
83
+ canvas.desc = opts[:title]
84
+
85
+ if opts[:title?]
86
+ canvas.text(title_x, title_y, opts[:title]).styles(:font_size => opts[:title_font_size])
87
+ end
88
+
89
+ # border for whole matrix
90
+ table_x = (opts[:canvas_width] - opts[:cell_width] * self.shape[0]) / 2.0
91
+ table_y = opts[:header_height] + opts[:cell_height]
92
+
93
+ canvas.rect(self.shape[0] * opts[:cell_width],
94
+ self.shape[1] * opts[:cell_height],
95
+ table_x,
96
+ table_y).styles(:stroke => opts[:table_border_color],
97
+ :stroke_width => opts[:table_border_width])
98
+
99
+ # drawing column and row labels
100
+ 0.upto(self.shape[0] - 1) do |col|
101
+ canvas.text(table_x + col * opts[:cell_width] + opts[:small_gap_width],
102
+ opts[:cell_height] + opts[:header_height] - opts[:small_gap_width],
103
+ opts[:col_header][col]).styles( :font_family => opts[:font_family],
104
+ :font_size => opts[:cell_width] * opts[:font_scale])
105
+ end
106
+
107
+ 0.upto(self.shape[1] - 1) do |row|
108
+ canvas.text(table_x - opts[:cell_width],
109
+ table_y + (row + 1) * opts[:cell_height],
110
+ opts[:row_header][row]).styles( :font_family => opts[:font_family],
111
+ :font_size => opts[:cell_height] * opts[:font_scale])
112
+ end
113
+
114
+ # drawing cells
115
+
116
+ # calculating a unit of RGB color in a decimal number
117
+ r_beg = (opts[:gradient_beg_color].rgb_to_integer & 0xFF0000) >> 16
118
+ g_beg = (opts[:gradient_beg_color].rgb_to_integer & 0x00FF00) >> 8
119
+ b_beg = (opts[:gradient_beg_color].rgb_to_integer & 0x0000FF) >> 0
120
+ r_end = (opts[:gradient_end_color].rgb_to_integer & 0xFF0000) >> 16
121
+ g_end = (opts[:gradient_end_color].rgb_to_integer & 0x00FF00) >> 8
122
+ b_end = (opts[:gradient_end_color].rgb_to_integer & 0x0000FF) >> 0
123
+ gap = opts[:max_val] - opts[:min_val]
124
+
125
+ if opts[:gradient_mid_color]
126
+ r_mid = (opts[:gradient_mid_color].rgb_to_integer & 0xFF0000) >> 16
127
+ g_mid = (opts[:gradient_mid_color].rgb_to_integer & 0x00FF00) >> 8
128
+ b_mid = (opts[:gradient_mid_color].rgb_to_integer & 0x0000FF) >> 0
129
+ gap1 = opts[:mid_val] - opts[:min_val]
130
+ gap2 = opts[:max_val] - opts[:mid_val]
131
+ end
132
+
133
+ 0.upto(self.shape[0] - 1) do |col|
134
+ 0.upto(self.shape[1] - 1) do |row|
135
+ if opts[:gradient_mid_color]
136
+ if self[col, row] <= opts[:mid_val]
137
+ r = interpolate(r_beg, r_mid, self[col, row] - opts[:min_val], gap1)
138
+ g = interpolate(g_beg, g_mid, self[col, row] - opts[:min_val], gap1)
139
+ b = interpolate(b_beg, b_mid, self[col, row] - opts[:min_val], gap1)
140
+ else
141
+ r = interpolate(r_mid, r_end, self[col, row] - opts[:mid_val], gap2)
142
+ g = interpolate(g_mid, g_end, self[col, row] - opts[:mid_val], gap2)
143
+ b = interpolate(b_mid, b_end, self[col, row] - opts[:mid_val], gap2)
144
+ end
145
+ else
146
+ r = interpolate(r_beg, r_end, self[col, row] - opts[:min_val], gap)
147
+ g = interpolate(g_beg, g_end, self[col, row] - opts[:min_val], gap)
148
+ b = interpolate(b_beg, b_end, self[col, row] - opts[:min_val], gap)
149
+ end
150
+
151
+ color = ("#%6X" % ((((r << 8) | g) << 8) | b)).gsub(" ", "0")
152
+
153
+ canvas.rect(opts[:cell_width],
154
+ opts[:cell_height],
155
+ table_x + col * opts[:cell_width],
156
+ table_y + row * opts[:cell_height]).styles( :fill => color,
157
+ :stroke => opts[:cell_border_color],
158
+ :stroke_width => opts[:cell_border_width])
159
+
160
+ if opts[:print_value]
161
+ canvas.text(table_x + col * opts[:cell_width] + opts[:cell_border_width],
162
+ table_y + (row + 1) * opts[:cell_height],
163
+ "#{'%.1f' % self[col, row]}").styles(:font_size => opts[:value_font_size])
164
+ end
165
+ end
166
+ end
167
+
168
+ # gradient key
169
+ if opts[:print_gradient]
170
+ if opts[:gradient_mid_color]
171
+ img1 = Image.new(opts[:gradient_height],
172
+ opts[:gradient_width] / 2,
173
+ GradientFill.new(0,
174
+ opts[:gradient_width] / 2,
175
+ opts[:gradient_height],
176
+ opts[:gradient_width] / 2,
177
+ opts[:gradient_beg_color],
178
+ opts[:gradient_mid_color])).rotate(90)
179
+
180
+ img2 = Image.new(opts[:gradient_height],
181
+ opts[:gradient_width] / 2,
182
+ GradientFill.new(0,
183
+ opts[:gradient_width] / 2,
184
+ opts[:gradient_height],
185
+ opts[:gradient_width] / 2,
186
+ opts[:gradient_mid_color],
187
+ opts[:gradient_end_color])).rotate(90)
188
+ img3 = ImageList.new
189
+ img3 << img1 << img2
190
+ img = img3.append(false)
191
+ else
192
+ img = Image.new(opts[:gradient_height],
193
+ opts[:gradient_width],
194
+ GradientFill.new(0,
195
+ opts[:gradient_width],
196
+ opts[:gradient_height],
197
+ opts[:gradient_width],
198
+ opts[:gradient_beg_color],
199
+ opts[:gradient_end_color])).rotate(90)
200
+ end
201
+
202
+ img.border!(opts[:gradient_border_width],
203
+ opts[:gradient_border_width],
204
+ opts[:gradient_border_color])
205
+
206
+ gradient_x = (opts[:canvas_width] - opts[:gradient_width]) / 2
207
+ gradient_y = opts[:header_height] + opts[:cell_height] * opts[:row_header].count + opts[:margin_width]
208
+
209
+ canvas.image(img,
210
+ opts[:gradient_width],
211
+ opts[:gradient_height] + opts[:margin_width],
212
+ gradient_x,
213
+ gradient_y)
214
+
215
+ canvas.text(gradient_x,
216
+ gradient_y + opts[:gradient_height] + opts[:key_font_size] * 2,
217
+ "#{'%.1f' % opts[:min_val]}").styles(:font_size => opts[:key_font_size])
218
+
219
+ canvas.text(gradient_x + opts[:gradient_width],
220
+ gradient_y + opts[:gradient_height] + opts[:key_font_size] * 2,
221
+ "#{'%.1f' % opts[:max_val]}").styles(:font_size => opts[:key_font_size])
222
+ end
223
+ end
224
+
225
+ rvg.draw
226
+ end
227
+
228
+
229
+ private
230
+
231
+ def interpolate(start_val, end_val, step, no_steps)
232
+ begin
233
+ if (start_val < end_val)
234
+ ((end_val - start_val) / no_steps.to_f) * step + start_val
235
+ else
236
+ start_val - ((start_val - end_val) / no_steps.to_f) * step
237
+ end.round
238
+ rescue FloatDomainError
239
+ start_val
240
+ end
241
+ end
242
+
243
+ end
244
+
245
+ NMatrix.send(:include, NMatrixExtensions)
@@ -0,0 +1,17 @@
1
+ module StringExtensions
2
+
3
+ def remove_internal_spaces
4
+ gsub(/[\n|\r|\s]+/, '')
5
+ end
6
+
7
+ def rgb_to_integer
8
+ if self.length == 7 # '#FF00FF'
9
+ Integer(self.gsub('#', '0x'))
10
+ else
11
+ raise "#{self} doesn't seem to be a proper RGB code."
12
+ end
13
+ end
14
+ end
15
+
16
+ String.send :include, StringExtensions
17
+