ruby-gr 0.0.14 → 0.0.19

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.
@@ -61,7 +61,9 @@ module GR
61
61
  try_extern 'void gr_setcharexpan(double)'
62
62
  try_extern 'void gr_setcharspace(double)'
63
63
  try_extern 'void gr_settextcolorind(int)'
64
+ try_extern 'void gr_inqtextcolorind(int *)'
64
65
  try_extern 'void gr_setcharheight(double)'
66
+ try_extern 'void gr_inqcharheight(double *)'
65
67
  try_extern 'void gr_setcharup(double, double)'
66
68
  try_extern 'void gr_settextpath(int)'
67
69
  try_extern 'void gr_settextalign(int, int)'
@@ -160,7 +162,7 @@ module GR
160
162
  try_extern 'void gr_selectcontext(int)'
161
163
  try_extern 'void gr_destroycontext(int)'
162
164
  try_extern 'int gr_uselinespec(char *)'
163
- # 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 **)'
164
166
  try_extern 'void gr_reducepoints(int, const double *, const double *, int, double *, double *)'
165
167
  try_extern 'void gr_trisurface(int, double *, double *, double *)'
166
168
  try_extern 'void gr_gradient(int, int, double *, double *, double *, double *, double *)'
@@ -193,5 +195,12 @@ module GR
193
195
  try_extern 'void gr_camerainteraction(double, double, double, double)'
194
196
  try_extern 'void gr_setwindow3d(double, double, double, double, double, double)'
195
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 *)'
196
205
  end
197
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
@@ -37,15 +37,16 @@ module GR
37
37
  volume].freeze # the name might be changed in the future.
38
38
 
39
39
  # Keyword options conform to GR.jl.
40
- KW_ARGS = %i[accelerate algorithm alpha backgroundcolor barwidth baseline
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
- def self.last_plot
48
- @@last_plot
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
46
+
47
+ @last_plot = nil
48
+ class << self
49
+ attr_accessor :last_plot
49
50
  end
50
51
 
51
52
  def initialize(*args)
@@ -64,14 +65,14 @@ module GR
64
65
 
65
66
  @args = plot_args(args) # method name is the same as Julia/Python
66
67
  @kvs[:size] ||= [600, 450]
67
- @kvs[:ax] ||= false
68
+ @kvs[:ax] = false if @kvs[:ax].nil?
68
69
  @kvs[:subplot] ||= [0, 1, 0, 1]
69
- @kvs[:clear] ||= true
70
- @kvs[:update] ||= true
70
+ @kvs[:clear] = true if @kvs[:clear].nil?
71
+ @kvs[:update] = true if @kvs[:update].nil?
71
72
  @scheme = 0
72
73
  @background = 0xffffff
73
74
  @handle = nil
74
- @@last_plot = self
75
+ self.class.last_plot = self
75
76
  end
76
77
  attr_accessor :args, :kvs, :scheme
77
78
 
@@ -172,6 +173,7 @@ module GR
172
173
  scale |= GR::OPTION_FLIP_Y if kvs[:yflip]
173
174
  scale |= GR::OPTION_FLIP_Z if kvs[:zflip]
174
175
  end
176
+ kvs[:scale] = scale
175
177
  if kvs.has_key?(:panzoom)
176
178
  xmin, xmax, ymin, ymax = GR.panzoom(*kvs[:panzoom])
177
179
  kvs[:xrange] = [xmin, xmax]
@@ -180,12 +182,8 @@ module GR
180
182
  minmax
181
183
  end
182
184
 
183
- major_count = if %i[wireframe surface plot3 scatter3 polar polarhist
184
- polarheatmap trisurf volume].include?(kind)
185
- 2
186
- else
187
- 5
188
- end
185
+ major_count = %i[wireframe surface plot3 scatter3 polar polarhist
186
+ polarheatmap trisurf volume].include?(kind) ? 2 : 5
189
187
 
190
188
  xmin, xmax = kvs[:xrange]
191
189
  if (scale & GR::OPTION_X_LOG) == 0
@@ -271,7 +269,7 @@ module GR
271
269
  ratio = kvs[:ratio]
272
270
  xtick, xorg, majorx = kvs[:xaxis]
273
271
  ytick, yorg, majory = kvs[:yaxis]
274
- drawgrid = kvs[:grid] || true
272
+ drawgrid = kvs.has_key?(:grid) ? kvs[:grid] : true
275
273
  xtick = 10 if kvs[:scale] & GR::OPTION_X_LOG != 0
276
274
  ytick = 10 if kvs[:scale] & GR::OPTION_Y_LOG != 0
277
275
  GR.setlinecolorind(1)
@@ -292,8 +290,8 @@ module GR
292
290
  else
293
291
  if %i[heatmap nonuniformheatmap shade].include?(kind)
294
292
  ticksize = -ticksize
295
- else
296
- drawgrid && GR.grid(xtick, ytick, 0, 0, majorx, majory)
293
+ elsif drawgrid
294
+ GR.grid(xtick, ytick, 0, 0, majorx, majory)
297
295
  end
298
296
  if kvs.has_key?(:xticklabels) || kvs.has_key?(:yticklabels)
299
297
  fx = if kvs.has_key?(:xticklabels)
@@ -331,7 +329,7 @@ module GR
331
329
  GR.axes(xtick, ytick, xorg[1], yorg[1], -majorx, -majory, -ticksize)
332
330
  end
333
331
 
334
- if kvs.has_key?(:title)
332
+ if kvs[:title]
335
333
  GR.savestate
336
334
  GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
337
335
  text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title])
