ruby-gr 0.0.19 → 0.0.24

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.
@@ -174,7 +174,7 @@ module GR
174
174
  try_extern 'void gr_shadepoints(int, double *, double *, int, int, int)'
175
175
  try_extern 'void gr_shadelines(int, double *, double *, int, int, int)'
176
176
  try_extern 'void gr_panzoom(double, double, double, double, double *, double *, double *, double *)'
177
- # try_extern 'int gr_findboundary(int, double *, double *, double, double (*)(double, double), int, int *)'
177
+ try_extern 'int gr_findboundary(int, double *, double *, double, double (*)(double, double), int, int *)'
178
178
  try_extern 'void gr_setresamplemethod(unsigned int flag)'
179
179
  try_extern 'void gr_inqresamplemethod(unsigned int *flag)'
180
180
  try_extern 'void gr_path(int, double *, double *, const char *)'
@@ -202,5 +202,6 @@ module GR
202
202
  try_extern 'void gr_inqtext3d(double, double, double, char *, int axis, double *, double *)'
203
203
  try_extern 'void gr_settextencoding(int)'
204
204
  try_extern 'void gr_inqtextencoding(int *)'
205
+ # gr_setcallback(char *(*)(const char *));
205
206
  end
206
207
  end
@@ -38,59 +38,95 @@ module GR
38
38
 
39
39
  # Keyword options conform to GR.jl.
40
40
  KW_ARGS = %i[accelerate algorithm alpha ax backgroundcolor barwidth baseline
41
- clabels clear clim color colormap crange figsize horizontal
42
- isovalue kind label labels levels location nbins ratio rotation
43
- scale size spec subplot tilt title update xaxis xflip xform
44
- xlabel xlim xlog xrange yaxis yflip ylabel ylim ylog zflip
45
- yrange viewport vp where window zaxis zlabel zlim zlog zrange].freeze
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
+ pingfangsc: 234
83
+ }.freeze
46
84
 
47
85
  @last_plot = nil
48
86
  class << self
49
87
  attr_accessor :last_plot
50
88
  end
51
89
 
52
- def initialize(*args)
53
- @kvs = if args[-1].is_a? Hash
54
- args.pop
55
- else
56
- {}
57
- end
90
+ attr_accessor :args, :kvs, :scheme
91
+
92
+ def initialize(*raw_args)
93
+ @kvs = raw_args.last.is_a?(Hash) ? raw_args.pop : {}
94
+ @args = plot_args(raw_args) # method name is the same as Julia/Python
95
+
58
96
  # Check keyword options.
59
- @kvs.each_key do |k|
60
- warn "Unknown keyword: #{k}" unless KW_ARGS.include? k
61
- end
97
+ kvs.each_key { |k| warn "Unknown keyword: #{k}" unless KW_ARGS.include? k }
62
98
 
63
99
  # label(singular form) is a original keyword arg which GR.jl does not have.
64
- @kvs[:labels] = [@kvs[:label]] if @kvs[:label] && @kvs[:labels].nil?
65
-
66
- @args = plot_args(args) # method name is the same as Julia/Python
67
- @kvs[:size] ||= [600, 450]
68
- @kvs[:ax] = false if @kvs[:ax].nil?
69
- @kvs[:subplot] ||= [0, 1, 0, 1]
70
- @kvs[:clear] = true if @kvs[:clear].nil?
71
- @kvs[:update] = true if @kvs[:update].nil?
72
- @scheme = 0
100
+ kvs[:labels] ||= [kvs[:label]] if kvs.has_key? :label
101
+
102
+ # Don't use ||= here, because we need to tell `false` from `nil`
103
+ kvs[:size] = [600, 450] unless kvs.has_key? :size
104
+ kvs[:ax] = false unless kvs.has_key? :ax
105
+ kvs[:subplot] = [0, 1, 0, 1] unless kvs.has_key? :subplot
106
+ kvs[:clear] = true unless kvs.has_key? :clear
107
+ kvs[:update] = true unless kvs.has_key? :update
108
+
109
+ @scheme = 0
73
110
  @background = 0xffffff
74
- @handle = nil
111
+ # @handle = nil # This variable will be used in gr_meta
112
+
75
113
  self.class.last_plot = self
76
114
  end
77
- attr_accessor :args, :kvs, :scheme
78
115
 
79
116
  def set_viewport(kind, subplot)
80
117
  mwidth, mheight, width, height = GR.inqdspsize
