ruby-gr 0.0.13 → 0.0.18

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.
@@ -3,7 +3,9 @@
3
3
  require 'fiddle/import'
4
4
 
5
5
  module GR
6
- # FFI Wrapper module for GR
6
+ # FFI Wrapper module for GR.
7
+ # The functions for GR are listed here.
8
+ # Add functions here when a new version of GR is released.
7
9
  module FFI
8
10
  extend Fiddle::Importer
9
11
 
@@ -16,8 +18,7 @@ module GR
16
18
  extend GRCommons::Extern
17
19
 
18
20
  # https://github.com/sciapp/gr/blob/master/lib/gr/gr.h
19
- # Order is important.
20
-
21
+ # keep same order
21
22
  try_extern 'void gr_initgr(void)'
22
23
  try_extern 'void gr_opengks(void)'
23
24
  try_extern 'void gr_closegks(void)'
@@ -60,7 +61,9 @@ module GR
60
61
  try_extern 'void gr_setcharexpan(double)'
61
62
  try_extern 'void gr_setcharspace(double)'
62
63
  try_extern 'void gr_settextcolorind(int)'
64
+ try_extern 'void gr_inqtextcolorind(int *)'
63
65
  try_extern 'void gr_setcharheight(double)'
66
+ try_extern 'void gr_inqcharheight(double *)'
64
67
  try_extern 'void gr_setcharup(double, double)'
65
68
  try_extern 'void gr_settextpath(int)'
66
69
  try_extern 'void gr_settextalign(int, int)'
@@ -159,7 +162,7 @@ module GR
159
162
  try_extern 'void gr_selectcontext(int)'
160
163
  try_extern 'void gr_destroycontext(int)'
161
164
  try_extern 'int gr_uselinespec(char *)'
162
- # try_extern 'void gr_delaunay(int, const double *, const double *, int *, int **)'
165
+ try_extern 'void gr_delaunay(int, const double *, const double *, int *, int **)'
163
166
  try_extern 'void gr_reducepoints(int, const double *, const double *, int, double *, double *)'
164
167
  try_extern 'void gr_trisurface(int, double *, double *, double *)'
165
168
  try_extern 'void gr_gradient(int, int, double *, double *, double *, double *, double *)'
@@ -192,5 +195,12 @@ module GR
192
195
  try_extern 'void gr_camerainteraction(double, double, double, double)'
193
196
  try_extern 'void gr_setwindow3d(double, double, double, double, double, double)'
194
197
  try_extern 'void gr_inqwindow3d(double *, double *, double *, double *, double *, double *)'
198
+ try_extern 'void gr_setscalefactors3d(double, double, double)'
199
+ try_extern 'void gr_inqscalefactors3d(double *, double *, double *)'
200
+ try_extern 'void gr_setspace3d(double, double, double, double)'
201
+ try_extern 'void gr_text3d(double, double, double, char *, int axis)'
202
+ try_extern 'void gr_inqtext3d(double, double, double, char *, int axis, double *, double *)'
203
+ try_extern 'void gr_settextencoding(int)'
204
+ try_extern 'void gr_inqtextencoding(int *)'
195
205
  end
196
206
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GR
4
- # This module automatically converts Ruby arrays and Numo::Narray into pointers.
4
+ # This module automatically converts Ruby arrays and Numo::Narray into
5
+ # Fiddley::MemoryPointer.
5
6
  module GRBase
6
7
  extend GRCommons::DefineMethods
7
8
  define_ffi_methods(FFI,
@@ -9,6 +10,4 @@ module GR
9
10
  default_type: :double)
10
11
  end
11
12
  private_constant :GRBase
12
-
13
- extend GRCommons::GRCommonUtils
14
13
  end
@@ -8,7 +8,9 @@ autoload :GR3, 'gr3'
8
8
  require 'numo/narray'
9
9
 
10
10
  module GR
11
- class Plot # should be Figure ?
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
12
14
  # Why is the Plot class NOT object-oriented?