@@ -420,7 +418,7 @@ module GR
420
418
  if img.is_a? String
421
419
  width, height, data = GR.readimage(img)
422
420
  else
423
- width, height = img.shape
421
+ height, width = img.shape
424
422
  cmin, cmax = kvs[:crange]
425
423
  data = img.map { |i| normalize_color(i, cmin, cmax) }
426
424
  data = data.map { |i| (1000 + i * 255).round }
@@ -487,7 +485,9 @@ module GR
487
485
  end
488
486
 
489
487
  GR.selntran(0)
490
- values = ((v - v.min) / (v.max - v.min) * (2 ^ 16 - 1)).round
488
+ v = Numo::DFloat.cast(v) if v.is_a? Array
489
+ values = ((v - v.min) / (v.max - v.min) * (2**16 - 1)).round
490
+ values = Numo::UInt16.cast(values)
491
491
  nx, ny, nz = v.shape
492
492
  isovalue = ((kvs[:isovalue] || 0.5) - v.min) / (v.max - v.min)
493
493
  rotation = ((kvs[:rotation] || 40) * Math::PI / 180.0)
@@ -496,7 +496,7 @@ module GR
496
496
  GR3.clear
497
497
  mesh = GR3.createisosurfacemesh(values, [2.0 / (nx - 1), 2.0 / (ny - 1), 2.0 / (nz - 1)],
498
498
  [-1, -1, -1],
499
- (isovalue * (2 ^ 16 - 1)).round)
499
+ (isovalue * (2**16 - 1)).round)
500
500
  color = kvs[:color] || [0.0, 0.5, 0.8]
501
501
  GR3.setbackgroundcolor(1, 1, 1, 0)
502
502
  GR3.drawmesh(mesh, 1, [0, 0, 0], [0, 0, 1], [0, 1, 0], color, [1, 1, 1])
@@ -561,6 +561,8 @@ module GR
561
561
  # Not yet.
562
562
  end
563
563
 
564
+ GR.settextfontprec(232, 3)
565
+
564
566
  set_viewport(kind, kvs[:subplot])
565
567
  unless kvs[:ax]
566
568
  set_window(kind)
@@ -579,8 +581,7 @@ module GR
579
581
 
580
582
  GR.uselinespec(' ')
581
583
  args.each do |x, y, z, c, spec|
582
- # FIXME
583
- spec ||= ''
584
+ spec ||= kvs[:spec] ||= ''
584
585
  GR.savestate
585
586
  GR.settransparency(kvs[:alpha]) if kvs.has_key?(:alpha)
586
587
 