81
- if kvs[:figsize]
82
- w = 0.0254 * width * kvs[:figsize][0] / mwidth
83
- h = 0.0254 * height * kvs[:figsize][1] / mheight
84
- else
85
- dpi = width / mwidth * 0.0254
86
- if dpi > 200
87
- w, h = kvs[:size].map { |x| x * dpi / 100 }
88
- else
89
- w, h = kvs[:size]
90
- end
91
- end
92
- viewport = [0, 0, 0, 0]
118
+ dpi = width / mwidth * 0.0254
119
+ w, h = if kvs[:figsize]
120
+ [(0.0254 * width * kvs[:figsize][0] / mwidth),
121
+ (0.0254 * height * kvs[:figsize][1] / mheight)]
122
+ elsif dpi > 200
123
+ kvs[:size].map { |i| i * dpi / 100 }
124
+ else
125
+ kvs[:size]
126
+ end
127
+
93
128
  vp = subplot.clone
129
+
94
130
  if w > h
95
131
  ratio = h / w.to_f
96
132
  msize = mwidth * w / width
@@ -106,6 +142,7 @@ module GR
106
142
  vp[0] *= ratio
107
143
  vp[1] *= ratio
108
144
  end
145
+
109
146
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
110
147
  extent = [vp[1] - vp[0], vp[3] - vp[2]].min
111
148
  vp1 = 0.5 * (vp[0] + vp[1] - extent)
@@ -115,10 +152,12 @@ module GR
115
152
  else
116
153
  vp1, vp2, vp3, vp4 = vp
117
154
  end
118
- viewport[0] = vp1 + 0.125 * (vp2 - vp1)
119
- viewport[1] = vp1 + 0.925 * (vp2 - vp1)
120
- viewport[2] = vp3 + 0.125 * (vp4 - vp3)
121
- viewport[3] = vp3 + 0.925 * (vp4 - vp3)
155
+
156
+ viewport = [vp1 + 0.125 * (vp2 - vp1),
157
+ vp1 + 0.925 * (vp2 - vp1),
158
+ vp3 + 0.125 * (vp4 - vp3),
159
+ vp3 + 0.925 * (vp4 - vp3)]
160
+
122
161
  if %i[contour contourf hexbin heatmap nonuniformheatmap polarheatmap
123
162
  surface trisurf volume].include?(kind)
124
163
  viewport[1] -= 0.1
@@ -132,11 +171,11 @@ module GR
132
171
  end
133
172
  end
134
173
 
135
- GR.setviewport(viewport[0], viewport[1], viewport[2], viewport[3])
174
+ GR.setviewport(*viewport)
136
175
 
137
176
  kvs[:viewport] = viewport
138
- kvs[:vp] = vp
139
- kvs[:ratio] = ratio
177
+ kvs[:vp] = vp
178
+ kvs[:ratio] = ratio
140
179
 
141
180
  if kvs[:backgroundcolor]
142
181
  GR.savestate
@@ -166,14 +205,15 @@ module GR
166
205
  def set_window(kind)
167
206
  scale = 0
168
207
  unless %i[polar polarhist polarheatmap].include?(kind)
169
- scale |= GR::OPTION_X_LOG if kvs[:xlog]
170
- scale |= GR::OPTION_Y_LOG if kvs[:ylog]
171
- scale |= GR::OPTION_Z_LOG if kvs[:zlog]
208
+ scale |= GR::OPTION_X_LOG if kvs[:xlog]
209
+ scale |= GR::OPTION_Y_LOG if kvs[:ylog]
210
+ scale |= GR::OPTION_Z_LOG if kvs[:zlog]
172
211
  scale |= GR::OPTION_FLIP_X if kvs[:xflip]
173
212
  scale |= GR::OPTION_FLIP_Y if kvs[:yflip]
174
213
  scale |= GR::OPTION_FLIP_Z if kvs[:zflip]
175
214
  end
176
215
  kvs[:scale] = scale
216
+
177
217
  if kvs.has_key?(:panzoom)
178
218
  xmin, xmax, ymin, ymax = GR.panzoom(*kvs[:panzoom])
179
219
  kvs[:xrange] = [xmin, xmax]
@@ -182,68 +222,81 @@ module GR
182
222
  minmax
183
223
  end
184
224
 
