ruby-gr 0.0.26 → 0.64.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.
- checksums.yaml +4 -4
- data/README.md +41 -73
- data/lib/gr/ffi.rb +11 -0
- data/lib/gr.rb +148 -32
- data/lib/gr3/ffi.rb +11 -0
- data/lib/gr3.rb +5 -1
- data/lib/gr_commons/fiddley.rb +1 -1
- data/lib/gr_commons/gr_lib.rb +43 -22
- data/lib/gr_commons/gr_logger.rb +23 -11
- data/lib/gr_commons/version.rb +1 -1
- data/lib/grm/ffi.rb +0 -3
- data/lib/grm.rb +5 -1
- metadata +8 -79
- data/lib/gr/plot.rb +0 -1530
data/lib/gr/plot.rb
DELETED
@@ -1,1530 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'gr'
|
4
|
-
autoload :GR3, 'gr3'
|
5
|
-
|
6
|
-
# FIXME: Plot should not depend on Numo::Narrray unless the GR3 module is required.
|
7
|
-
# Note: The Plot class has a linspace function that is independent of Numo..
|
8
|
-
require 'numo/narray'
|
9
|
-
|
10
|
-
module GR
|
11
|
-
# This class offers a simple, matlab-style API built on top of the GR package.
|
12
|
-
# The class name Plot may be changed in the future.
|
13
|
-
class Plot
|
14
|
-
# Why is the Plot class NOT object-oriented?
|
15
|
-
#
|
16
|
-
# Because the code here is mainly ported from GR.jl.
|
17
|
-
# https://github.com/jheinen/GR.jl/blob/master/src/jlgr.jl
|
18
|
-
#
|
19
|
-
# The Python implementation is also Julia compliant.
|
20
|
-
# https://github.com/sciapp/python-gr
|
21
|
-
#
|
22
|
-
# Julia is not an object-oriented language (at least in 2019).
|
23
|
-
# So, you will see many if branches here.
|
24
|
-
# This is not the Ruby code style. But it WORKS.
|
25
|
-
#
|
26
|
-
# I want to thank Josef Heinen(@jheinen), the creator of GR.jl
|
27
|
-
# and Florian Rhiem(@FlorianRhiem), the creator of python-gr.
|
28
|
-
#
|
29
|
-
# If you are interested in an object-oriented implementation,
|
30
|
-
# See rubyplot.
|
31
|
-
# https://github.com/SciRuby/rubyplot
|
32
|
-
|
33
|
-
# Plot kinds conform to GR.jl
|
34
|
-
PLOT_KIND = %i[line step scatter stem hist contour contourf hexbin heatmap
|
35
|
-
nonuniformheatmap wireframe surface plot3 scatter3 imshow
|
36
|
-
isosurface polar polarhist polarheatmap nonuniformpolarheatmap
|
37
|
-
trisurf tricont shade volume].freeze
|
38
|
-
|
39
|
-
# Keyword options conform to GR.jl.
|
40
|
-
KW_ARGS = %i[accelerate algorithm alpha ax backgroundcolor barwidth baseline
|
41
|
-
clabels clear clim color colormap crange figsize font grid
|
42
|
-
horizontal isovalue kind label labels levels location nbins
|
43
|
-
ratio rotation scale size spec subplot tilt title update xaxis
|
44
|
-
xflip xform xlabel xlim xlog xrange xticks yaxis yflip ylabel
|
45
|
-
ylim ylog zflip yrange yticks viewport vp where window zaxis
|
46
|
-
zlabel zlim zlog zrange zticks].freeze
|
47
|
-
|
48
|
-
FONTS = {
|
49
|
-
times_roman: 101,
|
50
|
-
times_italic: 102,
|
51
|
-
times_bold: 103,
|
52
|
-
times_bolditalic: 104,
|
53
|
-
helvetica_regular: 105,
|
54
|
-
helvetica_oblique: 106,
|
55
|
-
helvetica_bold: 107,
|
56
|
-
helvetica_boldoblique: 108,
|
57
|
-
courier_regular: 109,
|
58
|
-
courier_oblique: 110,
|
59
|
-
courier_bold: 111,
|
60
|
-
courier_boldoblique: 112,
|
61
|
-
symbol: 113,
|
62
|
-
bookman_light: 114,
|
63
|
-
bookman_lightitalic: 115,
|
64
|
-
bookman_demi: 116,
|
65
|
-
bookman_demiitalic: 117,
|
66
|
-
newcenturyschlbk_roman: 118,
|
67
|
-
newcenturyschlbk_italic: 119,
|
68
|
-
newcenturyschlbk_bold: 120,
|
69
|
-
newcenturyschlbk_bolditalic: 121,
|
70
|
-
avantgarde_book: 122,
|
71
|
-
avantgarde_bookoblique: 123,
|
72
|
-
avantgarde_demi: 124,
|
73
|
-
avantgarde_demioblique: 125,
|
74
|
-
palatino_roman: 126,
|
75
|
-
palatino_italic: 127,
|
76
|
-
palatino_bold: 128,
|
77
|
-
palatino_bolditalic: 129,
|
78
|
-
zapfchancery_mediumitalic: 130,
|
79
|
-
zapfdingbats: 131,
|
80
|
-
cmuserif_math: 232, # original: cmuserif-math
|
81
|
-
dejavusans: 233
|
82
|
-
}.freeze
|
83
|
-
|
84
|
-
@last_plot = nil
|
85
|
-
class << self
|
86
|
-
attr_accessor :last_plot
|
87
|
-
end
|
88
|
-
|
89
|
-
attr_accessor :args, :kvs, :scheme
|
90
|
-
|
91
|
-
def initialize(*raw_args)
|
92
|
-
@kvs = raw_args.last.is_a?(Hash) ? raw_args.pop : {}
|
93
|
-
@args = plot_args(raw_args) # method name is the same as Julia/Python
|
94
|
-
|
95
|
-
# Check keyword options.
|
96
|
-
kvs.each_key { |k| warn "Unknown keyword: #{k}" unless KW_ARGS.include? k }
|
97
|
-
|
98
|
-
# label(singular form) is a original keyword arg which GR.jl does not have.
|
99
|
-
kvs[:labels] ||= [kvs[:label]] if kvs.has_key? :label
|
100
|
-
|
101
|
-
# Don't use ||= here, because we need to tell `false` from `nil`
|
102
|
-
kvs[:size] = [600, 450] unless kvs.has_key? :size
|
103
|
-
kvs[:ax] = false unless kvs.has_key? :ax
|
104
|
-
kvs[:subplot] = [0, 1, 0, 1] unless kvs.has_key? :subplot
|
105
|
-
kvs[:clear] = true unless kvs.has_key? :clear
|
106
|
-
kvs[:update] = true unless kvs.has_key? :update
|
107
|
-
|
108
|
-
@scheme = 0
|
109
|
-
@background = 0xffffff
|
110
|
-
# @handle = nil # This variable will be used in gr_meta
|
111
|
-
|
112
|
-
self.class.last_plot = self
|
113
|
-
end
|
114
|
-
|
115
|
-
def set_viewport(kind, subplot)
|
116
|
-
mwidth, mheight, width, height = GR.inqdspsize
|
117
|
-
dpi = width / mwidth * 0.0254
|
118
|
-
w, h = if kvs[:figsize]
|
119
|
-
[(0.0254 * width * kvs[:figsize][0] / mwidth),
|
120
|
-
(0.0254 * height * kvs[:figsize][1] / mheight)]
|
121
|
-
elsif dpi > 200
|
122
|
-
kvs[:size].map { |i| i * dpi / 100 }
|
123
|
-
else
|
124
|
-
kvs[:size]
|
125
|
-
end
|
126
|
-
|
127
|
-
vp = subplot.clone
|
128
|
-
|
129
|
-
if w > h
|
130
|
-
ratio = h / w.to_f
|
131
|
-
msize = mwidth * w / width
|
132
|
-
GR.setwsviewport(0, msize, 0, msize * ratio)
|
133
|
-
GR.setwswindow(0, 1, 0, ratio)
|
134
|
-
vp[2] *= ratio
|
135
|
-
vp[3] *= ratio
|
136
|
-
else
|
137
|
-
ratio = w / h.to_f
|
138
|
-
msize = mheight * h / height
|
139
|
-
GR.setwsviewport(0, msize * ratio, 0, msize)
|
140
|
-
GR.setwswindow(0, ratio, 0, 1)
|
141
|
-
vp[0] *= ratio
|
142
|
-
vp[1] *= ratio
|
143
|
-
end
|
144
|
-
|
145
|
-
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
146
|
-
extent = [vp[1] - vp[0], vp[3] - vp[2]].min
|
147
|
-
vp1 = 0.5 * (vp[0] + vp[1] - extent)
|
148
|
-
vp2 = 0.5 * (vp[0] + vp[1] + extent)
|
149
|
-
vp3 = 0.5 * (vp[2] + vp[3] - extent)
|
150
|
-
vp4 = 0.5 * (vp[2] + vp[3] + extent)
|
151
|
-
else
|
152
|
-
vp1, vp2, vp3, vp4 = vp
|
153
|
-
end
|
154
|
-
|
155
|
-
viewport = [vp1 + 0.125 * (vp2 - vp1),
|
156
|
-
vp1 + 0.925 * (vp2 - vp1),
|
157
|
-
vp3 + 0.125 * (vp4 - vp3),
|
158
|
-
vp3 + 0.925 * (vp4 - vp3)]
|
159
|
-
|
160
|
-
if %i[contour contourf hexbin heatmap nonuniformheatmap polarheatmap
|
161
|
-
nonuniformpolarheatmap surface trisurf volume].include?(kind)
|
162
|
-
viewport[1] -= 0.1
|
163
|
-
end
|
164
|
-
|
165
|
-
if %i[line step scatter stem].include?(kind) && kvs[:labels]
|
166
|
-
location = kvs[:location] || 1
|
167
|
-
if [11, 12, 13].include?(location)
|
168
|
-
w, h = legend_size
|
169
|
-
viewport[1] -= w + 0.1
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
GR.setviewport(*viewport)
|
174
|
-
|
175
|
-
kvs[:viewport] = viewport
|
176
|
-
kvs[:vp] = vp
|
177
|
-
kvs[:ratio] = ratio
|
178
|
-
|
179
|
-
if kvs[:backgroundcolor]
|
180
|
-
GR.savestate
|
181
|
-
GR.selntran(0)
|
182
|
-
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
183
|
-
GR.setfillcolorind(kvs[:backgroundcolor])
|
184
|
-
if w > h
|
185
|
-
GR.fillrect(subplot[0], subplot[1],
|
186
|
-
ratio * subplot[2], ratio * subplot[3])
|
187
|
-
else
|
188
|
-
GR.fillrect(ratio * subplot[0], ratio * subplot[1],
|
189
|
-
subplot[2], subplot[3])
|
190
|
-
end
|
191
|
-
GR.selntran(1)
|
192
|
-
GR.restorestate
|
193
|
-
end
|
194
|
-
|
195
|
-
if %i[polar polarhist polarheatmap nonuniformpolarheatmap].include? kind
|
196
|
-
xmin, xmax, ymin, ymax = viewport
|
197
|
-
xcenter = 0.5 * (xmin + xmax)
|
198
|
-
ycenter = 0.5 * (ymin + ymax)
|
199
|
-
r = 0.5 * [xmax - xmin, ymax - ymin].min
|
200
|
-
GR.setviewport(xcenter - r, xcenter + r, ycenter - r, ycenter + r)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def set_window(kind)
|
205
|
-
scale = 0
|
206
|
-
unless %i[polar polarhist polarheatmap nonuniformpolarheatmap].include?(kind)
|
207
|
-
scale |= GR::OPTION_X_LOG if kvs[:xlog]
|
208
|
-
scale |= GR::OPTION_Y_LOG if kvs[:ylog]
|
209
|
-
scale |= GR::OPTION_Z_LOG if kvs[:zlog]
|
210
|
-
scale |= GR::OPTION_FLIP_X if kvs[:xflip]
|
211
|
-
scale |= GR::OPTION_FLIP_Y if kvs[:yflip]
|
212
|
-
scale |= GR::OPTION_FLIP_Z if kvs[:zflip]
|
213
|
-
end
|
214
|
-
kvs[:scale] = scale
|
215
|
-
|
216
|
-
if kvs.has_key?(:panzoom)
|
217
|
-
xmin, xmax, ymin, ymax = GR.panzoom(*kvs[:panzoom])
|
218
|
-
kvs[:xrange] = [xmin, xmax]
|
219
|
-
kvs[:yrange] = [ymin, ymax]
|
220
|
-
else
|
221
|
-
minmax
|
222
|
-
end
|
223
|
-
|
224
|
-
major_count = if %i[wireframe surface plot3 scatter3 polar polarhist
|
225
|
-
polarheatmap nonuniformpolarheatmap trisurf volume].include?(kind)
|
226
|
-
2
|
227
|
-
else
|
228
|
-
5
|
229
|
-
end
|
230
|
-
|
231
|
-
kvs[:xticks] = [kvs[:xticks], major_count] if kvs[:xticks].is_a? Numeric
|
232
|
-
kvs[:yticks] = [kvs[:yticks], major_count] if kvs[:yticks].is_a? Numeric
|
233
|
-
kvs[:zticks] = [kvs[:zticks], major_count] if kvs[:zticks].is_a? Numeric
|
234
|
-
|
235
|
-
xmin, xmax = kvs[:xrange]
|
236
|
-
if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:xlim)
|
237
|
-
xmin -= 0.5
|
238
|
-
xmax += 0.5
|
239
|
-
end
|
240
|
-
xtick, majorx = if (scale & GR::OPTION_X_LOG) == 0
|
241
|
-
if !%i[heatmap polarheatmap].include?(kind) &&
|
242
|
-
!kvs.has_key?(:xlim) &&
|
243
|
-
!kvs[:panzoom]
|
244
|
-
xmin, xmax = GR.adjustlimits(xmin, xmax)
|
245
|
-
end
|
246
|
-
if kvs.has_key?(:xticks)
|
247
|
-
kvs[:xticks]
|
248
|
-
else
|
249
|
-
[GR.tick(xmin, xmax) / major_count, major_count]
|
250
|
-
end
|
251
|
-
else
|
252
|
-
[1, 1]
|
253
|
-
end
|
254
|
-
xorg = (scale & GR::OPTION_FLIP_X) == 0 ? [xmin, xmax] : [xmax, xmin]
|
255
|
-
kvs[:xaxis] = xtick, xorg, majorx
|
256
|
-
|
257
|
-
ymin, ymax = kvs[:yrange]
|
258
|
-
if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:ylim)
|
259
|
-
ymin -= 0.5
|
260
|
-
ymax += 0.5
|
261
|
-
end
|
262
|
-
if kind == :hist
|
263
|
-
if kvs[:horizontal] && !kvs.has_key?(:xlim)
|
264
|
-
xmin = (scale & GR::OPTION_X_LOG) == 0 ? 0 : 1
|
265
|
-
elsif !kvs.has_key?(:ylim)
|
266
|
-
ymin = (scale & GR::OPTION_Y_LOG) == 0 ? 0 : 1
|
267
|
-
end
|
268
|
-
end
|
269
|
-
ytick, majory = if (scale & GR::OPTION_Y_LOG) == 0
|
270
|
-
if !%i[heatmap polarheatmap].include?(kind) &&
|
271
|
-
!kvs.has_key?(:ylim) &&
|
272
|
-
!kvs[:panzoom]
|
273
|
-
ymin, ymax = GR.adjustlimits(ymin, ymax)
|
274
|
-
end
|
275
|
-
if kvs.has_key?(:yticks)
|
276
|
-
kvs[:yticks]
|
277
|
-
else
|
278
|
-
[GR.tick(ymin, ymax) / major_count, major_count]
|
279
|
-
end
|
280
|
-
else
|
281
|
-
[1, 1]
|
282
|
-
end
|
283
|
-
yorg = (scale & GR::OPTION_FLIP_Y) == 0 ? [ymin, ymax] : [ymax, ymin]
|
284
|
-
kvs[:yaxis] = ytick, yorg, majory
|
285
|
-
|
286
|
-
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
287
|
-
zmin, zmax = kvs[:zrange]
|
288
|
-
ztick, majorz = if (scale & GR::OPTION_Z_LOG) == 0
|
289
|
-
zmin, zmax = GR.adjustlimits(zmin, zmax) if kvs.has_key?(:zlim)
|
290
|
-
if kvs.has_key?(:zticks)
|
291
|
-
kvs[:zticks]
|
292
|
-
else
|
293
|
-
[GR.tick(zmin, zmax) / major_count, major_count]
|
294
|
-
end
|
295
|
-
else
|
296
|
-
[1, 1]
|
297
|
-
end
|
298
|
-
zorg = (scale & GR::OPTION_FLIP_Z) == 0 ? [zmin, zmax] : [zmax, zmin]
|
299
|
-
kvs[:zaxis] = ztick, zorg, majorz
|
300
|
-
end
|
301
|
-
|
302
|
-
kvs[:window] = xmin, xmax, ymin, ymax
|
303
|
-
if %i[polar polarhist polarheatmap nonuniformpolarheatmap].include?(kind)
|
304
|
-
GR.setwindow(-1, 1, -1, 1)
|
305
|
-
else
|
306
|
-
GR.setwindow(xmin, xmax, ymin, ymax)
|
307
|
-
end
|
308
|
-
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
309
|
-
rotation = kvs[:rotation] || 40
|
310
|
-
tilt = kvs[:tilt] || 70
|
311
|
-
GR.setspace(zmin, zmax, rotation, tilt)
|
312
|
-
end
|
313
|
-
|
314
|
-
kvs[:scale] = scale
|
315
|
-
GR.setscale(scale)
|
316
|
-
end
|
317
|
-
|
318
|
-
def draw_axes(kind, pass = 1)
|
319
|
-
viewport = kvs[:viewport]
|
320
|
-
vp = kvs[:vp]
|
321
|
-
ratio = kvs[:ratio]
|
322
|
-
xtick, xorg, majorx = kvs[:xaxis]
|
323
|
-
ytick, yorg, majory = kvs[:yaxis]
|
324
|
-
drawgrid = kvs.has_key?(:grid) ? kvs[:grid] : true
|
325
|
-
xtick = 10 if kvs[:scale] & GR::OPTION_X_LOG != 0
|
326
|
-
ytick = 10 if kvs[:scale] & GR::OPTION_Y_LOG != 0
|
327
|
-
GR.setlinecolorind(1)
|
328
|
-
diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
|
329
|
-
GR.setlinewidth(1)
|
330
|
-
charheight = [0.018 * diag, 0.012].max
|
331
|
-
GR.setcharheight(charheight)
|
332
|
-
ticksize = 0.0075 * diag
|
333
|
-
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
334
|
-
ztick, zorg, majorz = kvs[:zaxis]
|
335
|
-
if pass == 1 && drawgrid
|
336
|
-
GR.grid3d(xtick, 0, ztick, xorg[0], yorg[1], zorg[0], 2, 0, 2)
|
337
|
-
GR.grid3d(0, ytick, 0, xorg[0], yorg[1], zorg[0], 0, 2, 0)
|
338
|
-
else
|
339
|
-
GR.axes3d(xtick, 0, ztick, xorg[0], yorg[0], zorg[0], majorx, 0, majorz, -ticksize)
|
340
|
-
GR.axes3d(0, ytick, 0, xorg[1], yorg[0], zorg[0], 0, majory, 0, ticksize)
|
341
|
-
end
|
342
|
-
else
|
343
|
-
if %i[heatmap nonuniformheatmap shade].include?(kind)
|
344
|
-
ticksize = -ticksize
|
345
|
-
elsif drawgrid
|
346
|
-
GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
347
|
-
end
|
348
|
-
if kvs.has_key?(:xticklabels) || kvs.has_key?(:yticklabels)
|
349
|
-
fx = if kvs.has_key?(:xticklabels)
|
350
|
-
GRCommons::Fiddley::Function.new(
|
351
|
-
:void, %i[double double string double]
|
352
|
-
) do |x, y, _svalue, value|
|
353
|
-
label = value < 0 ? '' : kvs[:xticklabels][value] || ''
|
354
|
-
GR.textext(x, y, label)
|
355
|
-
end
|
356
|
-
else
|
357
|
-
GRCommons::Fiddley::Function.new(
|
358
|
-
:void, %i[double double string double]
|
359
|
-
) do |x, y, _svalue, value|
|
360
|
-
GR.textext(x, y, value.to_s)
|
361
|
-
end
|
362
|
-
end
|
363
|
-
fy = if kvs.has_key?(:yticklabels)
|
364
|
-
GRCommons::Fiddley::Function.new(
|
365
|
-
:void, %i[double double string double]
|
366
|
-
) do |x, y, _svalue, value|
|
367
|
-
label = value < 0 ? '' : kvs[:yticklabels][value] || ''
|
368
|
-
GR.textext(x, y, label)
|
369
|
-
end
|
370
|
-
else
|
371
|
-
GRCommons::Fiddley::Function.new(
|
372
|
-
:void, %i[double double string double]
|
373
|
-
) do |x, y, _svalue, value|
|
374
|
-
GR.textext(x, y, value.to_s)
|
375
|
-
end
|
376
|
-
end
|
377
|
-
GR.axeslbl(xtick, ytick, xorg[0], yorg[0], majorx, majory, ticksize, fx, fy)
|
378
|
-
else
|
379
|
-
GR.axes(xtick, ytick, xorg[0], yorg[0], majorx, majory, ticksize)
|
380
|
-
end
|
381
|
-
GR.axes(xtick, ytick, xorg[1], yorg[1], -majorx, -majory, -ticksize)
|
382
|
-
end
|
383
|
-
|
384
|
-
if kvs.has_key?(:title)
|
385
|
-
GR.savestate
|
386
|
-
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
|
387
|
-
text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title].to_s)
|
388
|
-
GR.restorestate
|
389
|
-
end
|
390
|
-
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
391
|
-
xlabel = (kvs[:xlabel] || '').to_s
|
392
|
-
ylabel = (kvs[:ylabel] || '').to_s
|
393
|
-
zlabel = (kvs[:zlabel] || '').to_s
|
394
|
-
GR.titles3d(xlabel, ylabel, zlabel)
|
395
|
-
else
|
396
|
-
if kvs.has_key?(:xlabel)
|
397
|
-
GR.savestate
|
398
|
-
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_BOTTOM)
|
399
|
-
text(0.5 * (viewport[0] + viewport[1]), vp[2] + 0.5 * charheight, kvs[:xlabel].to_s)
|
400
|
-
GR.restorestate
|
401
|
-
end
|
402
|
-
if kvs.has_key?(:ylabel)
|
403
|
-
GR.savestate
|
404
|
-
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
|
405
|
-
GR.setcharup(-1, 0)
|
406
|
-
text(vp[0] + 0.5 * charheight, 0.5 * (viewport[2] + viewport[3]), kvs[:ylabel].to_s)
|
407
|
-
GR.restorestate
|
408
|
-
end
|
409
|
-
end
|
410
|
-
end
|
411
|
-
|
412
|
-
def draw_polar_axes
|
413
|
-
viewport = kvs[:viewport]
|
414
|
-
diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
|
415
|
-
charheight = [0.018 * diag, 0.012].max
|
416
|
-
|
417
|
-
window = kvs[:window]
|
418
|
-
rmin = window[2]
|
419
|
-
rmax = window[3]
|
420
|
-
|
421
|
-
GR.savestate
|
422
|
-
GR.setcharheight(charheight)
|
423
|
-
GR.setlinetype(GR::LINETYPE_SOLID)
|
424
|
-
|
425
|
-
tick = 0.5 * GR.tick(rmin, rmax)
|
426
|
-
n = ((rmax - rmin) / tick + 0.5).round
|
427
|
-
(n + 1).times do |i|
|
428
|
-
r = i.to_f / n
|
429
|
-
if i.even?
|
430
|
-
GR.setlinecolorind(88)
|
431
|
-
GR.drawarc(-r, r, -r, r, 0, 359) if i > 0
|
432
|
-
GR.settextalign(GR::TEXT_HALIGN_LEFT, GR::TEXT_VALIGN_HALF)
|
433
|
-
x, y = GR.wctondc(0.05, r)
|
434
|
-
GR.text(x, y, (rmin + i * tick).to_s) # FIXME: round. significant digits.
|
435
|
-
else
|
436
|
-
GR.setlinecolorind(90)
|
437
|
-
GR.drawarc(-r, r, -r, r, 0, 359)
|
438
|
-
end
|
439
|
-
end
|
440
|
-
0.step(by: 45, to: 315) do |alpha|
|
441
|
-
sinf = Math.sin(alpha * Math::PI / 180)
|
442
|
-
cosf = Math.cos(alpha * Math::PI / 180)
|
443
|
-
GR.polyline([cosf, 0], [sinf, 0])
|
444
|
-
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_HALF)
|
445
|
-
x, y = GR.wctondc(1.1 * cosf, 1.1 * sinf)
|
446
|
-
GR.textext(x, y, "#{alpha}^o")
|
447
|
-
end
|
448
|
-
GR.restorestate
|
449
|
-
end
|
450
|
-
|
451
|
-
def plot_polar(θ, ρ)
|
452
|
-
window = kvs[:window]
|
453
|
-
rmax = window[3].to_f
|
454
|
-
ρ = ρ.map { |i| i / rmax }
|
455
|
-
n = ρ.length
|
456
|
-
x = []
|
457
|
-
y = []
|
458
|
-
n.times do |i|
|
459
|
-
x << ρ[i] * Math.cos(θ[i])
|
460
|
-
y << ρ[i] * Math.sin(θ[i])
|
461
|
-
end
|
462
|
-
GR.polyline(x, y)
|
463
|
-
end
|
464
|
-
|
465
|
-
def plot_img(img)
|
466
|
-
viewport = kvs[:vp].clone
|
467
|
-
viewport[3] -= 0.05 if kvs.has_key?(:title)
|
468
|
-
vp = kvs[:vp]
|
469
|
-
|
470
|
-
if img.is_a? String
|
471
|
-
width, height, data = GR.readimage(img)
|
472
|
-
else
|
473
|
-
height, width = img.shape
|
474
|
-
cmin, cmax = kvs[:crange]
|
475
|
-
data = img.map { |i| normalize_color(i, cmin, cmax) }
|
476
|
-
data = data.map { |i| (1000 + i * 255).round }
|
477
|
-
end
|
478
|
-
|
479
|
-
if width * (viewport[3] - viewport[2]) < height * (viewport[1] - viewport[0])
|
480
|
-
w = width.to_f / height * (viewport[3] - viewport[2])
|
481
|
-
xmin = [0.5 * (viewport[0] + viewport[1] - w), viewport[0]].max
|
482
|
-
xmax = [0.5 * (viewport[0] + viewport[1] + w), viewport[1]].min
|
483
|
-
ymin = viewport[2]
|
484
|
-
ymax = viewport[3]
|
485
|
-
else
|
486
|
-
h = height.to_f / width * (viewport[1] - viewport[0])
|
487
|
-
xmin = viewport[0]
|
488
|
-
xmax = viewport[1]
|
489
|
-
ymin = [0.5 * (viewport[3] + viewport[2] - h), viewport[2]].max
|
490
|
-
ymax = [0.5 * (viewport[3] + viewport[2] + h), viewport[3]].min
|
491
|
-
end
|
492
|
-
|
493
|
-
GR.selntran(0)
|
494
|
-
GR.setscale(0)
|
495
|
-
if kvs.has_key?(:xflip)
|
496
|
-
tmp = xmax
|
497
|
-
xmax = xmin
|
498
|
-
xmin = tmp
|
499
|
-
end
|
500
|
-
if kvs.has_key?(:yflip)
|
501
|
-
tmp = ymax
|
502
|
-
ymax = ymin
|
503
|
-
ymin = tmp
|
504
|
-
end
|
505
|
-
if img.is_a? String
|
506
|
-
GR.drawimage(xmin, xmax, ymin, ymax, width, height, data)
|
507
|
-
else
|
508
|
-
GR.cellarray(xmin, xmax, ymin, ymax, width, height, data)
|
509
|
-
end
|
510
|
-
|
511
|
-
if kvs.has_key?(:title)
|
512
|
-
GR.savestate
|
513
|
-
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
|
514
|
-
text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title].to_s)
|
515
|
-
GR.restorestate
|
516
|
-
end
|
517
|
-
GR.selntran(1)
|
518
|
-
end
|
519
|
-
|
520
|
-
def plot_iso(v)
|
521
|
-
viewport = kvs[:viewport]
|
522
|
-
|
523
|
-
if viewport[3] - viewport[2] < viewport[1] - viewport[0]
|
524
|
-
width = viewport[3] - viewport[2]
|
525
|
-
centerx = 0.5 * (viewport[0] + viewport[1])
|
526
|
-
xmin = [centerx - 0.5 * width, viewport[0]].max
|
527
|
-
xmax = [centerx + 0.5 * width, viewport[1]].min
|
528
|
-
ymin = viewport[2]
|
529
|
-
ymax = viewport[3]
|
530
|
-
else
|
531
|
-
height = viewport[1] - viewport[0]
|
532
|
-
centery = 0.5 * (viewport[2] + viewport[3])
|
533
|
-
xmin = viewport[0]
|
534
|
-
xmax = viewport[1]
|
535
|
-
ymin = [centery - 0.5 * height, viewport[2]].max
|
536
|
-
ymax = [centery + 0.5 * height, viewport[3]].min
|
537
|
-
end
|
538
|
-
|
539
|
-
GR.selntran(0)
|
540
|
-
v = Numo::DFloat.cast(v) if v.is_a? Array
|
541
|
-
values = ((v - v.min) / (v.max - v.min) * (2**16 - 1)).round
|
542
|
-
values = Numo::UInt16.cast(values)
|
543
|
-
nx, ny, nz = v.shape
|
544
|
-
isovalue = ((kvs[:isovalue] || 0.5) - v.min) / (v.max - v.min)
|
545
|
-
rotation = ((kvs[:rotation] || 40) * Math::PI / 180.0)
|
546
|
-
tilt = ((kvs[:tilt] || 70) * Math::PI / 180.0)
|
547
|
-
r = 2.5
|
548
|
-
GR3.clear
|
549
|
-
mesh = GR3.createisosurfacemesh(values, [2.0 / (nx - 1), 2.0 / (ny - 1), 2.0 / (nz - 1)],
|
550
|
-
[-1, -1, -1],
|
551
|
-
(isovalue * (2**16 - 1)).round)
|
552
|
-
color = kvs[:color] || [0.0, 0.5, 0.8]
|
553
|
-
GR3.setbackgroundcolor(1, 1, 1, 0)
|
554
|
-
GR3.drawmesh(mesh, 1, [0, 0, 0], [0, 0, 1], [0, 1, 0], color, [1, 1, 1])
|
555
|
-
GR3.cameralookat(r * Math.sin(tilt) * Math.sin(rotation),
|
556
|
-
r * Math.cos(tilt), r * Math.sin(tilt) * Math.cos(rotation),
|
557
|
-
0, 0, 0, 0, 1, 0)
|
558
|
-
GR3.drawimage(xmin, xmax, ymin, ymax, 500, 500, GR3::DRAWABLE_GKS)
|
559
|
-
GR3.deletemesh(mesh)
|
560
|
-
GR.selntran(1)
|
561
|
-
end
|
562
|
-
|
563
|
-
def colorbar(off = 0, colors = 256)
|
564
|
-
GR.savestate
|
565
|
-
viewport = kvs[:viewport]
|
566
|
-
zmin, zmax = kvs[:zrange]
|
567
|
-
mask = (GR::OPTION_Z_LOG | GR::OPTION_FLIP_Y | GR::OPTION_FLIP_Z)
|
568
|
-
options = if kvs.has_key?(:zflip)
|
569
|
-
(GR.inqscale | GR::OPTION_FLIP_Y)
|
570
|
-
elsif kvs.has_key?(:yflip)
|
571
|
-
GR.inqscale & ~GR::OPTION_FLIP_Y
|
572
|
-
else
|
573
|
-
GR.inqscale
|
574
|
-
end
|
575
|
-
GR.setscale(options & mask)
|
576
|
-
h = 0.5 * (zmax - zmin) / (colors - 1)
|
577
|
-
GR.setwindow(0, 1, zmin, zmax)
|
578
|
-
GR.setviewport(viewport[1] + 0.02 + off, viewport[1] + 0.05 + off,
|
579
|
-
viewport[2], viewport[3])
|
580
|
-
l = linspace(1000, 1255, colors).map(&:round)
|
581
|
-
GR.cellarray(0, 1, zmax + h, zmin - h, 1, colors, l)
|
582
|
-
GR.setlinecolorind(1)
|
583
|
-
diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
|
584
|
-
charheight = [0.016 * diag, 0.012].max
|
585
|
-
GR.setcharheight(charheight)
|
586
|
-
if kvs[:scale] & GR::OPTION_Z_LOG == 0
|
587
|
-
ztick = 0.5 * GR.tick(zmin, zmax)
|
588
|
-
GR.axes(0, ztick, 1, zmin, 0, 1, 0.005)
|
589
|
-
else
|
590
|
-
GR.setscale(GR::OPTION_Y_LOG)
|
591
|
-
GR.axes(0, 2, 1, zmin, 0, 1, 0.005)
|
592
|
-
end
|
593
|
-
GR.restorestate
|
594
|
-
end
|
595
|
-
|
596
|
-
def plot_data(_figure = true)
|
597
|
-
# GR.init
|
598
|
-
|
599
|
-
# target = GR.displayname
|
600
|
-
# if flag && target != None
|
601
|
-
# if target == "js" || target == "meta"
|
602
|
-
# send_meta(0)
|
603
|
-
# else
|
604
|
-
# send_serialized(target)
|
605
|
-
# end
|
606
|
-
# return
|
607
|
-
# end
|
608
|
-
|
609
|
-
kind = kvs[:kind] || :line
|
610
|
-
GR.clearws if kvs[:clear]
|
611
|
-
|
612
|
-
if scheme != 0
|
613
|
-
# Not yet.
|
614
|
-
end
|
615
|
-
|
616
|
-
if kvs.has_key?(:font)
|
617
|
-
name = kvs[:font]
|
618
|
-
# 'Cmuserif-Math' => :cmuserif_math
|
619
|
-
sym_name = name.to_s.gsub('-', '_').downcase.to_sym
|
620
|
-
if FONTS.include?(sym_name)
|
621
|
-
font = FONTS[sym_name]
|
622
|
-
GR.settextfontprec(font, font > 200 ? 3 : 0)
|
623
|
-
else
|
624
|
-
font = GR.loadfont(name)
|
625
|
-
if font >= 0
|
626
|
-
GR.settextfontprec(font, 3)
|
627
|
-
else
|
628
|
-
warn "Unknown font name: #{name}"
|
629
|
-
end
|
630
|
-
end
|
631
|
-
else
|
632
|
-
# The following fonts are the default in GR.jl
|
633
|
-
# Japanese, Chinese, Korean, etc. cannot be displayed.
|
634
|
-
|
635
|
-
# GR.settextfontprec(232, 3) # CM Serif Roman
|
636
|
-
end
|
637
|
-
|
638
|
-
set_viewport(kind, kvs[:subplot])
|
639
|
-
unless kvs[:ax]
|
640
|
-
set_window(kind)
|
641
|
-
if %i[polar polarhist].include?(kind)
|
642
|
-
draw_polar_axes
|
643
|
-
elsif !%i[imshow isosurface polarheatmap nonuniformpolarheatmap].include?(kind)
|
644
|
-
draw_axes(kind)
|
645
|
-
end
|
646
|
-
end
|
647
|
-
|
648
|
-
if kvs.has_key?(:colormap)
|
649
|
-
GR.setcolormap(kvs[:colormap])
|
650
|
-
else
|
651
|
-
GR.setcolormap(GR::COLORMAP_VIRIDIS)
|
652
|
-
end
|
653
|
-
|
654
|
-
GR.uselinespec(' ')
|
655
|
-
args.each do |x, y, z, c, spec|
|
656
|
-
spec ||= kvs[:spec] ||= ''
|
657
|
-
GR.savestate
|
658
|
-
GR.settransparency(kvs[:alpha]) if kvs.has_key?(:alpha)
|
659
|
-
|
660
|
-
case kind
|
661
|
-
|
662
|
-
when :line
|
663
|
-
mask = GR.uselinespec(spec)
|
664
|
-
GR.polyline(x, y) if hasline(mask)
|
665
|
-
GR.polymarker(x, y) if hasmarker(mask)
|
666
|
-
|
667
|
-
when :step
|
668
|
-
mask = GR.uselinespec(spec)
|
669
|
-
if hasline(mask)
|
670
|
-
where = kvs[:where] || 'mid'
|
671
|
-
n = x.length
|
672
|
-
xs = [x[0]]
|
673
|
-
case where
|
674
|
-
when 'pre'
|
675
|
-
ys = [y[0]]
|
676
|
-
(n - 1).times do |i|
|
677
|
-
xs << x[i] << x[i + 1]
|
678
|
-
ys << y[i + 1] << y[i + 1]
|
679
|
-
end
|
680
|
-
when 'post'
|
681
|
-
ys = [y[0]]
|
682
|
-
(n - 1).times do |i|
|
683
|
-
xs << x[i + 1] << x[i + 1]
|
684
|
-
ys << y[i] << y[i + 1]
|
685
|
-
end
|
686
|
-
else
|
687
|
-
ys = []
|
688
|
-
(n - 1).times do |i|
|
689
|
-
xs << 0.5 * (x[i] + x[i + 1]) << 0.5 * (x[i] + x[i + 1])
|
690
|
-
ys << y[i] << y[i]
|
691
|
-
end
|
692
|
-
xs << x[n - 1]
|
693
|
-
ys << y[n - 1] << y[n - 1]
|
694
|
-
end
|
695
|
-
GR.polyline(xs, ys)
|
696
|
-
end
|
697
|
-
GR.polymarker(x, y) if hasmarker(mask)
|
698
|
-
|
699
|
-
when :scatter
|
700
|
-
GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
|
701
|
-
if z || c
|
702
|
-
if c
|
703
|
-
cmin, cmax = kvs[:crange]
|
704
|
-
c = c.map { |i| normalize_color(i, cmin, cmax) }
|
705
|
-
cind = c.map { |i| (1000 + i * 255).round }
|
706
|
-
end
|
707
|
-
x.length.times do |i|
|
708
|
-
GR.setmarkersize(z[i] / 100.0) if z
|
709
|
-
GR.setmarkercolorind(cind[i]) if c
|
710
|
-
GR.polymarker([x[i]], [y[i]])
|
711
|
-
end
|
712
|
-
else
|
713
|
-
GR.polymarker(x, y)
|
714
|
-
end
|
715
|
-
|
716
|
-
when :stem
|
717
|
-
GR.setlinecolorind(1)
|
718
|
-
GR.polyline(kvs[:window][0..1], [0, 0])
|
719
|
-
GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
|
720
|
-
GR.uselinespec(spec)
|
721
|
-
x = x.to_a if narray?(x)
|
722
|
-
y = y.to_a if narray?(y)
|
723
|
-
x.zip(y).each do |xi, yi|
|
724
|
-
GR.polyline([xi, xi], [0, yi])
|
725
|
-
end
|
726
|
-
GR.polymarker(x, y)
|
727
|
-
|
728
|
-
when :hist
|
729
|
-
if kvs[:horizontal]
|
730
|
-
xmin = kvs[:window][0]
|
731
|
-
x.length.times do |i|
|
732
|
-
GR.setfillcolorind(989)
|
733
|
-
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
734
|
-
GR.fillrect(xmin, x[i], y[i], y[i + 1])
|
735
|
-
GR.setfillcolorind(1)
|
736
|
-
GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
|
737
|
-
GR.fillrect(xmin, x[i], y[i], y[i + 1])
|
738
|
-
end
|
739
|
-
else
|
740
|
-
ymin = kvs[:window][2]
|
741
|
-
y.length.times do |i|
|
742
|
-
GR.setfillcolorind(989)
|
743
|
-
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
744
|
-
GR.fillrect(x[i], x[i + 1], ymin, y[i])
|
745
|
-
GR.setfillcolorind(1)
|
746
|
-
GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
|
747
|
-
GR.fillrect(x[i], x[i + 1], ymin, y[i])
|
748
|
-
end
|
749
|
-
end
|
750
|
-
|
751
|
-
when :polarhist
|
752
|
-
ymax = kvs[:window][3].to_f
|
753
|
-
ρ = y.map { |i| i / ymax }
|
754
|
-
θ = x.map { |i| i * 180 / Math::PI }
|
755
|
-
(1...ρ.length).each do |i|
|
756
|
-
GR.setfillcolorind(989)
|
757
|
-
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
758
|
-
GR.fillarc(-ρ[i], ρ[i], -ρ[i], ρ[i], θ[i - 1], θ[i])
|
759
|
-
GR.setfillcolorind(1)
|
760
|
-
GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
|
761
|
-
GR.fillarc(-ρ[i], ρ[i], -ρ[i], ρ[i], θ[i - 1], θ[i])
|
762
|
-
end
|
763
|
-
|
764
|
-
when :polarheatmap, :nonuniformpolarheatmap
|
765
|
-
w, h = z.shape
|
766
|
-
cmap = colormap
|
767
|
-
cmin, cmax = kvs[:zrange]
|
768
|
-
data = z.map { |i| normalize_color(i, cmin, cmax) }
|
769
|
-
data.reverse(axis: 0) if kvs[:xflip]
|
770
|
-
data.reverse(axis: 1) if kvs[:yflip]
|
771
|
-
colors = data * 255 + 1000
|
772
|
-
colors = colors.transpose # Julia is column major
|
773
|
-
case kind
|
774
|
-
when :polarheatmap
|
775
|
-
GR.polarcellarray(0, 0, 0, 360, 0, 1, w, h, colors)
|
776
|
-
when :nonuniformpolarheatmap
|
777
|
-
ymax = y.max.to_f
|
778
|
-
ρ = y.map{|i| i / ymax}
|
779
|
-
θ = x.map { |i| i * 180 / Math::PI }
|
780
|
-
GR.nonuniformpolarcellarray(θ, ρ, w, h, colors)
|
781
|
-
end
|
782
|
-
draw_polar_axes
|
783
|
-
kvs[:zrange] = [cmin, cmax]
|
784
|
-
colorbar
|
785
|
-
|
786
|
-
when :contour, :contourf
|
787
|
-
zmin, zmax = kvs[:zrange]
|
788
|
-
if narray?(z) && z.ndim == 2
|
789
|
-
a, b = z.shape
|
790
|
-
x = (1..b).to_a
|
791
|
-
y = (1..a).to_a
|
792
|
-
zmin, zmax = z.minmax
|
793
|
-
elsif equal_length(x, y, z)
|
794
|
-
x, y, z = GR.gridit(x, y, z, 200, 200)
|
795
|
-
zmin, zmax = z.compact.minmax # compact : removed nil
|
796
|
-
end
|
797
|
-
|
798
|
-
# kvs[:zlim] is supposed to be Array or Range
|
799
|
-
if kvs.has_key?(:zlim)
|
800
|
-
zmin = kvs[:zlim].first if kvs[:zlim].first
|
801
|
-
zmax = kvs[:zlim].last if kvs[:zlim].last
|
802
|
-
end
|
803
|
-
|
804
|
-
GR.setspace(zmin, zmax, 0, 90)
|
805
|
-
levels = kvs[:levels] || 0
|
806
|
-
clabels = kvs[:clabels] || false
|
807
|
-
if levels.is_a? Integer
|
808
|
-
hmin, hmax = GR.adjustrange(zmin, zmax)
|
809
|
-
h = linspace(hmin, hmax, levels == 0 ? 21 : levels + 1)
|
810
|
-
else
|
811
|
-
h = levels
|
812
|
-
end
|
813
|
-
case kind
|
814
|
-
when :contour
|
815
|
-
GR._contour_(x, y, h, z, clabels ? 1 : 1000)
|
816
|
-
when :contourf
|
817
|
-
GR._contourf_(x, y, h, z, clabels ? 1 : 0)
|
818
|
-
end
|
819
|
-
colorbar(0, h.length)
|
820
|
-
|
821
|
-
when :hexbin
|
822
|
-
nbins = kvs[:nbins] || 40
|
823
|
-
cntmax = GR._hexbin_(x, y, nbins)
|
824
|
-
if cntmax > 0
|
825
|
-
kvs[:zrange] = [0, cntmax]
|
826
|
-
colorbar
|
827
|
-
end
|
828
|
-
|
829
|
-
when :heatmap, :nonuniformheatmap
|
830
|
-
case z
|
831
|
-
when Array
|
832
|
-
if z.all? { |zi| zi.size = z[0].size }
|
833
|
-
w = z.size
|
834
|
-
h = z[0].size
|
835
|
-
else
|
836
|
-
raise
|
837
|
-
end
|
838
|
-
when ->(obj) { narray?(obj) }
|
839
|
-
w, h = z.shape
|
840
|
-
else
|
841
|
-
raise
|
842
|
-
end
|
843
|
-
cmap = colormap
|
844
|
-
cmin, cmax = kvs[:crange]
|
845
|
-
levels = kvs[:levels] || 256
|
846
|
-
data = z.flatten.to_a.map { |i| normalize_color(i, cmin, cmax) } # NArray -> Array
|
847
|
-
if kind == :heatmap
|
848
|
-
rgba = data.map { |v| to_rgba(v, cmap) }
|
849
|
-
GR.drawimage(0.5, w + 0.5, h + 0.5, 0.5, w, h, rgba)
|
850
|
-
else
|
851
|
-
colors = data.map { |i| (1000 + i * 255).round }
|
852
|
-
GR.nonuniformcellarray(x, y, w, h, colors)
|
853
|
-
end
|
854
|
-
colorbar(0, levels)
|
855
|
-
|
856
|
-
when :wireframe
|
857
|
-
if narray?(z) && z.ndim == 2
|
858
|
-
a, b = z.shape
|
859
|
-
x = (1..b).to_a
|
860
|
-
y = (1..a).to_a
|
861
|
-
elsif equal_length(x, y, z)
|
862
|
-
x, y, z = GR.gridit(x, y, z, 50, 50)
|
863
|
-
end
|
864
|
-
GR.setfillcolorind(0)
|
865
|
-
GR._surface_(x, y, z, GR::OPTION_FILLED_MESH)
|
866
|
-
draw_axes(kind, 2)
|
867
|
-
|
868
|
-
when :surface
|
869
|
-
if narray?(z) && z.ndim == 2
|
870
|
-
a, b = z.shape
|
871
|
-
x = (1..b).to_a
|
872
|
-
y = (1..a).to_a
|
873
|
-
elsif equal_length(x, y, z)
|
874
|
-
x, y, z = GR.gridit(x, y, z, 200, 200)
|
875
|
-
end
|
876
|
-
if kvs[:accelerate] == false
|
877
|
-
GR._surface_(x, y, z, GR::OPTION_COLORED_MESH)
|
878
|
-
else
|
879
|
-
require 'gr3'
|
880
|
-
GR3.clear
|
881
|
-
GR3.surface(x, y, z, GR::OPTION_COLORED_MESH)
|
882
|
-
end
|
883
|
-
draw_axes(kind, 2)
|
884
|
-
colorbar(0.05)
|
885
|
-
|
886
|
-
when :volume
|
887
|
-
algorithm = kvs[:algorithm] || 0
|
888
|
-
require 'gr3'
|
889
|
-
GR3.clear
|
890
|
-
dmin, dmax = GR3.volume(z, algorithm)
|
891
|
-
draw_axes(kind, 2)
|
892
|
-
kvs[:zrange] = [dmin, dmax]
|
893
|
-
colorbar(0.05)
|
894
|
-
|
895
|
-
when :plot3
|
896
|
-
mask = GR.uselinespec(spec)
|
897
|
-
GR.polyline3d(x, y, z) if hasline(mask)
|
898
|
-
GR.polymarker3d(x, y, z) if hasmarker(mask)
|
899
|
-
draw_axes(kind, 2)
|
900
|
-
|
901
|
-
when :scatter3
|
902
|
-
GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
|
903
|
-
if c
|
904
|
-
cmin, cmax = kvs[:crange]
|
905
|
-
c = c.map { |i| normalize_color(i, cmin, cmax) }
|
906
|
-
cind = c.map { |i| (1000 + i * 255).round }
|
907
|
-
x.length.times do |i|
|
908
|
-
GR.setmarkercolorind(cind[i])
|
909
|
-
GR.polymarker3d([x[i]], [y[i]], [z[i]])
|
910
|
-
end
|
911
|
-
else
|
912
|
-
GR.polymarker3d(x, y, z)
|
913
|
-
end
|
914
|
-
draw_axes(kind, 2)
|
915
|
-
|
916
|
-
when :imshow
|
917
|
-
plot_img(z)
|
918
|
-
|
919
|
-
when :isosurface
|
920
|
-
plot_iso(z)
|
921
|
-
|
922
|
-
when :polar
|
923
|
-
GR.uselinespec(spec)
|
924
|
-
plot_polar(x, y)
|
925
|
-
|
926
|
-
when :trisurf
|
927
|
-
GR.trisurface(x, y, z)
|
928
|
-
draw_axes(kind, 2)
|
929
|
-
colorbar(0.05)
|
930
|
-
|
931
|
-
when :tricont
|
932
|
-
zmin, zmax = kvs[:zrange]
|
933
|
-
levels = linspace(zmin, zmax, 20)
|
934
|
-
GR.tricontour(x, y, z, levels)
|
935
|
-
|
936
|
-
when :shade
|
937
|
-
xform = kvs[:xform] || 5
|
938
|
-
if x.to_a.include? Float::NAN # FIXME: Ruby is different from Julia?
|
939
|
-
# How to check NArray?
|
940
|
-
GR.shadelines(x, y, xform: xform)
|
941
|
-
else
|
942
|
-
GR.shadepoints(x, y, xform: xform)
|
943
|
-
end
|
944
|
-
|
945
|
-
when :bar
|
946
|
-
0.step(x.length - 1, 2) do |i|
|
947
|
-
GR.setfillcolorind(989)
|
948
|
-
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
949
|
-
GR.fillrect(x[i], x[i + 1], y[i], y[i + 1])
|
950
|
-
GR.setfillcolorind(1)
|
951
|
-
GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
|
952
|
-
GR.fillrect(x[i], x[i + 1], y[i], y[i + 1])
|
953
|
-
end
|
954
|
-
end
|
955
|
-
|
956
|
-
GR.restorestate
|
957
|
-
end
|
958
|
-
|
959
|
-
draw_legend if %i[line step scatter stem].include?(kind) && kvs.has_key?(:labels)
|
960
|
-
|
961
|
-
if kvs[:update]
|
962
|
-
GR.updatews
|
963
|
-
# if GR.isinline()
|
964
|
-
# restore_context()
|
965
|
-
# return GR.show()
|
966
|
-
# end
|
967
|
-
end
|
968
|
-
|
969
|
-
# flag && restore_context()
|
970
|
-
end
|
971
|
-
|
972
|
-
def draw_legend
|
973
|
-
w, h = legend_size
|
974
|
-
viewport = kvs[:viewport]
|
975
|
-
location = kvs[:location] || 1
|
976
|
-
num_labels = kvs[:labels].length
|
977
|
-
GR.savestate
|
978
|
-
GR.selntran 0
|
979
|
-
GR.setscale 0
|
980
|
-
px = case location
|
981
|
-
when 11, 12, 13
|
982
|
-
viewport[1] + 0.11
|
983
|
-
when 8, 9, 10
|
984
|
-
0.5 * (viewport[0] + viewport[1] - w + 0.05)
|
985
|
-
when 2, 3, 6
|
986
|
-
viewport[0] + 0.11
|
987
|
-
else
|
988
|
-
viewport[1] - 0.05 - w
|
989
|
-
end
|
990
|
-
py = case location
|
991
|
-
when 5, 6, 7, 10, 12
|
992
|
-
0.5 * (viewport[2] + viewport[3] + h - 0.03)
|
993
|
-
when 13
|
994
|
-
viewport[2] + h
|
995
|
-
when 3, 4, 8
|
996
|
-
viewport[2] + h + 0.03
|
997
|
-
when 11
|
998
|
-
viewport[3] - 0.03
|
999
|
-
else
|
1000
|
-
viewport[3] - 0.06
|
1001
|
-
end
|
1002
|
-
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
1003
|
-
GR.setfillcolorind(0)
|
1004
|
-
GR.fillrect(px - 0.08, px + w + 0.02, py + 0.03, py - h)
|
1005
|
-
GR.setlinetype(GR::LINETYPE_SOLID)
|
1006
|
-
GR.setlinecolorind(1)
|
1007
|
-
GR.setlinewidth(1)
|
1008
|
-
GR.drawrect(px - 0.08, px + w + 0.02, py + 0.03, py - h)
|
1009
|
-
i = 0
|
1010
|
-
GR.uselinespec(' ')
|
1011
|
-
args.each do |_x, _y, _z, _c, spec|
|
1012
|
-
if i < num_labels
|
1013
|
-
label = kvs[:labels][i]
|
1014
|
-
label = label.to_s
|
1015
|
-
_tbx, tby = inqtext(0, 0, label)
|
1016
|
-
dy = [(tby[2] - tby[0]) - 0.03, 0].max
|
1017
|
-
py -= 0.5 * dy
|
1018
|
-
end
|
1019
|
-
GR.savestate
|
1020
|
-
mask = GR.uselinespec(spec || '')
|
1021
|
-
GR.polyline([px - 0.07, px - 0.01], [py, py]) if hasline(mask)
|
1022
|
-
GR.polymarker([px - 0.06, px - 0.02], [py, py]) if hasmarker(mask)
|
1023
|
-
GR.restorestate
|
1024
|
-
GR.settextalign(GR::TEXT_HALIGN_LEFT, GR::TEXT_VALIGN_HALF)
|
1025
|
-
if i < num_labels
|
1026
|
-
text(px, py, label)
|
1027
|
-
py -= 0.5 * dy
|
1028
|
-
i += 1
|
1029
|
-
end
|
1030
|
-
py -= 0.03
|
1031
|
-
end
|
1032
|
-
GR.selntran(1)
|
1033
|
-
GR.restorestate
|
1034
|
-
end
|
1035
|
-
|
1036
|
-
def to_svg
|
1037
|
-
## Need IRuby improvemend.
|
1038
|
-
GR.show(false) if ENV['GKS_WSTYPE'] == 'svg'
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
private
|
1042
|
-
|
1043
|
-
def hasline(mask)
|
1044
|
-
mask == 0x00 || (mask & 0x01 != 0)
|
1045
|
-
end
|
1046
|
-
|
1047
|
-
def hasmarker(mask)
|
1048
|
-
mask & 0x02 != 0
|
1049
|
-
end
|
1050
|
-
|
1051
|
-
def colormap
|
1052
|
-
# rgb
|
1053
|
-
Array.new(256) do |colorind|
|
1054
|
-
color = GR.inqcolor(1000 + colorind)
|
1055
|
-
[(color & 0xff) / 255.0,
|
1056
|
-
((color >> 8) & 0xff) / 255.0,
|
1057
|
-
((color >> 16) & 0xff) / 255.0]
|
1058
|
-
end
|
1059
|
-
end
|
1060
|
-
|
1061
|
-
def to_rgba(value, cmap)
|
1062
|
-
begin
|
1063
|
-
r, g, b = cmap[(value * 255).round]
|
1064
|
-
a = 1.0
|
1065
|
-
rescue StandardError # nil
|
1066
|
-
r = 0
|
1067
|
-
g = 0
|
1068
|
-
b = 0
|
1069
|
-
a = 0
|
1070
|
-
end
|
1071
|
-
|
1072
|
-
((a * 255).round << 24) + ((b * 255).round << 16) +
|
1073
|
-
((g * 255).round << 8) + (r * 255).round
|
1074
|
-
end
|
1075
|
-
|
1076
|
-
# https://gist.github.com/rysk-t/8d1aef0fb67abde1d259#gistcomment-1925021
|
1077
|
-
def linspace(low, high, num)
|
1078
|
-
[*0..(num - 1)].collect { |i| low + i.to_f * (high - low) / (num - 1) }
|
1079
|
-
end
|
1080
|
-
|
1081
|
-
def plot_args(args)
|
1082
|
-
# FIXME
|
1083
|
-
args = [args] unless args.all? do |i|
|
1084
|
-
i.is_a?(Array) && (i[0].is_a?(Array) || narray?(i[0]))
|
1085
|
-
end
|
1086
|
-
args.map do |xyzc|
|
1087
|
-
spec = nil
|
1088
|
-
case xyzc.last
|
1089
|
-
when String
|
1090
|
-
spec = xyzc.pop
|
1091
|
-
when Hash
|
1092
|
-
spec = xyzc.pop[:spec]
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
x, y, z, c = xyzc.map do |i|
|
1096
|
-
if i.is_a?(Array) || narray?(i) || i.nil?
|
1097
|
-
i
|
1098
|
-
elsif i.respond_to?(:to_a)
|
1099
|
-
# Convert an Array-like class such as Daru::Vector to an Array
|
1100
|
-
i.to_a
|
1101
|
-
else # String
|
1102
|
-
i
|
1103
|
-
end
|
1104
|
-
end
|
1105
|
-
[x, y, z, c, spec]
|
1106
|
-
end
|
1107
|
-
end
|
1108
|
-
|
1109
|
-
# Normalize a color c with the range [cmin, cmax]
|
1110
|
-
# 0 <= normalize_color(c, cmin, cmax) <= 1
|
1111
|
-
# Note: narray.map{|i| normalize_color(i)} There's room for speedup.
|
1112
|
-
def normalize_color(c, cmin, cmax)
|
1113
|
-
c = c.to_f # if c is Integer
|
1114
|
-
c = c.clamp(cmin, cmax) - cmin
|
1115
|
-
c /= (cmax - cmin) if cmin != cmax
|
1116
|
-
c
|
1117
|
-
end
|
1118
|
-
|
1119
|
-
def inqtext(x, y, s)
|
1120
|
-
s = s.to_s
|
1121
|
-
if s.length >= 2 && s[0] == '$' && s[-1] == '$'
|
1122
|
-
GR.inqmathtex(x, y, s[1..-2])
|
1123
|
-
elsif s.include?('\\') || s.include?('_') || s.include?('^')
|
1124
|
-
GR.inqtextext(x, y, s)
|
1125
|
-
else
|
1126
|
-
GR.inqtext(x, y, s)
|
1127
|
-
end
|
1128
|
-
end
|
1129
|
-
|
1130
|
-
def text(x, y, s)
|
1131
|
-
s = s.to_s
|
1132
|
-
if s.length >= 2 && s[0] == '$' && s[-1] == '$'
|
1133
|
-
GR.mathtex(x, y, s[1..-2])
|
1134
|
-
elsif s.include?('\\') || s.include?('_') || s.include?('^')
|
1135
|
-
GR.textext(x, y, s)
|
1136
|
-
else
|
1137
|
-
GR.text(x, y, s)
|
1138
|
-
end
|
1139
|
-
end
|
1140
|
-
|
1141
|
-
def fix_minmax(a, b)
|
1142
|
-
if a == b
|
1143
|
-
a -= a != 0 ? 0.1 * a : 0.1
|
1144
|
-
b += b != 0 ? 0.1 * b : 0.1
|
1145
|
-
end
|
1146
|
-
[a, b]
|
1147
|
-
end
|
1148
|
-
|
1149
|
-
def minmax
|
1150
|
-
xmin = ymin = zmin = cmin = Float::INFINITY
|
1151
|
-
xmax = ymax = zmax = cmax = -Float::INFINITY
|
1152
|
-
scale = kvs[:scale]
|
1153
|
-
args.each do |x, y, z, c|
|
1154
|
-
if x
|
1155
|
-
if scale & GR::OPTION_X_LOG != 0
|
1156
|
-
# duck typing for NArray
|
1157
|
-
x = x.map { |v| v > 0 ? v : Float::NAN }
|
1158
|
-
end
|
1159
|
-
x0, x1 = x.minmax
|
1160
|
-
xmin = [x0, xmin].min
|
1161
|
-
xmax = [x1, xmax].max
|
1162
|
-
else
|
1163
|
-
xmin = 0
|
1164
|
-
xmax = 1
|
1165
|
-
end
|
1166
|
-
if y
|
1167
|
-
if scale & GR::OPTION_Y_LOG != 0
|
1168
|
-
y = y.map { |v| v > 0 ? v : Float::NAN }
|
1169
|
-
end
|
1170
|
-
y0, y1 = y.minmax
|
1171
|
-
ymin = [y0, ymin].min
|
1172
|
-
ymax = [y1, ymax].max
|
1173
|
-
else
|
1174
|
-
ymin = 0
|
1175
|
-
ymax = 1
|
1176
|
-
end
|
1177
|
-
if z
|
1178
|
-
if scale & GR::OPTION_Z_LOG != 0
|
1179
|
-
z = z.map { |v| v > 0 ? v : Float::NAN }
|
1180
|
-
end
|
1181
|
-
z0, z1 = z.minmax
|
1182
|
-
zmin = [z0, zmin].min
|
1183
|
-
zmax = [z1, zmax].max
|
1184
|
-
end
|
1185
|
-
if c
|
1186
|
-
c0, c1 = c.minmax
|
1187
|
-
cmin = [c0, cmin].min
|
1188
|
-
cmax = [c1, cmax].max
|
1189
|
-
elsif z
|
1190
|
-
z0, z1 = z.minmax
|
1191
|
-
cmin = [z0, zmin].min
|
1192
|
-
cmax = [z1, zmax].max
|
1193
|
-
end
|
1194
|
-
end
|
1195
|
-
xmin, xmax = fix_minmax(xmin, xmax)
|
1196
|
-
ymin, ymax = fix_minmax(ymin, ymax)
|
1197
|
-
zmin, zmax = fix_minmax(zmin, zmax)
|
1198
|
-
|
1199
|
-
# kvs[:xlim], kvs[:ylim], kvs[:zlim] is supposed to be Array or Range
|
1200
|
-
kvs[:xrange] = [(kvs[:xlim]&.first || xmin), (kvs[:xlim]&.last || xmax)]
|
1201
|
-
kvs[:yrange] = [(kvs[:ylim]&.first || ymin), (kvs[:ylim]&.last || ymax)]
|
1202
|
-
kvs[:zrange] = [(kvs[:zlim]&.first || zmin), (kvs[:zlim]&.last || zmax)]
|
1203
|
-
|
1204
|
-
if kvs.has_key?(:clim)
|
1205
|
-
c0, c1 = kvs[:clim]
|
1206
|
-
c0 ||= cmin
|
1207
|
-
c1 ||= cmax
|
1208
|
-
kvs[:crange] = [c0, c1]
|
1209
|
-
else
|
1210
|
-
kvs[:crange] = [cmin, cmax]
|
1211
|
-
end
|
1212
|
-
end
|
1213
|
-
|
1214
|
-
def legend_size
|
1215
|
-
scale = GR.inqscale
|
1216
|
-
GR.selntran(0)
|
1217
|
-
GR.setscale(0)
|
1218
|
-
w = 0
|
1219
|
-
h = 0
|
1220
|
-
kvs[:labels].each do |label|
|
1221
|
-
label = label.to_s
|
1222
|
-
tbx, tby = inqtext(0, 0, label)
|
1223
|
-
w = [w, tbx[2] - tbx[0]].max
|
1224
|
-
h += [tby[2] - tby[0], 0.03].max
|
1225
|
-
end
|
1226
|
-
GR.setscale(scale)
|
1227
|
-
GR.selntran(1)
|
1228
|
-
[w, h]
|
1229
|
-
end
|
1230
|
-
|
1231
|
-
def equal_length(*args)
|
1232
|
-
GRCommons::GRCommonUtils.equal_length(*args)
|
1233
|
-
end
|
1234
|
-
|
1235
|
-
def narray?(data)
|
1236
|
-
GRCommons::GRCommonUtils.narray?(data)
|
1237
|
-
end
|
1238
|
-
end
|
1239
|
-
|
1240
|
-
class << self
|
1241
|
-
# (Plot) Draw one or more line plots.
|
1242
|
-
def plot(*args)
|
1243
|
-
create_plot(:line, *args)
|
1244
|
-
end
|
1245
|
-
|
1246
|
-
# (Plot) Draw one or more step or staircase plots.
|
1247
|
-
def step(*args)
|
1248
|
-
create_plot(:step, *args)
|
1249
|
-
end
|
1250
|
-
|
1251
|
-
# (Plot) Draw one or more scatter plots.
|
1252
|
-
def scatter(*args)
|
1253
|
-
create_plot(:scatter, *args)
|
1254
|
-
end
|
1255
|
-
|
1256
|
-
# (Plot) Draw a stem plot.
|
1257
|
-
def stem(*args)
|
1258
|
-
create_plot(:stem, *args)
|
1259
|
-
end
|
1260
|
-
|
1261
|
-
# (Plot)
|
1262
|
-
def polarhistogram(x, kv = {})
|
1263
|
-
plt = GR::Plot.new(x, kv)
|
1264
|
-
plt.kvs[:kind] = :polarhist
|
1265
|
-
nbins = plt.kvs[:nbins] || 0
|
1266
|
-
x, y = hist(x, nbins)
|
1267
|
-
plt.args = [[x, y, nil, nil, '']]
|
1268
|
-
plt.plot_data
|
1269
|
-
end
|
1270
|
-
|
1271
|
-
# (Plot) Draw a heatmap.
|
1272
|
-
def heatmap(*args)
|
1273
|
-
# FIXME
|
1274
|
-
args, kv = format_xyzc(*args)
|
1275
|
-
_x, _y, z = args
|
1276
|
-
ysize, xsize = z.shape
|
1277
|
-
z = z.reshape(xsize, ysize)
|
1278
|
-
create_plot(:heatmap, kv) do |plt|
|
1279
|
-
plt.kvs[:xlim] ||= [0.5, xsize + 0.5]
|
1280
|
-
plt.kvs[:ylim] ||= [0.5, ysize + 0.5]
|
1281
|
-
plt.args = [[(1..xsize).to_a, (1..ysize).to_a, z, nil, '']]
|
1282
|
-
end
|
1283
|
-
end
|
1284
|
-
|
1285
|
-
# (Plot) Draw a polarheatmap.
|
1286
|
-
def polarheatmap(*args)
|
1287
|
-
d = args.shift
|
1288
|
-
# FIXME
|
1289
|
-
z = Numo::DFloat.cast(d)
|
1290
|
-
raise 'expected 2-D array' unless z.ndim == 2
|
1291
|
-
|
1292
|
-
create_plot(:polarheatmap, z, *args) do |plt|
|
1293
|
-
width, height = z.shape
|
1294
|
-
plt.kvs[:xlim] ||= [0.5, width + 0.5]
|
1295
|
-
plt.kvs[:ylim] ||= [0.5, height + 0.5]
|
1296
|
-
plt.args = [[(1..width).to_a, (1..height).to_a, z, nil, '']]
|
1297
|
-
end
|
1298
|
-
end
|
1299
|
-
|
1300
|
-
# (Plot) Draw a nonuniformpolarheatmap.
|
1301
|
-
def nonuniformpolarheatmap(*args)
|
1302
|
-
# FIXME
|
1303
|
-
args, kv = format_xyzc(*args)
|
1304
|
-
_x, _y, z = args
|
1305
|
-
ysize, xsize = z.shape
|
1306
|
-
z = z.reshape(xsize, ysize)
|
1307
|
-
create_plot(:nonuniformpolarheatmap, kv) do |plt|
|
1308
|
-
plt.kvs[:xlim] ||= [0.5, xsize + 0.5]
|
1309
|
-
plt.kvs[:ylim] ||= [0.5, ysize + 0.5]
|
1310
|
-
plt.args = [[(1..xsize).to_a, (1..ysize).to_a, z, nil, '']]
|
1311
|
-
end
|
1312
|
-
end
|
1313
|
-
|
1314
|
-
alias _contour_ contour
|
1315
|
-
# (Plot) Draw a contour plot.
|
1316
|
-
def contour(*args)
|
1317
|
-
create_plot(:contour, *format_xyzc(*args))
|
1318
|
-
end
|
1319
|
-
|
1320
|
-
alias _contourf_ contourf
|
1321
|
-
# (Plot) Draw a filled contour plot.
|
1322
|
-
def contourf(*args)
|
1323
|
-
create_plot(:contourf, *format_xyzc(*args))
|
1324
|
-
end
|
1325
|
-
|
1326
|
-
alias _hexbin_ hexbin
|
1327
|
-
# (Plot) Draw a hexagon binning plot.
|
1328
|
-
def hexbin(*args)
|
1329
|
-
create_plot(:hexbin, *args)
|
1330
|
-
end
|
1331
|
-
|
1332
|
-
# (Plot) Draw a triangular contour plot.
|
1333
|
-
def tricont(*args)
|
1334
|
-
create_plot(:tricont, *format_xyzc(*args))
|
1335
|
-
end
|
1336
|
-
|
1337
|
-
# (Plot) Draw a three-dimensional wireframe plot.
|
1338
|
-
def wireframe(*args)
|
1339
|
-
create_plot(:wireframe, *format_xyzc(*args))
|
1340
|
-
end
|
1341
|
-
|
1342
|
-
# (Plot) Draw a three-dimensional surface plot.
|
1343
|
-
alias _surface_ surface
|
1344
|
-
def surface(*args)
|
1345
|
-
create_plot(:surface, *format_xyzc(*args))
|
1346
|
-
end
|
1347
|
-
|
1348
|
-
# (Plot)
|
1349
|
-
def polar(*args)
|
1350
|
-
create_plot(:polar, *args)
|
1351
|
-
end
|
1352
|
-
|
1353
|
-
# (Plot) Draw a triangular surface plot.
|
1354
|
-
def trisurf(*args)
|
1355
|
-
create_plot(:trisurf, *format_xyzc(*args))
|
1356
|
-
end
|
1357
|
-
|
1358
|
-
# (Plot) Draw one or more three-dimensional line plots.
|
1359
|
-
def plot3(*args)
|
1360
|
-
create_plot(:plot3, *args)
|
1361
|
-
end
|
1362
|
-
|
1363
|
-
# (Plot) Draw one or more three-dimensional scatter plots.
|
1364
|
-
def scatter3(*args)
|
1365
|
-
create_plot(:scatter3, *args)
|
1366
|
-
end
|
1367
|
-
|
1368
|
-
alias _shade_ shade
|
1369
|
-
# (Plot)
|
1370
|
-
def shade(*args)
|
1371
|
-
create_plot(:shade, *args)
|
1372
|
-
end
|
1373
|
-
|
1374
|
-
# (Plot)
|
1375
|
-
def volume(v, kv = {})
|
1376
|
-
create_plot(:volume, v, kv) do |plt|
|
1377
|
-
plt.args = [[nil, nil, v, nil, '']]
|
1378
|
-
end
|
1379
|
-
end
|
1380
|
-
|
1381
|
-
# (Plot) Draw a bar plot.
|
1382
|
-
def barplot(labels, heights, kv = {})
|
1383
|
-
labels = labels.map(&:to_s)
|
1384
|
-
wc, hc = barcoordinates(heights)
|
1385
|
-
create_plot(:bar, labels, heights, kv) do |plt|
|
1386
|
-
if kv[:horizontal]
|
1387
|
-
plt.args = [[hc, wc, nil, nil, '']]
|
1388
|
-
plt.kvs[:yticks] = [1, 1]
|
1389
|
-
plt.kvs[:yticklabels] = labels
|
1390
|
-
else
|
1391
|
-
plt.args = [[wc, hc, nil, nil, '']]
|
1392
|
-
plt.kvs[:xticks] = [1, 1]
|
1393
|
-
plt.kvs[:xticklabels] = labels
|
1394
|
-
end
|
1395
|
-
end
|
1396
|
-
end
|
1397
|
-
|
1398
|
-
# (Plot) Draw a histogram.
|
1399
|
-
def histogram(series, kv = {})
|
1400
|
-
create_plot(:hist, series, kv) do |plt|
|
1401
|
-
nbins = plt.kvs[:nbins] || 0
|
1402
|
-
x, y = hist(series, nbins)
|
1403
|
-
plt.args = if kv[:horizontal]
|
1404
|
-
[[y, x, nil, nil, '']]
|
1405
|
-
else
|
1406
|
-
[[x, y, nil, nil, '']]
|
1407
|
-
end
|
1408
|
-
end
|
1409
|
-
end
|
1410
|
-
|
1411
|
-
# (Plot) Draw an image.
|
1412
|
-
def imshow(img, kv = {})
|
1413
|
-
img = Numo::DFloat.cast(img) # Umm...
|
1414
|
-
create_plot(:imshow, img, kv) do |plt|
|
1415
|
-
plt.args = [[nil, nil, img, nil, '']]
|
1416
|
-
end
|
1417
|
-
end
|
1418
|
-
|
1419
|
-
# (Plot) Draw an isosurface.
|
1420
|
-
def isosurface(v, kv = {})
|
1421
|
-
v = Numo::DFloat.cast(v) # Umm...
|
1422
|
-
create_plot(:isosurface, v, kv) do |plt|
|
1423
|
-
plt.args = [[nil, nil, v, nil, '']]
|
1424
|
-
end
|
1425
|
-
end
|
1426
|
-
|
1427
|
-
def hold(flag = true)
|
1428
|
-
plt = GR::Plot.last_plot
|
1429
|
-
plt.kvs.slice(:window, :scale, :xaxis, :yaxis, :zaxis).merge({ ax: flag, clear: !flag })
|
1430
|
-
end
|
1431
|
-
|
1432
|
-
# Set current subplot index.
|
1433
|
-
def subplot(nr, nc, p, kv = {})
|
1434
|
-
xmin = 1
|
1435
|
-
xmax = 0
|
1436
|
-
ymin = 1
|
1437
|
-
ymax = 0
|
1438
|
-
p = [p] if p.is_a? Integer
|
1439
|
-
p.each do |i|
|
1440
|
-
r = (nr - (i - 1) / nc).to_f
|
1441
|
-
c = ((i - 1) % nc + 1).to_f
|
1442
|
-
xmin = [xmin, (c - 1) / nc].min
|
1443
|
-
xmax = [xmax, c / nc].max
|
1444
|
-
ymin = [ymin, (r - 1) / nr].min
|
1445
|
-
ymax = [ymax, r / nr].max
|
1446
|
-
end
|
1447
|
-
{
|
1448
|
-
subplot: [xmin, xmax, ymin, ymax],
|
1449
|
-
# The policy of clearing when p[0]==1 is controversial
|
1450
|
-
clear: p[0] == 1,
|
1451
|
-
update: p[-1] == nr * nc
|
1452
|
-
}.merge kv
|
1453
|
-
end
|
1454
|
-
|
1455
|
-
# (Plot) Save the current figure to a file.
|
1456
|
-
def savefig(filename, kv = {})
|
1457
|
-
GR.beginprint(filename)
|
1458
|
-
plt = GR::Plot.last_plot
|
1459
|
-
plt.kvs.merge!(kv)
|
1460
|
-
plt.plot_data(false)
|
1461
|
-
GR.endprint
|
1462
|
-
end
|
1463
|
-
|
1464
|
-
private
|
1465
|
-
|
1466
|
-
def create_plot(type, *args)
|
1467
|
-
plt = GR::Plot.new(*args)
|
1468
|
-
plt.kvs[:kind] = type
|
1469
|
-
yield(plt) if block_given?
|
1470
|
-
plt.plot_data
|
1471
|
-
plt
|
1472
|
-
end
|
1473
|
-
|
1474
|
-
def format_xyzc(*args)
|
1475
|
-
kv = if args[-1].is_a? Hash
|
1476
|
-
args.pop
|
1477
|
-
else
|
1478
|
-
{}
|
1479
|
-
end
|
1480
|
-
|
1481
|
-
args = [args] unless args.all? do |i|
|
1482
|
-
i.is_a?(Array) && (i[0].is_a?(Array) || narray?(i[0]))
|
1483
|
-
end
|
1484
|
-
args.map! do |xyzc|
|
1485
|
-
if xyzc.size == 1
|
1486
|
-
if xyzc[0].is_a? Array
|
1487
|
-
z = Numo::DFloat.cast(xyzc[0])
|
1488
|
-
elsif narray?(xyzc[0])
|
1489
|
-
z = xyzc[0]
|
1490
|
-
end
|
1491
|
-
xsize, ysize = z.shape
|
1492
|
-
x = (1..ysize).to_a * xsize
|
1493
|
-
y = (1..xsize).map { |i| Array.new(ysize, i) }.flatten
|
1494
|
-
[x, y, z]
|
1495
|
-
else
|
1496
|
-
|
1497
|
-
xyzc
|
1498
|
-
end
|
1499
|
-
end
|
1500
|
-
[*args, kv]
|
1501
|
-
end
|
1502
|
-
|
1503
|
-
def hist(x, nbins = 0)
|
1504
|
-
nbins = (3.3 * Math.log10(x.length)).round + 1 if nbins <= 1
|
1505
|
-
begin
|
1506
|
-
require 'histogram/array'
|
1507
|
-
rescue LoadError => e
|
1508
|
-
e.message << " Please add gem 'histogram' to your project's Gemfile."
|
1509
|
-
raise e
|
1510
|
-
end
|
1511
|
-
x = x.to_a if narray?(x)
|
1512
|
-
x, y = x.histogram(nbins, bin_boundary: :min)
|
1513
|
-
x.push(x[-1] + x[1] - x[0])
|
1514
|
-
[x, y]
|
1515
|
-
end
|
1516
|
-
|
1517
|
-
def barcoordinates(heights, barwidth = 0.8, baseline = 0.0)
|
1518
|
-
halfw = barwidth / 2.0
|
1519
|
-
wc = []
|
1520
|
-
hc = []
|
1521
|
-
heights.each_with_index do |value, i|
|
1522
|
-
wc << i - halfw
|
1523
|
-
wc << i + halfw
|
1524
|
-
hc << baseline
|
1525
|
-
hc << value
|
1526
|
-
end
|
1527
|
-
[wc, hc]
|
1528
|
-
end
|
1529
|
-
end
|
1530
|
-
end
|