@@ -682,9 +683,10 @@ module GR
682
683
  cmap = colormap
683
684
  cmin, cmax = kvs[:zrange]
684
685
  data = z.map { |i| normalize_color(i, cmin, cmax) }
685
- colors = data.map { |i| 1000 + i * 255 }
686
- # if kvs[:xflip]
687
- # if kvs[;yflip]
686
+ data.reverse(axis: 0) if kvs[:xflip]
687
+ data.reverse(axis: 1) if kvs[:yflip]
688
+ colors = data * 255 + 1000
689
+ colors = colors.transpose # Julia is column major
688
690
  GR.polarcellarray(0, 0, 0, 360, 0, 1, w, h, colors)
689
691
  draw_polar_axes
690
692
  kvs[:zrange] = [cmin, cmax]
@@ -696,11 +698,18 @@ module GR
696
698
  a, b = z.shape
697
699
  x = (1..b).to_a
698
700
  y = (1..a).to_a
699
- zmin, zmax = kvs[:zlim] || z.minmax
701
+ zmin, zmax = z.minmax
700
702
  elsif equal_length(x, y, z)
701
703
  x, y, z = GR.gridit(x, y, z, 200, 200)
702
- zmin, zmax = kvs[:zlim] || z.compact.minmax # compact : removed nil
704
+ zmin, zmax = z.compact.minmax # compact : removed nil
705
+ end
706
+
707
+ # kvs[:zlim] is supposed to be Array or Range
708
+ if kvs.has_key?(:zlim)
709
+ zmin = kvs[:zlim].first if kvs[:zlim].first
710
+ zmax = kvs[:zlim].last if kvs[:zlim].last
703
711
  end
712
+
704
713
  GR.setspace(zmin, zmax, 0, 90)
705
714
  levels = kvs[:levels] || 0
706
715
  clabels = kvs[:clabels] || false
@@ -792,7 +801,9 @@ module GR
792
801
  colorbar(0.05)
793
802
 
794
803
  when :plot3
795
- GR.polyline3d(x, y, z)
804
+ mask = GR.uselinespec(spec)
805
+ GR.polyline3d(x, y, z) if hasline(mask)
806
+ GR.polymarker3d(x, y, z) if hasmarker(mask)
796
807
  draw_axes(kind, 2)
797
808
 
798
809
  when :scatter3
@@ -821,7 +832,7 @@ module GR
821
832
  plot_polar(x, y)
822
833
 
823
834
  when :trisurf
824
- GR._trisurface_(x, y, z)
835
+ GR.trisurface(x, y, z)
825
836
  draw_axes(kind, 2)
826
837
  colorbar(0.05)
827
838
 
@@ -855,7 +866,7 @@ module GR
855
866
 
856
867
  draw_legend if %i[line step scatter stem].include?(kind) && kvs.has_key?(:labels)
857
868
 
858
- if kvs.has_key?(:update)
869
+ if kvs[:update]
859
870
  GR.updatews
860
871
  # if GR.isinline()
861
872
  # restore_context()
@@ -975,24 +986,31 @@ module GR
975
986
  [*0..(num - 1)].collect { |i| low + i.to_f * (high - low) / (num - 1) }
976
987
  end
977
988
 
978
- def plot_args(args, _fmt = :xys)
989
+ def plot_args(args)
979
990
  # FIXME
980
991
  args = [args] unless args.all? do |i|
981
992
  i.is_a?(Array) && (i[0].is_a?(Array) || narray?(i[0]))
982
993
  end
983
994
  args.map do |xyzc|
995
+ spec = nil
996
+ case xyzc.last
997
+ when String
998
+ spec = xyzc.pop
999
+ when Hash
1000
+ spec = xyzc.pop[:spec]
1001
+ end
1002
+
984
1003
  x, y, z, c = xyzc.map do |i|
985
- if i.is_a?(Array) || narray?(i)
1004
+ if i.is_a?(Array) || narray?(i) || i.nil?
986
1005
  i
987
1006
  elsif i.respond_to?(:to_a)
988
1007
  # Convert an Array-like class such as Daru::Vector to an Array
989
1008
  i.to_a