13
15
  #
14
16
  # Because the code here is mainly ported from GR.jl.
@@ -36,14 +38,14 @@ module GR
36
38
 
37
39
  # Keyword options conform to GR.jl.
38
40
  KW_ARGS = %i[accelerate algorithm alpha backgroundcolor barwidth baseline
39
- clabels color colormap figsize isovalue label labels levels
40
- location nbins rotation size tilt title where xflip xform xlabel
41
- xlim xlog yflip ylabel ylim ylog zflip zlabel zlim zlog clim
42
- subplot].freeze
43
-
44
- @@last_plot = nil
45
- def self.last_plot
46
- @@last_plot
41
+ clabels color colormap figsize horizontal isovalue label labels
42
+ levels location nbins rotation size tilt title where xflip
43
+ xform xlabel xlim xlog yflip ylabel ylim ylog zflip zlabel zlim
44
+ zlog clim subplot].freeze
45
+
46
+ @last_plot = nil
47
+ class << self
48
+ attr_accessor :last_plot
47
49
  end
48
50
 
49
51
  def initialize(*args)
@@ -62,14 +64,14 @@ module GR
62
64
 
63
65
  @args = plot_args(args) # method name is the same as Julia/Python
64
66
  @kvs[:size] ||= [600, 450]
65
- @kvs[:ax] ||= false
67
+ @kvs[:ax] = false if @kvs[:ax].nil?
66
68
  @kvs[:subplot] ||= [0, 1, 0, 1]
67
- @kvs[:clear] ||= true
68
- @kvs[:update] ||= true
69
+ @kvs[:clear] = true if @kvs[:clear].nil?
70
+ @kvs[:update] = true if @kvs[:update].nil?
69
71
  @scheme = 0
70
72
  @background = 0xffffff
71
73
  @handle = nil
72
- @@last_plot = self
74
+ self.class.last_plot = self
73
75
  end
74
76
  attr_accessor :args, :kvs, :scheme
75
77
 
@@ -170,6 +172,7 @@ module GR
170
172
  scale |= GR::OPTION_FLIP_Y if kvs[:yflip]
171
173
  scale |= GR::OPTION_FLIP_Z if kvs[:zflip]
172
174
  end
175
+ kvs[:scale] = scale
173
176
  if kvs.has_key?(:panzoom)
174
177
  xmin, xmax, ymin, ymax = GR.panzoom(*kvs[:panzoom])
175
178
  kvs[:xrange] = [xmin, xmax]
@@ -329,7 +332,7 @@ module GR
329
332
  GR.axes(xtick, ytick, xorg[1], yorg[1], -majorx, -majory, -ticksize)
330
333
  end
331
334
 
332
- if kvs.has_key?(:title)
335
+ if kvs[:title]
333
336
  GR.savestate
334
337
  GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
335
338
  text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title])
@@ -397,11 +400,9 @@ module GR
397
400
  end
398
401
 
399
402
  def plot_polar(θ, ρ)
400
- ρ = Numo::DFloat.cast(ρ) if ρ.is_a? Array
401
403
  window = kvs[:window]
402
- rmin = window[2]
403
- rmax = window[3]
404
- ρ = (ρ - rmin) / (rmax - rmin)
404
+ rmax = window[3].to_f
405
+ ρ = ρ.map { |i| i / rmax }
405
406
  n = ρ.length
406
407
  x = []
407
408
  y = []
@@ -420,7 +421,7 @@ module GR
420
421
  if img.is_a? String
421
422
  width, height, data = GR.readimage(img)
422
423
  else
423
- width, height = img.shape
424
+ height, width = img.shape
424
425
  cmin, cmax = kvs[:crange]
425
426
  data = img.map { |i| normalize_color(i, cmin, cmax) }
426
427
  data = data.map { |i| (1000 + i * 255).round }
@@ -487,7 +488,9 @@ module GR
487
488
  end
488
489
 
489
490
  GR.selntran(0)