185
- major_count = %i[wireframe surface plot3 scatter3 polar polarhist
186
- polarheatmap trisurf volume].include?(kind) ? 2 : 5
225
+ major_count = if %i[wireframe surface plot3 scatter3 polar polarhist
226
+ polarheatmap trisurf volume].include?(kind)
227
+ 2
228
+ else
229
+ 5
230
+ end
231
+
232
+ kvs[:xticks] = [kvs[:xticks], major_count] if kvs[:xticks].is_a? Numeric
233
+ kvs[:yticks] = [kvs[:yticks], major_count] if kvs[:yticks].is_a? Numeric
234
+ kvs[:zticks] = [kvs[:zticks], major_count] if kvs[:zticks].is_a? Numeric
187
235
 
188
236
  xmin, xmax = kvs[:xrange]
189
- if (scale & GR::OPTION_X_LOG) == 0
190
- xmin, xmax = GR.adjustlimits(xmin, xmax) unless kvs.has_key?(:xlim) || kvs.has_key?(:panzoom)
191
- if kvs.has_key?(:xticks)
192
- xtick, majorx = kvs[:xticks]
193
- else
194
- majorx = major_count
195
- xtick = GR.tick(xmin, xmax) / majorx
196
- end
197
- else
198
- xtick = majorx = 1
237
+ if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:xlim)
238
+ xmin -= 0.5
239
+ xmax += 0.5
199
240
  end
200
- xorg = if (scale & GR::OPTION_FLIP_X) == 0
201
- [xmin, xmax]
202
- else
203
- [xmax, xmin]
204
- end
241
+ xtick, majorx = if (scale & GR::OPTION_X_LOG) == 0
242
+ unless %i[heatmap polarheatmap].include?(kind)
243
+ unless kvs.has_key?(:xlim)
244
+ xmin, xmax = GR.adjustlimits(xmin, xmax) unless kvs[:panzoom]
245
+ end
246
+ end
247
+ if kvs.has_key?(:xticks)
248
+ kvs[:xticks]
249
+ else
250
+ [GR.tick(xmin, xmax) / major_count, major_count]
251
+ end
252
+ else
253
+ [1, 1]
254
+ end
255
+ xorg = (scale & GR::OPTION_FLIP_X) == 0 ? [xmin, xmax] : [xmax, xmin]
205
256
  kvs[:xaxis] = xtick, xorg, majorx
206
257
 
207
258
  ymin, ymax = kvs[:yrange]
208
- if kind == :hist && !kvs.has_key?(:ylim)
209
- ymin = (scale & GR::OPTION_Y_LOG) == 0 ? 0 : 1
259
+ if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:ylim)
260
+ ymin -= 0.5
261
+ ymax += 0.5
210
262
  end
211
- if (scale & GR::OPTION_Y_LOG) == 0
212
- ymin, ymax = GR.adjustlimits(ymin, ymax) unless kvs.has_key?(:ylim) || kvs.has_key?(:panzoom)
213
- if kvs.has_key?(:yticks)
214
- ytick, majory = kvs[:yticks]
215
- else
216
- majory = major_count
217
- ytick = GR.tick(ymin, ymax) / majory
263
+ if kind == :hist
264
+ if kvs[:horizontal] && !kvs.has_key?(:xlim)
265
+ xmin = (scale & GR::OPTION_X_LOG) == 0 ? 0 : 1
266
+ elsif !kvs.has_key?(:ylim)
267
+ ymin = (scale & GR::OPTION_Y_LOG) == 0 ? 0 : 1
218
268
  end
219
- else
220
- ytick = majory = 1
221
269
  end
222
- yorg = if (scale & GR::OPTION_FLIP_Y) == 0
223
- [ymin, ymax]
224
- else
225
- [ymax, ymin]
226
- end
270
+ ytick, majory = if (scale & GR::OPTION_Y_LOG) == 0
271
+ unless %i[heatmap polarheatmap].include?(kind)
272
+ unless kvs.has_key?(:ylim)
273
+ ymin, ymax = GR.adjustlimits(ymin, ymax) unless kvs[:panzoom]
274
+ end
275
+ end
276
+ if kvs.has_key?(:yticks)
277
+ kvs[:yticks]
278
+ else
279
+ [GR.tick(ymin, ymax) / major_count, major_count]
280
+ end
281
+ else
282
+ [1, 1]
283
+ end
284
+ yorg = (scale & GR::OPTION_FLIP_Y) == 0 ? [ymin, ymax] : [ymax, ymin]
227
285
  kvs[:yaxis] = ytick, yorg, majory