990
- else
991
- # String
1009
+ else # String
992
1010
  i
993
1011
  end
994
1012
  end
995
- [x, y, z, c]
1013
+ [x, y, z, c, spec]
996
1014
  end
997
1015
  end
998
1016
 
@@ -1035,9 +1053,12 @@ module GR
1035
1053
  def minmax
1036
1054
  xmin = ymin = zmin = cmin = Float::INFINITY
1037
1055
  xmax = ymax = zmax = cmax = -Float::INFINITY
1038
-
1056
+ scale = kvs[:scale]
1039
1057
  args.each do |x, y, z, c|
1040
1058
  if x
1059
+ if scale & GR::OPTION_X_LOG != 0
1060
+ x.map! { |v| v > 0 ? v : Float::NAN }
1061
+ end
1041
1062
  x0, x1 = x.minmax
1042
1063
  xmin = [x0, xmin].min
1043
1064
  xmax = [x1, xmax].max
@@ -1046,6 +1067,9 @@ module GR
1046
1067
  xmax = 1
1047
1068
  end
1048
1069
  if y
1070
+ if scale & GR::OPTION_Y_LOG != 0
1071
+ y.map! { |v| v > 0 ? v : Float::NAN }
1072
+ end
1049
1073
  y0, y1 = y.minmax
1050
1074
  ymin = [y0, ymin].min
1051
1075
  ymax = [y1, ymax].max
@@ -1054,6 +1078,9 @@ module GR
1054
1078
  ymax = 1
1055
1079
  end
1056
1080
  if z
1081
+ if scale & GR::OPTION_Z_LOG != 0
1082
+ z.map! { |v| v > 0 ? v : Float::NAN }
1083
+ end
1057
1084
  z0, z1 = z.minmax
1058
1085
  zmin = [z0, zmin].min
1059
1086
  zmax = [z1, zmax].max
@@ -1071,30 +1098,12 @@ module GR
1071
1098
  xmin, xmax = fix_minmax(xmin, xmax)
1072
1099
  ymin, ymax = fix_minmax(ymin, ymax)
1073
1100
  zmin, zmax = fix_minmax(zmin, zmax)
1074
- if kvs.has_key?(:xlim)
1075
- x0, x1 = kvs[:xlim]
1076
- x0 ||= xmin
1077
- x1 ||= xmax
1078
- kvs[:xrange] = [x0, x1]
1079
- else
1080
- kvs[:xrange] = [xmin, xmax]
1081
- end
1082
- if kvs.has_key?(:ylim)
1083
- y0, y1 = kvs[:ylim]
1084
- y0 ||= ymin
1085
- y1 ||= ymax
1086
- kvs[:yrange] = [y0, y1]
1087
- else
1088
- kvs[:yrange] = [ymin, ymax]
1089
- end
1090
- if kvs.has_key?(:zlim)
1091
- z0, z1 = kvs[:zlim]
1092
- z0 ||= zmin
1093
- z1 ||= zmax
1094
- kvs[:zrange] = [z0, z1]
1095
- else
1096
- kvs[:zrange] = [zmin, zmax]
1097
- end
1101
+
1102
+ # kvs[:xlim], kvs[:ylim], kvs[:zlim] is supposed to be Array or Range
1103
+ kvs[:xrange] = [(kvs[:xlim]&.first || xmin), (kvs[:xlim]&.last || xmax)]
1104
+ kvs[:yrange] = [(kvs[:ylim]&.first || ymin), (kvs[:ylim]&.last || ymax)]
1105
+ kvs[:zrange] = [(kvs[:zlim]&.first || zmin), (kvs[:zlim]&.last || zmax)]
1106
+
1098
1107
  if kvs.has_key?(:clim)
1099
1108
  c0, c1 = kvs[:clim]
1100
1109
  c0 ||= cmin
@@ -1114,7 +1123,7 @@ module GR
1114
1123
  kvs[:labels].each do |label|
1115
1124
  label = label.to_s
1116
1125
  tbx, tby = inqtext(0, 0, label)