490
- values = ((v - v.min) / (v.max - v.min) * (2 ^ 16 - 1)).round
491
+ v = Numo::DFloat.cast(v) if v.is_a? Array
492
+ values = ((v - v.min) / (v.max - v.min) * (2**16 - 1)).round
493
+ values = Numo::UInt16.cast(values)
491
494
  nx, ny, nz = v.shape
492
495
  isovalue = ((kvs[:isovalue] || 0.5) - v.min) / (v.max - v.min)
493
496
  rotation = ((kvs[:rotation] || 40) * Math::PI / 180.0)
@@ -496,7 +499,7 @@ module GR
496
499
  GR3.clear
497
500
  mesh = GR3.createisosurfacemesh(values, [2.0 / (nx - 1), 2.0 / (ny - 1), 2.0 / (nz - 1)],
498
501
  [-1, -1, -1],
499
- (isovalue * (2 ^ 16 - 1)).round)
502
+ (isovalue * (2**16 - 1)).round)
500
503
  color = kvs[:color] || [0.0, 0.5, 0.8]
501
504
  GR3.setbackgroundcolor(1, 1, 1, 0)
502
505
  GR3.drawmesh(mesh, 1, [0, 0, 0], [0, 0, 1], [0, 1, 0], color, [1, 1, 1])
@@ -561,6 +564,8 @@ module GR
561
564
  # Not yet.
562
565
  end
563
566
 
567
+ GR.settextfontprec(232, 3)
568
+
564
569
  set_viewport(kind, kvs[:subplot])
565
570
  unless kvs[:ax]
566
571
  set_window(kind)
@@ -579,8 +584,7 @@ module GR
579
584
 
580
585
  GR.uselinespec(' ')
581
586
  args.each do |x, y, z, c, spec|
582
- # FIXME
583
- spec ||= ''
587
+ spec ||= kvs[:spec] ||= ''
584
588
  GR.savestate
585
589
  GR.settransparency(kvs[:alpha]) if kvs.has_key?(:alpha)
586
590
 
@@ -664,21 +668,18 @@ module GR
664
668
  GR.fillrect(x[i], x[i + 1], ymin, y[i])
665
669
  end
666
670
 
667
- # when :polarhist
668
- # xmin, xmax = x.minmax
669
- # ymax = kvs[:window][3]
670
- # ρ = y.map { |i| 2 * (i.to_f / ymax - 0.5) }
671
- # θ = x.map { |i| 2 * Math::PI * (i.to_f - xmin) / (xmax - xmin) }
672
- # ρ.length.times do |i|
673
- # GR.setfillcolorind(989)
674
- # GR.setfillintstyle(GR::INTSTYLE_SOLID)
675
- # GR.fillarea([0, ρ[i] * Math.cos(θ[i]), ρ[i] * Math.cos(θ[i + 1])],
676
- # [0, ρ[i] * Math.sin(θ[i]), ρ[i] * Math.sin(θ[i + 1])])
677
- # GR.setfillcolorind(1)
678
- # GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
679
- # GR.fillarea([0, ρ[i] * Math.cos(θ[i]), ρ[i] * Math.cos(θ[i + 1])],
680
- # [0, ρ[i] * Math.sin(θ[i]), ρ[i] * Math.sin(θ[i + 1])])
681
- # end
671
+ when :polarhist
672
+ ymax = kvs[:window][3].to_f
673
+ ρ = y.map { |i| i / ymax }
674
+ θ = x.map { |i| i * 180 / Math::PI }
675
+ (1...ρ.length).each do |i|
676
+ GR.setfillcolorind(989)
677
+ GR.setfillintstyle(GR::INTSTYLE_SOLID)
678
+ GR.fillarc(-ρ[i], ρ[i], -ρ[i], ρ[i], θ[i - 1], θ[i])
679
+ GR.setfillcolorind(1)
680
+ GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
681
+ GR.fillarc(-ρ[i], ρ[i], -ρ[i], ρ[i], θ[i - 1], θ[i])
682
+ end
682
683
 