228
286
 
229
287
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
230
288
  zmin, zmax = kvs[:zrange]
231
- if (scale & GR::OPTION_Z_LOG) == 0
232
- zmin, zmax = GR.adjustlimits(zmin, zmax) if kvs.has_key?(:zlim)
233
- if kvs.has_key?(:zticks)
234
- ztick, majorz = kvs[:zticks]
235
- else
236
- majorz = major_count
237
- ztick = GR.tick(zmin, zmax) / majorz
238
- end
239
- else
240
- ztick = majorz = 1
241
- end
242
- zorg = if (scale & GR::OPTION_FLIP_Z) == 0
243
- [zmin, zmax]
244
- else
245
- [zmax, zmin]
246
- end
289
+ ztick, majorz = if (scale & GR::OPTION_Z_LOG) == 0
290
+ zmin, zmax = GR.adjustlimits(zmin, zmax) if kvs.has_key?(:zlim)
291
+ if kvs.has_key?(:zticks)
292
+ kvs[:zticks]
293
+ else
294
+ [GR.tick(zmin, zmax) / major_count, major_count]
295
+ end
296
+ else
297
+ [1, 1]
298
+ end
299
+ zorg = (scale & GR::OPTION_FLIP_Z) == 0 ? [zmin, zmax] : [zmax, zmin]
247
300
  kvs[:zaxis] = ztick, zorg, majorz
248
301
  end
249
302
 
@@ -255,7 +308,7 @@ module GR
255
308
  end
256
309
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
257
310
  rotation = kvs[:rotation] || 40
258
- tilt = kvs[:tilt] || 70
311
+ tilt = kvs[:tilt] || 70
259
312
  GR.setspace(zmin, zmax, rotation, tilt)
260
313
  end
261
314
 
@@ -329,29 +382,29 @@ module GR
329
382
  GR.axes(xtick, ytick, xorg[1], yorg[1], -majorx, -majory, -ticksize)
330
383
  end
331
384
 
332
- if kvs[:title]
385
+ if kvs.has_key?(:title)
333
386
  GR.savestate
334
387
  GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
335
- text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title])
388
+ text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title].to_s)
336
389
  GR.restorestate
337
390
  end
338
391
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
339
- xlabel = kvs[:xlabel] || ''
340
- ylabel = kvs[:ylabel] || ''
341
- zlabel = kvs[:zlabel] || ''
392
+ xlabel = (kvs[:xlabel] || '').to_s
393
+ ylabel = (kvs[:ylabel] || '').to_s
394
+ zlabel = (kvs[:zlabel] || '').to_s
342
395
  GR.titles3d(xlabel, ylabel, zlabel)
343
396
  else
344
397
  if kvs.has_key?(:xlabel)
345
398
  GR.savestate
346
399
  GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_BOTTOM)
347
- text(0.5 * (viewport[0] + viewport[1]), vp[2] + 0.5 * charheight, kvs[:xlabel])
400
+ text(0.5 * (viewport[0] + viewport[1]), vp[2] + 0.5 * charheight, kvs[:xlabel].to_s)
348
401
  GR.restorestate
349
402
  end
350
403
  if kvs.has_key?(:ylabel)
351
404
  GR.savestate
352
405
  GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
353
406
  GR.setcharup(-1, 0)
354
- text(vp[0] + 0.5 * charheight, 0.5 * (viewport[2] + viewport[3]), kvs[:ylabel])
407
+ text(vp[0] + 0.5 * charheight, 0.5 * (viewport[2] + viewport[3]), kvs[:ylabel].to_s)
355
408
  GR.restorestate
356
409
  end
357
410
  end
@@ -459,7 +512,7 @@ module GR
459
512
  if kvs.has_key?(:title)
460
513
  GR.savestate
461
514
  GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
462
- text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title])
515
+ text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title].to_s)
463
516
  GR.restorestate
464
517
  end
465
518
  GR.selntran(1)
@@ -561,7 +614,22 @@ module GR
561
614
  # Not yet.
562
615
  end
563
616
 