1117
- w = [w, tbx[2]].max
1126
+ w = [w, tbx[2] - tbx[0]].max
1118
1127
  h += [tby[2] - tby[0], 0.03].max
1119
1128
  end
1120
1129
  GR.setscale(scale)
@@ -1140,26 +1149,27 @@ module GR
1140
1149
  end
1141
1150
 
1142
1151
  class << self
1143
- # Draw one or more line plots.
1152
+ # (Plot) Draw one or more line plots.
1144
1153
  def plot(*args)
1145
1154
  create_plot(:line, *args)
1146
1155
  end
1147
1156
 
1148
- # Draw one or more step or staircase plots.
1157
+ # (Plot) Draw one or more step or staircase plots.
1149
1158
  def step(*args)
1150
1159
  create_plot(:step, *args)
1151
1160
  end
1152
1161
 
1153
- # Draw one or more scatter plots.
1162
+ # (Plot) Draw one or more scatter plots.
1154
1163
  def scatter(*args)
1155
1164
  create_plot(:scatter, *args)
1156
1165
  end
1157
1166
 
1158
- # Draw a stem plot.
1167
+ # (Plot) Draw a stem plot.
1159
1168
  def stem(*args)
1160
1169
  create_plot(:stem, *args)
1161
1170
  end
1162
1171
 
1172
+ # (Plot)
1163
1173
  def polarhistogram(x, kv = {})
1164
1174
  plt = GR::Plot.new(x, kv)
1165
1175
  plt.kvs[:kind] = :polarhist
@@ -1169,10 +1179,11 @@ module GR
1169
1179
  plt.plot_data
1170
1180
  end
1171
1181
 
1172
- # Draw a heatmap.
1182
+ # (Plot) Draw a heatmap.
1173
1183
  def heatmap(*args)
1174
1184
  # FIXME
1175
- _x, _y, z, kv = parse_args(*args)
1185
+ args, kv = format_xyzc(*args)
1186
+ _x, _y, z = args
1176
1187
  ysize, xsize = z.shape
1177
1188
  z = z.reshape(xsize, ysize)
1178
1189
  create_plot(:heatmap, kv) do |plt|
@@ -1182,6 +1193,7 @@ module GR
1182
1193
  end
1183
1194
  end
1184
1195
 
1196
+ # (Plot) Draw a polarheatmap.
1185
1197
  def polarheatmap(*args)
1186
1198
  d = args.shift
1187
1199
  # FIXME
@@ -1197,83 +1209,78 @@ module GR
1197
1209
  end
1198
1210
 
1199
1211
  alias _contour_ contour
1200
- # Draw a contour plot.
1212
+ # (Plot) Draw a contour plot.
1201
1213
  def contour(*args)
1202
- x, y, z, kv = parse_args(*args)
1203
- create_plot(:contour, x, y, z, kv)
1214
+ create_plot(:contour, *format_xyzc(*args))
1204
1215
  end
1205
1216
 
1206
1217
  alias _contourf_ contourf
1207
- # Draw a filled contour plot.
1218
+ # (Plot) Draw a filled contour plot.
1208
1219
  def contourf(*args)
1209
- x, y, z, kv = parse_args(*args)
1210
- create_plot(:contourf, x, y, z, kv)
1220
+ create_plot(:contourf, *format_xyzc(*args))
1211
1221
  end
1212
1222
 
1213
1223
  alias _hexbin_ hexbin
1214
- # Draw a hexagon binning plot.
1224
+ # (Plot) Draw a hexagon binning plot.
1215
1225
  def hexbin(*args)
1216
1226
  create_plot(:hexbin, *args)
1217
1227
  end
1218
1228
 
1219
- # Draw a triangular contour plot.
1229
+ # (Plot) Draw a triangular contour plot.
1220
1230
  def tricont(*args)
1221
- x, y, z, kv = parse_args(*args)
1222
- create_plot(:tricont, x, y, z, kv)
1231
+ create_plot(:tricont, *format_xyzc(*args))
1223
1232
  end
1224
1233
 
1225
- # Draw a three-dimensional wireframe plot.
1234
+ # (Plot) Draw a three-dimensional wireframe plot.
1226
1235
  def wireframe(*args)