683
684
  when :polarheatmap
684
685
  w, h = z.shape
@@ -699,11 +700,18 @@ module GR
699
700
  a, b = z.shape
700
701
  x = (1..b).to_a
701
702
  y = (1..a).to_a
702
- zmin, zmax = kvs[:zlim] || z.minmax
703
+ zmin, zmax = z.minmax
703
704
  elsif equal_length(x, y, z)
704
705
  x, y, z = GR.gridit(x, y, z, 200, 200)
705
- zmin, zmax = kvs[:zlim] || z.compact.minmax # compact : removed nil
706
+ zmin, zmax = z.compact.minmax # compact : removed nil
707
+ end
708
+
709
+ # kvs[:zlim] is supposed to be Array or Range
710
+ if kvs.has_key?(:zlim)
711
+ zmin = kvs[:zlim].first if kvs[:zlim].first
712
+ zmax = kvs[:zlim].last if kvs[:zlim].last
706
713
  end
714
+
707
715
  GR.setspace(zmin, zmax, 0, 90)
708
716
  levels = kvs[:levels] || 0
709
717
  clabels = kvs[:clabels] || false
@@ -795,7 +803,9 @@ module GR
795
803
  colorbar(0.05)
796
804
 
797
805
  when :plot3
798
- GR.polyline3d(x, y, z)
806
+ mask = GR.uselinespec(spec)
807
+ GR.polyline3d(x, y, z) if hasline(mask)
808
+ GR.polymarker3d(x, y, z) if hasmarker(mask)
799
809
  draw_axes(kind, 2)
800
810
 
801
811
  when :scatter3
@@ -824,7 +834,7 @@ module GR
824
834
  plot_polar(x, y)
825
835
 
826
836
  when :trisurf
827
- GR._trisurface_(x, y, z)
837
+ GR.trisurface(x, y, z)
828
838
  draw_axes(kind, 2)
829
839
  colorbar(0.05)
830
840
 
@@ -858,7 +868,7 @@ module GR
858
868
 
859
869
  draw_legend if %i[line step scatter stem].include?(kind) && kvs.has_key?(:labels)
860
870
 
861
- if kvs.has_key?(:update)
871
+ if kvs[:update]
862
872
  GR.updatews
863
873
  # if GR.isinline()
864
874
  # restore_context()
@@ -978,24 +988,31 @@ module GR
978
988
  [*0..(num - 1)].collect { |i| low + i.to_f * (high - low) / (num - 1) }
979
989
  end
980
990
 
981
- def plot_args(args, _fmt = :xys)
991
+ def plot_args(args)
982
992
  # FIXME
983
993
  args = [args] unless args.all? do |i|
984
994
  i.is_a?(Array) && (i[0].is_a?(Array) || narray?(i[0]))
985
995
  end
986
996
  args.map do |xyzc|
997
+ spec = nil
998
+ case xyzc.last
999
+ when String
1000
+ spec = xyzc.pop
1001
+ when Hash
1002
+ spec = xyzc.pop[:spec]
1003
+ end
1004
+
987
1005
  x, y, z, c = xyzc.map do |i|
988
- if i.is_a?(Array) || narray?(i)
1006
+ if i.is_a?(Array) || narray?(i) || i.nil?
989
1007
  i
990
1008
  elsif i.respond_to?(:to_a)
991
1009
  # Convert an Array-like class such as Daru::Vector to an Array
992
1010
  i.to_a
993
- else
994
- # String
1011
+ else # String
995
1012
  i
996
1013
  end
997
1014
  end
998
- [x, y, z, c]
1015
+ [x, y, z, c, spec]
999
1016
  end
1000
1017
  end
1001
1018
 
@@ -1038,9 +1055,12 @@ module GR
1038
1055
  def minmax
1039
1056
  xmin = ymin = zmin = cmin = Float::INFINITY
1040
1057
  xmax = ymax = zmax = cmax = -Float::INFINITY