564
- GR.settextfontprec(232, 3)
617
+ if kvs.has_key?(:font)
618
+ name = kvs[:font]
619
+ # 'Cmuserif-Math' => :cmuserif_math
620
+ sym_name = name.to_s.gsub('-','_').downcase.to_sym
621
+ if FONTS.include?(sym_name)
622
+ font = FONTS[sym_name]
623
+ GR.settextfontprec(font, font > 200 ? 3 : 0)
624
+ else
625
+ warn "Unknown font name: #{name}" # should raise error?
626
+ end
627
+ else
628
+ # The following fonts are the default in GR.jl
629
+ # Japanese, Chinese, Korean, etc. cannot be displayed.
630
+
631
+ # GR.settextfontprec(232, 3) # CM Serif Roman
632
+ end
565
633
 
566
634
  set_viewport(kind, kvs[:subplot])
567
635
  unless kvs[:ax]
@@ -629,8 +697,7 @@ module GR
629
697
  if z || c
630
698
  if c
631
699
  cmin, cmax = kvs[:crange]
632
- c = c.to_a if narray?(c)
633
- c.map! { |i| normalize_color(i, cmin, cmax) }
700
+ c = c.map { |i| normalize_color(i, cmin, cmax) }
634
701
  cind = c.map { |i| (1000 + i * 255).round }
635
702
  end
636
703
  x.length.times do |i|
@@ -655,14 +722,26 @@ module GR
655
722
  GR.polymarker(x, y)
656
723
 
657
724
  when :hist
658
- ymin = kvs[:window][2]
659
- y.length.times do |i|
660
- GR.setfillcolorind(989)
661
- GR.setfillintstyle(GR::INTSTYLE_SOLID)
662
- GR.fillrect(x[i], x[i + 1], ymin, y[i])
663
- GR.setfillcolorind(1)
664
- GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
665
- GR.fillrect(x[i], x[i + 1], ymin, y[i])
725
+ if kvs[:horizontal]
726
+ xmin = kvs[:window][0]
727
+ x.length.times do |i|
728
+ GR.setfillcolorind(989)
729
+ GR.setfillintstyle(GR::INTSTYLE_SOLID)
730
+ GR.fillrect(xmin, x[i], y[i], y[i + 1])
731
+ GR.setfillcolorind(1)
732
+ GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
733
+ GR.fillrect(xmin, x[i], y[i], y[i + 1])
734
+ end
735
+ else
736
+ ymin = kvs[:window][2]
737
+ y.length.times do |i|
738
+ GR.setfillcolorind(989)
739
+ GR.setfillintstyle(GR::INTSTYLE_SOLID)
740
+ GR.fillrect(x[i], x[i + 1], ymin, y[i])
741
+ GR.setfillcolorind(1)
742
+ GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
743
+ GR.fillrect(x[i], x[i + 1], ymin, y[i])
744
+ end
666
745
  end
667
746
 
668
747
  when :polarhist
@@ -719,9 +798,10 @@ module GR
719
798
  else
720
799
  h = levels
721
800
  end
722
- if kind == :contour
801
+ case kind
802
+ when :contour
723
803
  GR._contour_(x, y, h, z, clabels ? 1 : 1000)
724
- elsif kind == :contourf
804
+ when :contourf
725
805
  GR._contourf_(x, y, h, z, clabels ? 1 : 0)
726
806
  end
727
807
  colorbar(0, h.length)
@@ -810,7 +890,7 @@ module GR
810
890
  GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
811
891
  if c
812
892
  cmin, cmax = kvs[:crange]
813
- c = c.map { |i| normalize_color(i, cmin, cmax) } # NArray -> Array
893
+ c = c.map { |i| normalize_color(i, cmin, cmax) }
814
894
  cind = c.map { |i| (1000 + i * 255).round }
815
895
  x.length.times do |i|
816
896
  GR.setmarkercolorind(cind[i])
@@ -1016,13 +1096,16 @@ module GR
1016
1096
 
1017
1097
  # Normalize a color c with the range [cmin, cmax]
1018
1098
  # 0 <= normalize_color(c, cmin, cmax) <= 1
1099
+ # Note: narray.map{|i| normalize_color(i)} There's room for speedup.
1019
1100
  def normalize_color(c, cmin, cmax)
1101
+ c = c.to_f # if c is Integer
1020
1102
  c = c.clamp(cmin, cmax) - cmin
1021
1103
  c /= (cmax - cmin) if cmin != cmax
1022
1104
  c
1023
1105
  end
1024
1106
 
1025
1107
  def inqtext(x, y, s)
1108
+ s = s.to_s
1026
1109
  if s.length >= 2 && s[0] == '$' && s[-1] == '$'
1027
1110
  GR.inqmathtex(x, y, s[1..-2])
