21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
# File 'lib/nmatrix_extensions.rb', line 21
def heatmap(options={})
if $no_rmagick
return nil
end
opts = {:col_header => 'ACDEFGHIKLMNPQRSTVWYJ'.split(''),
:row_header => 'ACDEFGHIKLMNPQRSTVWYJ'.split(''),
:max_val => self.max,
:mid_val => (self.max - self.min) / 2.0,
:min_val => self.min,
:dpi => 100,
:margin_width => 30,
:rvg_width => nil,
:rvg_height => nil,
:canvas_width => nil,
:canvas_height => nil,
:cell_width => 20,
:cell_height => 20,
:cell_border_color => '#888888',
:cell_border_width => 1,
:table_border_color => '#000000',
:table_border_width => 2,
:header_height => 100,
:footer_height => 50,
:print_gradient => true,
:gradient_width => 300,
:gradient_height => 30,
:gradient_beg_color => '#FFFFFF',
:gradient_mid_color => nil,
:gradient_end_color => '#FF0000',
:gradient_border_width => 1,
:gradient_border_color => '#000000',
:font_scale => 0.9,
:font_family => 'san serif',
:small_gap_width => 2,
:title? => true,
:title => '',
:title_font_size => 35,
:title_font_scale => 1.0,
:print_value => false,
:key_font_size => 15,
:value_font_size => 8,
:background => '#FFFFFF'}.merge(options)
RVG::dpi = opts[:dpi]
rvg = RVG.new(opts[:rvg_width], opts[:rvg_height]) do |canvas|
title_x = (opts[:canvas_width] - opts[:title].length * opts[:title_font_size] * opts[:title_font_scale] / 2.0) / 2.0
title_y = opts[:header_height] - opts[:title_font_size] * opts[:title_font_scale]
canvas.viewbox(0, 0, opts[:canvas_width], opts[:canvas_height])
canvas.background_fill = opts[:background]
canvas.desc = opts[:title]
if opts[:title?]
canvas.text(title_x, title_y, opts[:title]).styles(:font_size => opts[:title_font_size] * opts[:title_font_scale])
end
table_x = (opts[:canvas_width] - opts[:cell_width] * self.shape[0]) / 2.0
table_y = opts[:header_height] + opts[:cell_height]
canvas.rect(self.shape[0] * opts[:cell_width],
self.shape[1] * opts[:cell_height],
table_x,
table_y).styles(:stroke => opts[:table_border_color],
:stroke_width => opts[:table_border_width])
0.upto(self.shape[0] - 1) do |col|
canvas.text(table_x + col * opts[:cell_width] + opts[:small_gap_width],
opts[:cell_height] + opts[:header_height] - opts[:small_gap_width],
opts[:col_header][col]).styles( :font_family => opts[:font_family],
:font_size => opts[:cell_width] * opts[:font_scale])
end
0.upto(self.shape[1] - 1) do |row|
canvas.text(table_x - opts[:cell_width],
table_y + (row + 1) * opts[:cell_height],
opts[:row_header][row]).styles( :font_family => opts[:font_family],
:font_size => opts[:cell_height] * opts[:font_scale])
end
r_beg = (opts[:gradient_beg_color].rgb_to_integer & 0xFF0000) >> 16
g_beg = (opts[:gradient_beg_color].rgb_to_integer & 0x00FF00) >> 8
b_beg = (opts[:gradient_beg_color].rgb_to_integer & 0x0000FF) >> 0
r_end = (opts[:gradient_end_color].rgb_to_integer & 0xFF0000) >> 16
g_end = (opts[:gradient_end_color].rgb_to_integer & 0x00FF00) >> 8
b_end = (opts[:gradient_end_color].rgb_to_integer & 0x0000FF) >> 0
gap = opts[:max_val] - opts[:min_val]
if opts[:gradient_mid_color]
r_mid = (opts[:gradient_mid_color].rgb_to_integer & 0xFF0000) >> 16
g_mid = (opts[:gradient_mid_color].rgb_to_integer & 0x00FF00) >> 8
b_mid = (opts[:gradient_mid_color].rgb_to_integer & 0x0000FF) >> 0
gap1 = opts[:mid_val] - opts[:min_val]
gap2 = opts[:max_val] - opts[:mid_val]
end
0.upto(self.shape[0] - 1) do |col|
0.upto(self.shape[1] - 1) do |row|
if opts[:gradient_mid_color]
if self[col, row] <= opts[:mid_val]
r = interpolate(r_beg, r_mid, self[col, row] - opts[:min_val], gap1)
g = interpolate(g_beg, g_mid, self[col, row] - opts[:min_val], gap1)
b = interpolate(b_beg, b_mid, self[col, row] - opts[:min_val], gap1)
else
r = interpolate(r_mid, r_end, self[col, row] - opts[:mid_val], gap2)
g = interpolate(g_mid, g_end, self[col, row] - opts[:mid_val], gap2)
b = interpolate(b_mid, b_end, self[col, row] - opts[:mid_val], gap2)
end
else
r = interpolate(r_beg, r_end, self[col, row] - opts[:min_val], gap)
g = interpolate(g_beg, g_end, self[col, row] - opts[:min_val], gap)
b = interpolate(b_beg, b_end, self[col, row] - opts[:min_val], gap)
end
color = ("#%6X" % ((((r << 8) | g) << 8) | b)).gsub(" ", "0")
canvas.rect(opts[:cell_width],
opts[:cell_height],
table_x + col * opts[:cell_width],
table_y + row * opts[:cell_height]).styles( :fill => color,
:stroke => opts[:cell_border_color],
:stroke_width => opts[:cell_border_width])
if opts[:print_value]
canvas.text(table_x + col * opts[:cell_width] + opts[:cell_border_width],
table_y + (row + 1) * opts[:cell_height],
"#{'%.1f' % self[col, row]}").styles(:font_size => opts[:value_font_size])
end
end
end
if opts[:print_gradient]
if opts[:gradient_mid_color]
img1 = Image.new(opts[:gradient_height],
opts[:gradient_width] / 2,
GradientFill.new(0,
opts[:gradient_width] / 2,
opts[:gradient_height],
opts[:gradient_width] / 2,
opts[:gradient_beg_color],
opts[:gradient_mid_color])).rotate(90)
img2 = Image.new(opts[:gradient_height],
opts[:gradient_width] / 2,
GradientFill.new(0,
opts[:gradient_width] / 2,
opts[:gradient_height],
opts[:gradient_width] / 2,
opts[:gradient_mid_color],
opts[:gradient_end_color])).rotate(90)
img3 = ImageList.new
img3 << img1 << img2
img = img3.append(false)
else
img = Image.new(opts[:gradient_height],
opts[:gradient_width],
GradientFill.new(0,
opts[:gradient_width],
opts[:gradient_height],
opts[:gradient_width],
opts[:gradient_beg_color],
opts[:gradient_end_color])).rotate(90)
end
img.border!(opts[:gradient_border_width],
opts[:gradient_border_width],
opts[:gradient_border_color])
gradient_x = (opts[:canvas_width] - opts[:gradient_width]) / 2
gradient_y = opts[:header_height] + opts[:cell_height] * opts[:row_header].count + opts[:margin_width]
canvas.image(img,
opts[:gradient_width],
opts[:gradient_height] + opts[:margin_width],
gradient_x,
gradient_y)
canvas.text(gradient_x,
gradient_y + opts[:gradient_height] + opts[:key_font_size] * 2,
"#{'%.1f' % opts[:min_val]}").styles(:font_size => opts[:key_font_size])
canvas.text(gradient_x + opts[:gradient_width],
gradient_y + opts[:gradient_height] + opts[:key_font_size] * 2,
"#{'%.1f' % opts[:max_val]}").styles(:font_size => opts[:key_font_size])
end
end
rvg.draw
end
|