1041
-
1058
+ scale = kvs[:scale]
1042
1059
  args.each do |x, y, z, c|
1043
1060
  if x
1061
+ if scale & GR::OPTION_X_LOG != 0
1062
+ x.map! { |v| v > 0 ? v : Float::NAN }
1063
+ end
1044
1064
  x0, x1 = x.minmax
1045
1065
  xmin = [x0, xmin].min
1046
1066
  xmax = [x1, xmax].max
@@ -1049,6 +1069,9 @@ module GR
1049
1069
  xmax = 1
1050
1070
  end
1051
1071
  if y
1072
+ if scale & GR::OPTION_Y_LOG != 0
1073
+ y.map! { |v| v > 0 ? v : Float::NAN }
1074
+ end
1052
1075
  y0, y1 = y.minmax
1053
1076
  ymin = [y0, ymin].min
1054
1077
  ymax = [y1, ymax].max
@@ -1057,6 +1080,9 @@ module GR
1057
1080
  ymax = 1
1058
1081
  end
1059
1082
  if z
1083
+ if scale & GR::OPTION_Z_LOG != 0
1084
+ z.map! { |v| v > 0 ? v : Float::NAN }
1085
+ end
1060
1086
  z0, z1 = z.minmax
1061
1087
  zmin = [z0, zmin].min
1062
1088
  zmax = [z1, zmax].max
@@ -1074,30 +1100,12 @@ module GR
1074
1100
  xmin, xmax = fix_minmax(xmin, xmax)
1075
1101
  ymin, ymax = fix_minmax(ymin, ymax)
1076
1102
  zmin, zmax = fix_minmax(zmin, zmax)
1077
- if kvs.has_key?(:xlim)
1078
- x0, x1 = kvs[:xlim]
1079
- x0 ||= xmin
1080
- x1 ||= xmax
1081
- kvs[:xrange] = [x0, x1]
1082
- else
1083
- kvs[:xrange] = [xmin, xmax]
1084
- end
1085
- if kvs.has_key?(:ylim)
1086
- y0, y1 = kvs[:ylim]
1087
- y0 ||= ymin
1088
- y1 ||= ymax
1089
- kvs[:yrange] = [y0, y1]
1090
- else
1091
- kvs[:yrange] = [ymin, ymax]
1092
- end
1093
- if kvs.has_key?(:zlim)
1094
- z0, z1 = kvs[:zlim]
1095
- z0 ||= zmin
1096
- z1 ||= zmax
1097
- kvs[:zrange] = [z0, z1]
1098
- else
1099
- kvs[:zrange] = [zmin, zmax]
1100
- end
1103
+
1104
+ # kvs[:xlim], kvs[:ylim], kvs[:zlim] is supposed to be Array or Range
1105
+ kvs[:xrange] = [(kvs[:xlim]&.first || xmin), (kvs[:xlim]&.last || xmax)]
1106
+ kvs[:yrange] = [(kvs[:ylim]&.first || ymin), (kvs[:ylim]&.last || ymax)]
1107
+ kvs[:zrange] = [(kvs[:zlim]&.first || zmin), (kvs[:zlim]&.last || zmax)]
1108
+
1101
1109
  if kvs.has_key?(:clim)
1102
1110
  c0, c1 = kvs[:clim]
1103
1111
  c0 ||= cmin
@@ -1117,7 +1125,7 @@ module GR
1117
1125
  kvs[:labels].each do |label|
1118
1126
  label = label.to_s
1119
1127
  tbx, tby = inqtext(0, 0, label)
1120
- w = [w, tbx[2]].max
1128
+ w = [w, tbx[2] - tbx[0]].max
1121
1129
  h += [tby[2] - tby[0], 0.03].max
1122
1130
  end
1123
1131
  GR.setscale(scale)
@@ -1143,39 +1151,41 @@ module GR
1143
1151
  end
1144
1152
 
1145
1153
  class << self
1146
- # Draw one or more line plots.
1154
+ # (Plot) Draw one or more line plots.
1147
1155
  def plot(*args)