1028
1111
  elsif s.include?('\\') || s.include?('_') || s.include?('^')
@@ -1033,6 +1116,7 @@ module GR
1033
1116
  end
1034
1117
 
1035
1118
  def text(x, y, s)
1119
+ s = s.to_s
1036
1120
  if s.length >= 2 && s[0] == '$' && s[-1] == '$'
1037
1121
  GR.mathtex(x, y, s[1..-2])
1038
1122
  elsif s.include?('\\') || s.include?('_') || s.include?('^')
@@ -1057,7 +1141,8 @@ module GR
1057
1141
  args.each do |x, y, z, c|
1058
1142
  if x
1059
1143
  if scale & GR::OPTION_X_LOG != 0
1060
- x.map! { |v| v > 0 ? v : Float::NAN }
1144
+ # duck typing for NArray
1145
+ x = x.map { |v| v > 0 ? v : Float::NAN }
1061
1146
  end
1062
1147
  x0, x1 = x.minmax
1063
1148
  xmin = [x0, xmin].min
@@ -1068,7 +1153,7 @@ module GR
1068
1153
  end
1069
1154
  if y
1070
1155
  if scale & GR::OPTION_Y_LOG != 0
1071
- y.map! { |v| v > 0 ? v : Float::NAN }
1156
+ y = y.map { |v| v > 0 ? v : Float::NAN }
1072
1157
  end
1073
1158
  y0, y1 = y.minmax
1074
1159
  ymin = [y0, ymin].min
@@ -1079,7 +1164,7 @@ module GR
1079
1164
  end
1080
1165
  if z
1081
1166
  if scale & GR::OPTION_Z_LOG != 0
1082
- z.map! { |v| v > 0 ? v : Float::NAN }
1167
+ z = z.map { |v| v > 0 ? v : Float::NAN }
1083
1168
  end
1084
1169
  z0, z1 = z.minmax
1085
1170
  zmin = [z0, zmin].min
@@ -1131,20 +1216,12 @@ module GR
1131
1216
  [w, h]
1132
1217
  end
1133
1218
 
1134
- # NOTE: duplicated definition (GRCommonUtils)
1135
1219
  def equal_length(*args)
1136
- lengths = args.map(&:length)
1137
- unless lengths.all? { |l| l == lengths[0] }
1138
- raise ArgumentError,
1139
- 'Sequences must have same length.'
1140
- end
1141
-
1142
- lengths[0]
1220
+ GRCommons::GRCommonUtils.equal_length(*args)
1143
1221
  end
1144
1222
 
1145
- # NOTE: duplicated definition (GRCommonUtils)
1146
1223
  def narray?(data)
1147
- defined?(Numo::NArray) && data.is_a?(Numo::NArray)
1224
+ GRCommons::GRCommonUtils.narray?(data)
1148
1225
  end
1149
1226
  end
1150
1227
 
@@ -1293,11 +1370,15 @@ module GR
1293
1370
  end
1294
1371
 
1295
1372
  # (Plot) Draw a histogram.
1296
- def histogram(x, kv = {})
1297
- create_plot(:hist, x, kv) do |plt|
1373
+ def histogram(series, kv = {})
1374
+ create_plot(:hist, series, kv) do |plt|
1298
1375
  nbins = plt.kvs[:nbins] || 0
1299
- x, y = hist(x, nbins)
1300
- plt.args = [[x, y, nil, nil, '']]
1376
+ x, y = hist(series, nbins)
1377
+ plt.args = if kv[:horizontal]
1378
+ [[y, x, nil, nil, '']]
1379
+ else
1380
+ [[x, y, nil, nil, '']]
1381
+ end
1301
1382
  end
1302
1383
  end
1303
1384
 
@@ -1323,7 +1404,7 @@ module GR
1323
1404
  end
1324
1405
 
1325
1406
  # Set current subplot index.
1326
- def subplot(nr, nc, p)
1407
+ def subplot(nr, nc, p, kv = {})
1327
1408
  xmin = 1
1328
1409
  xmax = 0
1329
1410
  ymin = 1
@@ -1342,7 +1423,7 @@ module GR
1342
1423
  # The policy of clearing when p[0]==1 is controversial
1343
1424
  clear: p[0] == 1,
1344
1425
  update: p[-1] == nr * nc
1345
- }
1426
+ }.merge kv
1346
1427
  end
1347
1428
 
1348
1429
  # (Plot) Save the current figure to a file.