1227
- x, y, z, kv = parse_args(*args)
1228
- create_plot(:wireframe, x, y, z, kv)
1236
+ create_plot(:wireframe, *format_xyzc(*args))
1229
1237
  end
1230
1238
 
1231
- # Draw a three-dimensional surface plot.
1239
+ # (Plot) Draw a three-dimensional surface plot.
1232
1240
  alias _surface_ surface
1233
1241
  def surface(*args)
1234
- x, y, z, kv = parse_args(*args)
1235
- create_plot(:surface, x, y, z, kv)
1242
+ create_plot(:surface, *format_xyzc(*args))
1236
1243
  end
1237
1244
 
1245
+ # (Plot)
1238
1246
  def polar(*args)
1239
1247
  create_plot(:polar, *args)
1240
1248
  end
1241
1249
 
1242
- alias _trisurface_ trisurface
1243
- # Draw a triangular surface plot.
1244
- def trisurface(*args)
1245
- x, y, z, kv = parse_args(*args)
1246
- create_plot(:trisurf, x, y, z, kv)
1250
+ # (Plot) Draw a triangular surface plot.
1251
+ def trisurf(*args)
1252
+ create_plot(:trisurf, *format_xyzc(*args))
1247
1253
  end
1248
1254
 
1249
- # Draw one or more three-dimensional line plots.
1255
+ # (Plot) Draw one or more three-dimensional line plots.
1250
1256
  def plot3(*args)
1251
1257
  create_plot(:plot3, *args)
1252
1258
  end
1253
1259
 
1254
- # Draw one or more three-dimensional scatter plots.
1260
+ # (Plot) Draw one or more three-dimensional scatter plots.
1255
1261
  def scatter3(*args)
1256
1262
  create_plot(:scatter3, *args)
1257
1263
  end
1258
1264
 
1259
1265
  alias _shade_ shade
1266
+ # (Plot)
1260
1267
  def shade(*args)
1261
1268
  create_plot(:shade, *args)
1262
1269
  end
1263
1270
 
1271
+ # (Plot)
1264
1272
  def volume(v, kv = {})
1265
1273
  create_plot(:volume, v, kv) do |plt|
1266
1274
  plt.args = [[nil, nil, v, nil, '']]
1267
1275
  end
1268
1276
  end
1269
1277
 
1270
- # Draw a bar plot.
1278
+ # (Plot) Draw a bar plot.
1271
1279
  def barplot(labels, heights, kv = {})
1272
1280
  labels = labels.map(&:to_s)
1273
1281
  wc, hc = barcoordinates(heights)
1274
- horizontal = kv[:horizontal] || false
1275
1282
  create_plot(:bar, labels, heights, kv) do |plt|
1276
- if horizontal
1283
+ if kv[:horizontal]
1277
1284
  plt.args = [[hc, wc, nil, nil, '']]
1278
1285
  plt.kvs[:yticks] = [1, 1]
1279
1286
  plt.kvs[:yticklabels] = labels
@@ -1285,7 +1292,7 @@ module GR
1285
1292
  end
1286
1293
  end
1287
1294
 
1288
- # Draw a histogram.
1295
+ # (Plot) Draw a histogram.
1289
1296
  def histogram(x, kv = {})
1290
1297
  create_plot(:hist, x, kv) do |plt|
1291
1298
  nbins = plt.kvs[:nbins] || 0
@@ -1294,7 +1301,7 @@ module GR
1294
1301
  end
1295
1302
  end
1296
1303
 
1297
- # Draw an image.
1304
+ # (Plot) Draw an image.
1298
1305
  def imshow(img, kv = {})
1299
1306
  img = Numo::DFloat.cast(img) # Umm...
1300
1307
  create_plot(:imshow, img, kv) do |plt|
@@ -1302,7 +1309,7 @@ module GR
1302
1309
  end
1303
1310
  end
1304
1311
 
1305
- # Draw an isosurface.
1312
+ # (Plot) Draw an isosurface.
1306
1313
  def isosurface(v, kv = {})