1148
1156
  create_plot(:line, *args)
1149
1157
  end
1150
1158
 
1151
- # Draw one or more step or staircase plots.
1159
+ # (Plot) Draw one or more step or staircase plots.
1152
1160
  def step(*args)
1153
1161
  create_plot(:step, *args)
1154
1162
  end
1155
1163
 
1156
- # Draw one or more scatter plots.
1164
+ # (Plot) Draw one or more scatter plots.
1157
1165
  def scatter(*args)
1158
1166
  create_plot(:scatter, *args)
1159
1167
  end
1160
1168
 
1161
- # Draw a stem plot.
1169
+ # (Plot) Draw a stem plot.
1162
1170
  def stem(*args)
1163
1171
  create_plot(:stem, *args)
1164
1172
  end
1165
1173
 
1166
- # def polarhistogram(x, kv = {})
1167
- # plt = GR::Plot.new(x, kv)
1168
- # plt.kvs[:kind] = :polarhist
1169
- # nbins = plt.kvs[:nbins] || 0
1170
- # x, y = hist(x, nbins)
1171
- # plt.args = [[x, y, nil, nil, '']]
1172
- # plt.plot_data
1173
- # end
1174
+ # (Plot)
1175
+ def polarhistogram(x, kv = {})
1176
+ plt = GR::Plot.new(x, kv)
1177
+ plt.kvs[:kind] = :polarhist
1178
+ nbins = plt.kvs[:nbins] || 0
1179
+ x, y = hist(x, nbins)
1180
+ plt.args = [[x, y, nil, nil, '']]
1181
+ plt.plot_data
1182
+ end
1174
1183
 
1175
- # Draw a heatmap.
1184
+ # (Plot) Draw a heatmap.
1176
1185
  def heatmap(*args)
1177
1186
  # FIXME
1178
- _x, _y, z, kv = parse_args(*args)
1187
+ args, kv = format_xyzc(*args)
1188
+ _x, _y, z = args
1179
1189
  ysize, xsize = z.shape
1180
1190
  z = z.reshape(xsize, ysize)
1181
1191
  create_plot(:heatmap, kv) do |plt|
@@ -1185,6 +1195,7 @@ module GR
1185
1195
  end
1186
1196
  end
1187
1197
 
1198
+ # (Plot) Draw a polarheatmap.
1188
1199
  def polarheatmap(*args)
1189
1200
  d = args.shift
1190
1201
  # FIXME
@@ -1200,77 +1211,73 @@ module GR
1200
1211
  end
1201
1212
 
1202
1213
  alias _contour_ contour
1203
- # Draw a contour plot.
1214
+ # (Plot) Draw a contour plot.
1204
1215
  def contour(*args)
1205
- x, y, z, kv = parse_args(*args)
1206
- create_plot(:contour, x, y, z, kv)
1216
+ create_plot(:contour, *format_xyzc(*args))
1207
1217
  end
1208
1218
 
1209
1219
  alias _contourf_ contourf
1210
- # Draw a filled contour plot.
1220
+ # (Plot) Draw a filled contour plot.
1211
1221
  def contourf(*args)
1212
- x, y, z, kv = parse_args(*args)
1213
- create_plot(:contourf, x, y, z, kv)
1222
+ create_plot(:contourf, *format_xyzc(*args))
1214
1223
  end
1215
1224
 
1216
1225
  alias _hexbin_ hexbin
1217
- # Draw a hexagon binning plot.
1226
+ # (Plot) Draw a hexagon binning plot.
1218
1227
  def hexbin(*args)
1219
1228
  create_plot(:hexbin, *args)
1220
1229
  end
1221
1230
 
1222
- # Draw a triangular contour plot.
1231
+ # (Plot) Draw a triangular contour plot.
1223
1232
  def tricont(*args)
1224
- x, y, z, kv = parse_args(*args)
1225
- create_plot(:tricont, x, y, z, kv)
1233
+ create_plot(:tricont, *format_xyzc(*args))
1226
1234
  end
1227
1235
 
1228
- # Draw a three-dimensional wireframe plot.
1236
+ # (Plot) Draw a three-dimensional wireframe plot.
1229
1237
  def wireframe(*args)
1230
- x, y, z, kv = parse_args(*args)
1231
- create_plot(:wireframe, x, y, z, kv)
1238
+ create_plot(:wireframe, *format_xyzc(*args))
1232
1239
  end
1233
1240
 
1234
- # Draw a three-dimensional surface plot.
1241
+ # (Plot) Draw a three-dimensional surface plot.
1235
1242
  alias _surface_ surface
1236
1243
  def surface(*args)
1237
- x, y, z, kv = parse_args(*args)
1238
- create_plot(:surface, x, y, z, kv)
1244
+ create_plot(:surface, *format_xyzc(*args))
1239
1245
  end
1240
1246
 
1247
+ # (Plot)
1241
1248
  def polar(*args)
1242
1249
  create_plot(:polar, *args)
1243
1250
  end
1244
1251
 
1245
- alias _trisurface_ trisurface
1246
- # Draw a triangular surface plot.
1247
- def trisurface(*args)
1248
- x, y, z, kv = parse_args(*args)
1249
- create_plot(:trisurf, x, y, z, kv)
1252
+ # (Plot) Draw a triangular surface plot.
1253
+ def trisurf(*args)
1254
+ create_plot(:trisurf, *format_xyzc(*args))
1250
1255
  end
1251
1256
 
1252
- # Draw one or more three-dimensional line plots.
1257
+ # (Plot) Draw one or more three-dimensional line plots.
1253
1258
  def plot3(*args)
1254
1259
  create_plot(:plot3, *args)
1255
1260
  end
1256
1261
 
1257
- # Draw one or more three-dimensional scatter plots.
1262
+ # (Plot) Draw one or more three-dimensional scatter plots.
1258
1263
  def scatter3(*args)
1259
1264
  create_plot(:scatter3, *args)
1260
1265
  end
1261
1266
 
1262
1267
  alias _shade_ shade
1268
+ # (Plot)
1263
1269
  def shade(*args)
1264
1270
  create_plot(:shade, *args)
1265
1271
  end
1266
1272
 
1273
+ # (Plot)
1267
1274
  def volume(v, kv = {})
1268
1275
  create_plot(:volume, v, kv) do |plt|
1269
1276
  plt.args = [[nil, nil, v, nil, '']]
1270
1277
  end
1271
1278
  end
1272
1279
 
1273
- # Draw a bar plot.
1280
+ # (Plot) Draw a bar plot.
1274
1281
  def barplot(labels, heights, kv = {})
1275
1282
  labels = labels.map(&:to_s)
1276
1283
  wc, hc = barcoordinates(heights)
@@ -1288,7 +1295,7 @@ module GR
1288
1295
  end
1289
1296
  end
1290
1297
 
1291
- # Draw a histogram.
1298
+ # (Plot) Draw a histogram.
1292
1299
  def histogram(x, kv = {})
1293
1300
  create_plot(:hist, x, kv) do |plt|
1294
1301
  nbins = plt.kvs[:nbins] || 0
@@ -1297,7 +1304,7 @@ module GR
1297
1304
  end
1298
1305
  end
1299
1306
 
1300
- # Draw an image.
1307
+ # (Plot) Draw an image.
1301
1308
  def imshow(img, kv = {})
1302
1309
  img = Numo::DFloat.cast(img) # Umm...
1303
1310
  create_plot(:imshow, img, kv) do |plt|
@@ -1305,7 +1312,7 @@ module GR
1305
1312
  end
1306
1313
  end
1307
1314
 
1308
- # Draw an isosurface.
1315
+ # (Plot) Draw an isosurface.
1309
1316
  def isosurface(v, kv = {})
1310
1317
  v = Numo::DFloat.cast(v) # Umm...