1307
1314
  v = Numo::DFloat.cast(v) # Umm...
1308
1315
  create_plot(:isosurface, v, kv) do |plt|
@@ -1310,6 +1317,35 @@ module GR
1310
1317
  end
1311
1318
  end
1312
1319
 
1320
+ def hold(flag = true)
1321
+ plt = GR::Plot.last_plot
1322
+ plt.kvs.slice(:window, :scale, :xaxis, :yaxis, :zaxis).merge({ ax: flag, clear: !flag })
1323
+ end
1324
+
1325
+ # Set current subplot index.
1326
+ def subplot(nr, nc, p)
1327
+ xmin = 1
1328
+ xmax = 0
1329
+ ymin = 1
1330
+ ymax = 0
1331
+ p = [p] if p.is_a? Integer
1332
+ p.each do |i|
1333
+ r = (nr - (i - 1) / nc).to_f
1334
+ c = ((i - 1) % nc + 1).to_f
1335
+ xmin = [xmin, (c - 1) / nc].min
1336
+ xmax = [xmax, c / nc].max
1337
+ ymin = [ymin, (r - 1) / nr].min
1338
+ ymax = [ymax, r / nr].max
1339
+ end
1340
+ {
1341
+ subplot: [xmin, xmax, ymin, ymax],
1342
+ # The policy of clearing when p[0]==1 is controversial
1343
+ clear: p[0] == 1,
1344
+ update: p[-1] == nr * nc
1345
+ }
1346
+ end
1347
+
1348
+ # (Plot) Save the current figure to a file.
1313
1349
  def savefig(filename, kv = {})
1314
1350
  GR.beginprint(filename)
1315
1351
  plt = GR::Plot.last_plot
@@ -1320,40 +1356,41 @@ module GR
1320
1356
 
1321
1357
  private
1322
1358
 
1323
- def create_plot(type, *args, &block)
1359
+ def create_plot(type, *args)
1324
1360
  plt = GR::Plot.new(*args)
1325
1361
  plt.kvs[:kind] = type
1326
- block.call(plt) if block_given?
1362
+ yield(plt) if block_given?
1327
1363
  plt.plot_data
1328
1364
  plt
1329
1365
  end
1330
1366
 
1331
- def parse_args(*args)
1367
+ def format_xyzc(*args)
1332
1368
  kv = if args[-1].is_a? Hash
1333
1369
  args.pop
1334
1370
  else
1335
1371
  {}
1336
1372
  end
1337
- if args.size == 1
1338
- if args[0].is_a? Array
1339
- z = Numo::DFloat.cast(args[0])
1340
- elsif narray?(args[0])
1341
- z = args[0]
1373
+
1374
+ args = [args] unless args.all? do |i|
1375
+ i.is_a?(Array) && (i[0].is_a?(Array) || narray?(i[0]))
1376
+ end
1377
+ args.map! do |xyzc|
1378
+ if xyzc.size == 1
1379
+ if xyzc[0].is_a? Array
1380
+ z = Numo::DFloat.cast(xyzc[0])
1381
+ elsif narray?(xyzc[0])
1382
+ z = xyzc[0]
1383
+ end
1384
+ xsize, ysize = z.shape
1385
+ x = (1..ysize).to_a * xsize
1386
+ y = (1..xsize).map { |i| Array.new(ysize, i) }.flatten
1387
+ [x, y, z]
1388
+ else
1389
+
1390
+ xyzc
1342
1391
  end
1343
- xsize, ysize = z.shape
1344
- # NOTE:
1345
- # See
1346
- # https://github.com/jheinen/GR.jl/pull/246
1347
- # https://github.com/jheinen/GR.jl/issues/241
1348
- x = (1..ysize).to_a * xsize
1349
- y = (1..xsize).map { |i| Array.new(ysize, i) }.flatten
1350
-
1351
- elsif args.size == 3
1352
- x, y, z = args
1353
- else
1354
- raise
1355
1392
  end
1356
- [x, y, z, kv]
1393
+ [*args, kv]
1357
1394
  end
1358
1395
 
1359
1396
  def hist(x, nbins = 0)