1311
1318
  create_plot(:isosurface, v, kv) do |plt|
@@ -1313,6 +1320,34 @@ module GR
1313
1320
  end
1314
1321
  end
1315
1322
 
1323
+ def hold(flag = true)
1324
+ plt = GR::Plot.last_plot
1325
+ plt.kvs.slice(:window, :scale, :xaxis, :yaxis, :zaxis).merge({ ax: flag, clear: !flag })
1326
+ end
1327
+
1328
+ # Set current subplot index.
1329
+ def subplot(nr, nc, p)
1330
+ xmin = 1
1331
+ xmax = 0
1332
+ ymin = 1
1333
+ ymax = 0
1334
+ p = [p] if p.is_a? Integer
1335
+ p.each do |i|
1336
+ r = (nr - (i - 1) / nc).to_f
1337
+ c = ((i - 1) % nc + 1).to_f
1338
+ xmin = [xmin, (c - 1) / nc].min
1339
+ xmax = [xmax, c / nc].max
1340
+ ymin = [ymin, (r - 1) / nr].min
1341
+ ymax = [ymax, r / nr].max
1342
+ end
1343
+ {
1344
+ subplot: [xmin, xmax, ymin, ymax],
1345
+ clear: p[0] == 1,
1346
+ update: p[-1] == nr * nc
1347
+ }
1348
+ end
1349
+
1350
+ # (Plot) Save the current figure to a file.
1316
1351
  def savefig(filename, kv = {})
1317
1352
  GR.beginprint(filename)
1318
1353
  plt = GR::Plot.last_plot
@@ -1323,40 +1358,41 @@ module GR
1323
1358
 
1324
1359
  private
1325
1360
 
1326
- def create_plot(type, *args, &block)
1361
+ def create_plot(type, *args)
1327
1362
  plt = GR::Plot.new(*args)
1328
1363
  plt.kvs[:kind] = type
1329
- block.call(plt) if block_given?
1364
+ yield(plt) if block_given?
1330
1365
  plt.plot_data
1331
1366
  plt
1332
1367
  end
1333
1368
 
1334
- def parse_args(*args)
1369
+ def format_xyzc(*args)
1335
1370
  kv = if args[-1].is_a? Hash
1336
1371
  args.pop
1337
1372
  else
1338
1373
  {}
1339
1374
  end
1340
- if args.size == 1
1341
- if args[0].is_a? Array
1342
- z = Numo::DFloat.cast(args[0])
1343
- elsif narray?(args[0])
1344
- z = args[0]
1375
+
1376
+ args = [args] unless args.all? do |i|
1377
+ i.is_a?(Array) && (i[0].is_a?(Array) || narray?(i[0]))
1378
+ end
1379
+ args.map! do |xyzc|
1380
+ if xyzc.size == 1
1381
+ if xyzc[0].is_a? Array
1382
+ z = Numo::DFloat.cast(xyzc[0])
1383
+ elsif narray?(xyzc[0])
1384
+ z = xyzc[0]
1385
+ end
1386
+ xsize, ysize = z.shape
1387
+ x = (1..ysize).to_a * xsize
1388
+ y = (1..xsize).map { |i| Array.new(ysize, i) }.flatten
1389
+ [x, y, z]
1390
+ else
1391
+
1392
+ xyzc
1345
1393
  end
1346
- xsize, ysize = z.shape
1347
- # NOTE:
1348
- # See
1349
- # https://github.com/jheinen/GR.jl/pull/246
1350
- # https://github.com/jheinen/GR.jl/issues/241
1351
- x = (1..ysize).to_a * xsize
1352
- y = (1..xsize).map { |i| Array.new(ysize, i) }.flatten
1353
-
1354
- elsif args.size == 3
1355
- x, y, z = args
1356
- else
1357
- raise
1358
1394
  end
1359
- [x, y, z, kv]
1395
+ [*args, kv]
1360
1396
  end
1361
1397
 
1362
1398
  def hist(x, nbins = 0)