ruby-gr 0.0.17 → 0.0.22

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 668fdb6db9526bf6b55fb6b293aa776ec625b76a650be20852efcd2869f1c751
4
- data.tar.gz: 3b3a7645021470b12840734506f2a466d32fdff111c0e7dd6762ccf9e374ee92
3
+ metadata.gz: d61176c3d03c6d635adbdc0cec5dd701b2303862405fa63a60815fc03b724054
4
+ data.tar.gz: 405d76e691b88c53d471b2e552f1af310e0a4d4b377c02ecbeac1827e62f5921
5
5
  SHA512:
6
- metadata.gz: 982637afaeb9be0f9b7abb631e1554fd04a2082ec7b019cb55e4f8d4ec870634f734b1b28dda8177e784a593476e0f065a924bd362ba58a881210015a7ec2f4c
7
- data.tar.gz: 5bd9205778607854747d7ab9e4c1165600792710a9c3df0452c3c306fceff7ab90d665ccb244aa4761c407f59df9c3f80413bf4663ff81643887966b87109e27
6
+ metadata.gz: 4d23ae259c265dd3e8ed030a31a7f04ca4e358859e807885cda9f53c2c4b0be5839ccb2464bd4a6c2c9cf5d68fd99665d3f32dd74254ddd2eadfe4fe7123e9e3
7
+ data.tar.gz: 20b3a2dfec804617038a5884e272197d92f6f10069e568b149736d63775054d4d0c29e6f346397338401db44da1a4f3d9d5ba3c3f65a461c38df97ed8d10dc34
data/README.md CHANGED
@@ -6,31 +6,43 @@
6
6
  [![Gitter Chat](https://badges.gitter.im/red-data-tools/en.svg)](https://gitter.im/red-data-tools/en)
7
7
  [![Docs Latest](https://img.shields.io/badge/docs-latest-blue.svg)](https://rubydoc.info/gems/ruby-gr)
8
8
 
9
- <p align="center">
10
- <img src="https://user-images.githubusercontent.com/5798442/70857099-13d57600-1f2c-11ea-8f3c-7d81065f13a5.png">
11
- </p>
12
-
13
- :bar_chart: [GR framework](https://github.com/sciapp/gr) - the graphics library for visualization - for Ruby
9
+ [![rdatasets-1](https://i.imgur.com/XEQ6wKs.png)](examples/rdatasets.rb)
10
+ [![stem](https://i.imgur.com/3w0Ejrm.png)](examples/fast_plots.rb)
11
+ [![histogram](https://i.imgur.com/xUdoA2s.png)](examples/fast_plots.rb)
12
+ [![barplot](https://i.imgur.com/52bOFKE.png)](examples/fast_plots.rb)
13
+ [![scatter3](https://i.imgur.com/yTTVetQ.png)](examples/fast_plots.rb)
14
+ [![volume](https://i.imgur.com/CuRN6oC.png)](examples/fast_plots.rb)
15
+ [![griddata](https://i.imgur.com/58HdYDo.png)](examples/griddata.rb)
16
+ [![2darray](https://i.imgur.com/aKR2FJG.png)](examples/2darray.rb)
17
+ [![2dpolararray](https://i.imgur.com/cmSrxvS.png)](examples/2dpolararray.rb)
18
+ [![hexbin](https://i.imgur.com/unWhQHr.png)](examples/hexbin.rb)
19
+ [![rdatasets-2](https://i.imgur.com/ZPit2F5.png)](examples/rdatasets.rb)
20
+ [![rdatasets-3](https://i.imgur.com/TbNoxwy.png)](examples/rdatasets.rb)
21
+ [![surface](https://i.imgur.com/sWdaHme.png)](examples/kws2.rb)
22
+ [![face](https://i.imgur.com/uLCKi2r.png)](examples/face.rb)
23
+ [![shade](https://i.imgur.com/VJmS3EQ.png)](examples/shade_ex.rb)
24
+
25
+ :bar_chart: [GR framework](https://github.com/sciapp/gr) - powerful visualization library - for Ruby
14
26
 
15
27
  ## Installation
16
28
 
17
- GR.rb supports Ruby 2.4+.
18
-
19
- [Install GR](#gr-installation).
29
+ GR.rb supports Ruby 2.5+.
20
30
 
21
- Set environment variable GRDIR, if you have not already done.
31
+ First, [install GR](#gr-installation). Then install `ruby-gr` gem.
22
32
 
23
33
  ```sh
24
- export GRDIR="/your/path/to/gr"
34
+ gem install ruby-gr
25
35
  ```
26
36
 
27
- Add this line to your application's Gemfile:
37
+ Note: If you are using Rubyinstaller(Windows), pacman will automatically install [mingw-w64-gr](https://packages.msys2.org/base/mingw-w64-gr).
38
+
39
+ Set environment variable `GRDIR`.
28
40
 
29
41
  ```sh
30
- gem 'ruby-gr'
42
+ export GRDIR="/your/path/to/gr"
31
43
  ```
32
44
 
33
- GR3 and GR::Plot require [numo-narray](https://github.com/ruby-numo/numo-narray).
45
+ Note: If you use package managers to install GR, [pkg-config](https://github.com/ruby-gnome/pkg-config) may automatically detect the shared library location without specifying the `GRDIR` environment variable.
34
46
 
35
47
  ## Quick Start
36
48
 
@@ -47,43 +59,103 @@ y = [0.3, 0.5, 0.4, 0.2, 0.6, 0.7]
47
59
  GR.plot(x, y)
48
60
  ```
49
61
 
50
- ## Examples
62
+ <p align="center">
63
+ <img src="https://user-images.githubusercontent.com/5798442/84570709-242ab880-adca-11ea-9099-3a6b3418bf19.png">
64
+ </p>
65
+
66
+ ```ruby
67
+ require 'gr/plot'
68
+
69
+ x = Numo::DFloat.linspace(0, 10, 101)
70
+ y1 = Numo::NMath.sin(x)
71
+ y2 = Numo::NMath.cos(x)
72
+
73
+ GR.plot(
74
+ [x, y1, 'bo'], [x, y2, 'g*'],
75
+ title: "Multiple plot example",
76
+ xlabel: "x",
77
+ ylabel: "y",
78
+ ylim: [-1.2, 1.2],
79
+ labels: ["sin(x)", "cos(x)"],
80
+ location: 11
81
+ )
82
+ ```
83
+
84
+ Save in PNG format.
51
85
 
52
- Have a look in the [`examples`](https://github.com/red-data-tools/GR.rb/tree/master/examples) directory.
53
- * [Example Gallery](https://github.com/red-data-tools/GR.rb/wiki/Example-gallery)
86
+ ```ruby
87
+ GR.savefig("figure.png")
88
+ ```
54
89
 
55
- ## Features
90
+ ## API Overview
56
91
 
57
- #### GR::Plot
92
+ There are two different approaches to plotting with GR.rb. One way is to call Matlab-like APIs. The other is to call GR/GR3 native functions. We are planning to prepare a [more object-oriented interface](https://github.com/kojix2/GRUtils.rb) based on [GRUtils.jl](https://github.com/heliosdrm/GRUtils.jl) in the future.
58
93
 
59
- A simple, matlab-style API.
94
+ #### GR::Plot - A simple, matlab-style API.
60
95
 
61
96
  ```ruby
62
97
  require 'gr/plot'
98
+ GR.plot(x, y)
63
99
  ```
64
100
 
65
- `plot` `step` `scatter` `stem` `histogram` `contour` `contourf` `hexbin` `heatmap` `wireframe` `surface` `plot3` `scatter3` `imshow` `isosurface` `polar` `polarhist` `polarheatmap` `trisurf` `tricont` `shade` `volume`
66
-
67
- #### GR
101
+ List of vailable functions. See [GR.rb Wiki](https://github.com/red-data-tools/GR.rb/wiki) for details.
102
+
103
+ [`plot`](../../wiki/Plotting-functions#plot)
104
+ [`step`](../../wiki/Plotting-functions#step)
105
+ [`plot3`](../../wiki/Plotting-functions#plot3)
106
+ [`polar`](../../wiki/Plotting-functions#polar)
107
+ [`scatter`](../../wiki/Plotting-functions#scatter)
108
+ [`scatter3`](../../wiki/Plotting-functions#scatter3)
109
+ [`stem`](../../wiki/Plotting-functions#stem)
110
+ [`barplot`](../../wiki/Plotting-functions#barplot)
111
+ [`histogram`](../../wiki/Plotting-functions#histogram)
112
+ [`polarhistogram`](../../wiki/Plotting-functions#polarhistogram)
113
+ [`hexbin`](../../wiki/Plotting-functions#hexbin)
114
+ [`contour`](../../wiki/Plotting-functions#contour)
115
+ [`contourf`](../../wiki/Plotting-functions#contourf)
116
+ [`tricont`](../../wiki/Plotting-functions#tricont)
117
+ [`surface`](../../wiki/Plotting-functions#surface)
118
+ [`trisurf`](../../wiki/Plotting-functions#trisurf)
119
+ [`wireframe`](../../wiki/Plotting-functions#wireframe)
120
+ [`volume`](../../wiki/Plotting-functions#volume)
121
+ [`heatmap`](../../wiki/Plotting-functions#heatmap)
122
+ [`polarheatmap`](../../wiki/Plotting-functions#polarheatmap)
123
+ [`shade`](../../wiki/Plotting-functions#shade)
124
+ [`imshow`](../../wiki/Plotting-functions#imshow)
125
+ [`isosurface`](../../wiki/Plotting-functions#isosurface)
126
+
127
+ #### GR - A module for calling native GR functions.
128
+
129
+ 2-D Plots and common 3-D Plots.
68
130
 
69
131
  ```ruby
70
132
  require 'gr'
133
+
134
+ # For example
135
+ GR.setviewport(0.1, 0.9, 0.1, 0.9)
136
+ GR.setwindow(0.0, 20.0, 0.0, 20.0)
71
137
  ```
72
138
 
73
- #### GR3
139
+ #### GR3 - A module for calling native GR3 functions.
140
+
141
+ Complex 3D scenes.
74
142
 
75
143
  ```ruby
76
144
  require 'gr3'
145
+
146
+ # For example
147
+ GR3.cameralookat(-3, 2, -2, 0, 0, 0, 0, 0, -1)
77
148
  ```
78
149
 
79
150
  ## Documentation
80
151
 
152
+ - [GR.rb Wiki](https://github.com/red-data-tools/GR.rb/wiki)
81
153
  - [GR Framework](https://gr-framework.org/)
82
154
  - [GR.rb API Documentation](https://rubydoc.info/gems/ruby-gr)
83
155
 
84
156
  ## GR Installation
85
157
 
86
- ### Official binary release
158
+ ### Installing an official release (recommended)
87
159
 
88
160
  Download the [latest release](https://github.com/sciapp/gr/releases).
89
161
 
@@ -95,23 +167,25 @@ export GRDIR="your/path/to/gr"
95
167
 
96
168
  * macOS Catalina and macOS Mojave: See the "How to open an app that hasn’t been notarized or is from an unidentified developer" section of [Safely open apps on your Mac](https://support.apple.com/en-us/HT202491) in the Apple documentation.
97
169
 
98
- ### Homebrew
170
+ ### Using package managers
99
171
 
100
- ```sh
101
- brew install libgr
102
- ```
172
+ * The third party GR packages for Mac, Linux and Windows are available (for advanced users).
173
+ * If you find any problem, please report the issue [here](https://github.com/red-data-tools/GR.rb/issues).
174
+ * Note: These packages may not have some features, for example, video output.
103
175
 
104
- Set environment variable GRDIR.
176
+ #### Mac - Homebrew
105
177
 
106
178
  ```sh
107
- export GRDIR=$(brew --prefix libgr)
179
+ brew install libgr
108
180
  ```
109
181
 
110
- If you fail to build libgr using homebrew, Please feel free to [send us your feedback](https://github.com/red-data-tools/GR.rb/issues).
182
+ #### Linux - APT Yum
183
+
184
+ [packages.red-data-tools.org](https://github.com/red-data-tools/packages.red-data-tools.org) provides `libgr-dev`, `libgr3-dev` and `libgrm-dev`
111
185
 
112
- ### Red data tools repository
186
+ ### Windows - MSYS2
113
187
 
114
- Red data tools provides [packages](https://github.com/red-data-tools/packages.red-data-tools.org ) related to our project including `libgr-dev` and `libgr3-dev` for advanced users.
188
+ If you are using Rubyinstaller, pacman will automatically install [mingw-w64-gr](https://packages.msys2.org/base/mingw-w64-gr) when the gem is installed.
115
189
 
116
190
  ## Backend for Charty
117
191
 
@@ -119,13 +193,14 @@ GR.rb will be the default backend for [Charty](https://github.com/red-data-tools
119
193
 
120
194
  ## Contributing
121
195
 
122
- * Report bugs
123
- * Fix bugs and submit pull requests
196
+ * [Report bugs](https://github.com/red-data-tools/GR.rb/issues)
197
+ * Fix bugs and [submit pull requests](https://github.com/red-data-tools/GR.rb/pulls)
124
198
  * Write, clarify, or fix documentation
125
199
  * Suggest or add new features
126
- * Create visualization library based on GR.rb
200
+ * Update GR packages ( Homebrew, MinGW, red-data-tools )
201
+ * Create visualization tools based on GR.rb
127
202
 
128
203
  ## Acknowledgements
129
204
 
130
- We would like to thank Josef Heinen, the creator of [GR.jl](https://github.com/jheinen/GR.jl), Florian Rhiem, the creator of [python-gr](https://github.com/sciapp/python-gr), and [GR](https://github.com/sciapp/gr) developers.
205
+ We would like to thank Josef Heinen, the creator of [GR](https://github.com/sciapp/gr) and [GR.jl](https://github.com/jheinen/GR.jl), Florian Rhiem, the creator of [python-gr](https://github.com/sciapp/python-gr), and all [GR](https://github.com/sciapp/gr) developers.
131
206
 
data/lib/gr.rb CHANGED
@@ -52,23 +52,20 @@ module GR
52
52
  attr_accessor :ffi_lib
53
53
  end
54
54
 
55
- raise Error, 'Please set env variable GRDIR' unless ENV['GRDIR']
55
+ require_relative 'gr_commons/gr_commons'
56
+ extend GRCommons::SearchSharedLibrary
56
57
 
57
58
  # Platforms | path
58
59
  # Windows | bin/libgr.dll
59
60
  # MacOSX | lib/libGR.so (NOT .dylib)
60
61
  # Ubuntu | lib/libGR.so
61
- if Object.const_defined?(:RubyInstaller)
62
- self.ffi_lib = File.expand_path('bin/libgr.dll', ENV['GRDIR'])
63
- RubyInstaller::Runtime.add_dll_directory(File.dirname(ffi_lib))
64
- else
65
- self.ffi_lib = File.expand_path('lib/libGR.so', ENV['GRDIR'])
66
- end
67
-
68
- # Change the default encoding to UTF-8.
69
- ENV['GKS_ENCODING'] ||= 'utf8'
62
+ self.ffi_lib = case RbConfig::CONFIG['host_os']
63
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
64
+ search_shared_library('libgr.dll', 'gr')
65
+ else
66
+ search_shared_library('libGR.so', 'gr')
67
+ end
70
68
 
71
- require_relative 'gr_commons/gr_commons'
72
69
  require_relative 'gr/version'
73
70
  require_relative 'gr/ffi'
74
71
  require_relative 'gr/grbase'
@@ -99,7 +96,12 @@ module GR
99
96
  super
100
97
  end
101
98
 
102
- # inqdspsize
99
+ # Get the current display size.
100
+ # Depending on the current workstation type, the current display might be
101
+ # the primary screen (e.g. when using gksqt or GKSTerm) or a purely virtual
102
+ # display (e.g. when using Cairo). When a high DPI screen is used as the
103
+ # current display, width and height will be in logical pixels.
104
+ # @return [Array] meter_width, meter_height, width, height
103
105
  def inqdspsize
104
106
  inquiry %i[double double int int] do |*pts|
105
107
  super(*pts)
@@ -111,9 +113,7 @@ module GR
111
113
  # @param connection [String] A connection identifier.
112
114
  # @param workstation_type [Integer] The desired workstation type.
113
115
  # * 5 : Workstation Independent Segment Storage
114
- # * 7, 8 : Computer Graphics Metafile (CGM binary, clear text)
115
116
  # * 41 : Windows GDI
116
- # * 51 : Mac Quickdraw
117
117
  # * 61 - 64 : PostScript (b/w, color)
118
118
  # * 101, 102 : Portable Document Format (plain, compressed)
119
119
  # * 210 - 213 : X Windows
@@ -134,7 +134,6 @@ module GR
134
134
  # * 410 : Socket driver
135
135
  # * 415 : 0MQ driver
136
136
  # * 420 : OpenGL
137
- # * 430 : HTML5 Canvas
138
137
  def openws(*)
139
138
  super
140
139
  end
@@ -157,6 +156,7 @@ module GR
157
156
  super
158
157
  end
159
158
 
159
+ # Configure the specified workstation.
160
160
  def configurews(*)
161
161
  super
162
162
  end
@@ -298,6 +298,7 @@ module GR
298
298
  super(n, x, y, m, method)
299
299
  end
300
300
 
301
+ # Interpolate data from arbitrary points at points on a rectangular grid.
301
302
  def gridit(xd, yd, zd, nx, ny)
302
303
  nd = equal_length(xd, yd, zd)
303
304
  inquiry [{ double: nx }, { double: ny }, { double: nx * ny }] do |px, py, pz|
@@ -359,7 +360,6 @@ module GR
359
360
  super
360
361
  end
361
362
 
362
- # inqlinecolorind
363
363
  def inqlinecolorind
364
364
  inquiry_int { |pt| super(pt) }
365
365
  end
@@ -505,6 +505,8 @@ module GR
505
505
  # * 129 : FONT_PALATINO_BOLDITALIC
506
506
  # * 130 : FONT_ZAPFCHANCERY_MEDIUMITALIC
507
507
  # * 131 : FONT_ZAPFDINGBATS
508
+ # * 232 : FONT_COMPUTERMODERN
509
+ # * 233 : FONT_DEJAVUSANS
508
510
  # @param precision [Integer] Text precision
509
511
  # * 0 : TEXT_PRECISION_STRING
510
512
  # * String precision (higher quality)
@@ -512,10 +514,14 @@ module GR
512
514
  # * Character precision (medium quality)
513
515
  # * 2 : TEXT_PRECISION_STROKE
514
516
  # * Stroke precision (lower quality)
517
+ # * 3 : TEXT_PRECISION_OUTLINE
518
+ # * Outline precision (highest quality)
515
519
  # The appearance of a font depends on the text precision value specified.
516
520
  # STRING, CHARACTER or STROKE precision allows for a greater or lesser
517
521
  # realization of the text primitives, for efficiency. STRING is the default
518
- # precision for GR and produces the highest quality output.
522
+ # precision for GR and produces the highest quality output using either
523
+ # native font rendering or FreeType. OUTLINE uses the GR path rendering
524
+ # functions to draw individual glyphs and produces the highest quality output.
519
525
  def settextfontprec(*)
520
526
  super
521
527
  end
@@ -557,6 +563,14 @@ module GR
557
563
  super
558
564
  end
559
565
 
566
+ # Gets the current character height.
567
+ # This function gets the height of text output primitives. Text height is
568
+ # defined as a percentage of the default window. GR uses the default text
569
+ # height of 0.027 (2.7% of the height of the default window).
570
+ def inqcharheight
571
+ inquiry_double { |pt| super(pt) }
572
+ end
573
+
560
574
  # Set the current character text angle up vector.
561
575
  # @param ux [Numeric] Text up vector
562
576
  # @param uy [Numeric] Text up vector
@@ -618,6 +632,8 @@ module GR
618
632
  # * Fill the interior of the polygon using the style index as a pattern index
619
633
  # * 3 : HATCH
620
634
  # * Fill the interior of the polygon using the style index as a cross-hatched style
635
+ # * 4 : SOLID_WITH_BORDER
636
+ # * Fill the interior of the polygon using the fill color index and draw the bounding polyline
621
637
  # `setfillintstyle` defines the interior style for subsequent fill area output
622
638
  # primitives. The default interior style is HOLLOW.
623
639
  def setfillintstyle(*)
@@ -641,6 +657,7 @@ module GR
641
657
  end
642
658
 
643
659
  # Returns the current fill area color index.
660
+ # This function gets the color index for PATTERN and HATCH fills.
644
661
  def inqfillstyle
645
662
  inquiry_int { |pt| super(pt) }
646
663
  end
@@ -654,6 +671,7 @@ module GR
654
671
  end
655
672
 
656
673
  # Returns the current fill area color index.
674
+ # This function gets the color of fill area output primitives.
657
675
  def inqfillcolorind
658
676
  inquiry_int { |pt| super(pt) }
659
677
  end
@@ -928,12 +946,40 @@ module GR
928
946
  # coordinate unit. Major tick marks are twice as long as minor tick marks.
929
947
  # A negative value reverses the tick marks on the axes from inward facing
930
948
  # to outward facing (or vice versa).
949
+ # Tick marks are positioned along each axis so that major tick marks fall on
950
+ # the axes origin (whether visible or not). Major tick marks are labeled
951
+ # with the corresponding data values. Axes are drawn according to the scale
952
+ # of the window. Axes and tick marks are drawn using solid lines; line color
953
+ # and width can be modified using the gr_setlinetype and gr_setlinewidth
954
+ # functions. Axes are drawn according to the linear or logarithmic
955
+ # transformation established by the gr_setscale function.
931
956
  def axes(*)
932
957
  super
933
958
  end
934
959
 
935
960
  alias axes2d axes
936
961
 
962
+ # Create axes in the current workspace and supply a custom function for
963
+ # changing the behaviour of the tick labels.
964
+ # @param x_tick [Numeric] The interval between minor tick marks on the X axis.
965
+ # @param y_tick [Numeric] The interval between minor tick marks on the Y axis.
966
+ # @param x_org [Numeric] The world coordinate of the origin (point of intersection) of the X axis.
967
+ # @param y_org [Numeric] The world coordinate of the origin (point of intersection) of the Y axis.
968
+ # @param major_x [Integer] Unitless integer value specifying the number of minor tick intervals between major tick marks on the X axis. Values of 0 or 1 imply no minor ticks. Negative values specify no labels will be drawn for the associated axis.
969
+ # @param major_y [Integer] Unitless integer value specifying the number of minor tick intervals between major tick marks on the Y axis. Values of 0 or 1 imply no minor ticks. Negative values specify no labels will be drawn for the associated axis.
970
+ # @param tick_size [Numeric] The length of minor tick marks specified in a normalized device coordinate unit. Major tick marks are twice as long as minor tick marks. A negative value reverses the tick marks on the axes from inward facing to outward facing (or vice versa).
971
+ # @param fpx [Pointer] Function pointer to a function that returns a label for a given tick on the X axis. The callback function should have the following arguments [Numeric]
972
+ # @param fpy [Pointer] Exactly same as the fpx above, but for the the Y axis.
973
+ # Similar to gr_axes() but allows more fine-grained control over tick labels
974
+ # and text positioning by supplying callback functions. Within the callback
975
+ # function you can use normal GR text primitives for performing any
976
+ # manipulations on the label text.
977
+ # See gr_axes() for more details on drawing axes.
978
+ # * fpx/fpy
979
+ # * param x [Numeric] NDC of the label in X direction.
980
+ # * param y [Numeric] NDC of the label in Y direction.
981
+ # * param svalue [String] Internal string representation of the text drawn by GR at (x,y).
982
+ # * param value [Numeric] Floating point representation of the label drawn at (x,y).
937
983
  def axeslbl(*)
938
984
  super
939
985
  end
@@ -1591,10 +1637,10 @@ module GR
1591
1637
  super(npoints, x, y, ntri, triangles.ref)
1592
1638
  end
1593
1639
  if n_tri > 0
1594
- tri = triangles.to_str(3 * n_tri * Fiddle::SIZEOF_INT).unpack('l*') # Int32
1640
+ tri = triangles.to_str(dim * n_tri * Fiddle::SIZEOF_INT).unpack('l*') # Int32
1595
1641
  # Ruby : 0-based indexing
1596
1642
  # Julia : 1-based indexing
1597
- tri = tri.each_slice(3).to_a
1643
+ tri = tri.each_slice(dim).to_a
1598
1644
  [n_tri, tri]
1599
1645
  else
1600
1646
  0
@@ -37,59 +37,59 @@ 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
40
+ KW_ARGS = %i[accelerate algorithm alpha ax backgroundcolor barwidth baseline
41
+ clabels clear clim color colormap crange figsize grid 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 xticks yaxis yflip ylabel ylim ylog
45
+ zflip yrange yticks viewport vp where window zaxis zlabel zlim
46
+ zlog zrange zticks].freeze
45
47
 
46
48
  @last_plot = nil
47
49
  class << self
48
50
  attr_accessor :last_plot
49
51
  end
50
52
 
51
- def initialize(*args)
52
- @kvs = if args[-1].is_a? Hash
53
- args.pop
54
- else
55
- {}
56
- end
53
+ attr_accessor :args, :kvs, :scheme
54
+
55
+ def initialize(*raw_args)
56
+ @kvs = raw_args.last.is_a?(Hash) ? raw_args.pop : {}
57
+ @args = plot_args(raw_args) # method name is the same as Julia/Python
58
+
57
59
  # Check keyword options.
58
- @kvs.each_key do |k|
59
- warn "Unknown keyword: #{k}" unless KW_ARGS.include? k
60
- end
60
+ kvs.each_key { |k| warn "Unknown keyword: #{k}" unless KW_ARGS.include? k }
61
61
 
62
62
  # label(singular form) is a original keyword arg which GR.jl does not have.
63
- @kvs[:labels] = [@kvs[:label]] if @kvs[:label] && @kvs[:labels].nil?
64
-
65
- @args = plot_args(args) # method name is the same as Julia/Python
66
- @kvs[:size] ||= [600, 450]
67
- @kvs[:ax] = false if @kvs[:ax].nil?
68
- @kvs[:subplot] ||= [0, 1, 0, 1]
69
- @kvs[:clear] = true if @kvs[:clear].nil?
70
- @kvs[:update] = true if @kvs[:update].nil?
71
- @scheme = 0
63
+ kvs[:labels] ||= [kvs[:label]] if kvs.has_key? :label
64
+
65
+ # Don't use ||= here, because we need to tell `false` from `nil`
66
+ kvs[:size] = [600, 450] unless kvs.has_key? :size
67
+ kvs[:ax] = false unless kvs.has_key? :ax
68
+ kvs[:subplot] = [0, 1, 0, 1] unless kvs.has_key? :subplot
69
+ kvs[:clear] = true unless kvs.has_key? :clear
70
+ kvs[:update] = true unless kvs.has_key? :update
71
+
72
+ @scheme = 0
72
73
  @background = 0xffffff
73
- @handle = nil
74
+ # @handle = nil # This variable will be used in gr_meta
75
+
74
76
  self.class.last_plot = self
75
77
  end
76
- attr_accessor :args, :kvs, :scheme
77
78
 
78
79
  def set_viewport(kind, subplot)
79
80
  mwidth, mheight, width, height = GR.inqdspsize
80
- if kvs[:figsize]
81
- w = 0.0254 * width * kvs[:figsize][0] / mwidth
82
- h = 0.0254 * height * kvs[:figsize][1] / mheight
83
- else
84
- dpi = width / mwidth * 0.0254
85
- if dpi > 200
86
- w, h = kvs[:size].map { |x| x * dpi / 100 }
87
- else
88
- w, h = kvs[:size]
89
- end
90
- end
91
- viewport = [0, 0, 0, 0]
81
+ dpi = width / mwidth * 0.0254
82
+ w, h = if kvs[:figsize]
83
+ [(0.0254 * width * kvs[:figsize][0] / mwidth),
84
+ (0.0254 * height * kvs[:figsize][1] / mheight)]
85
+ elsif dpi > 200
86
+ kvs[:size].map { |i| i * dpi / 100 }
87
+ else
88
+ kvs[:size]
89
+ end
90
+
92
91
  vp = subplot.clone
92
+
93
93
  if w > h
94
94
  ratio = h / w.to_f
95
95
  msize = mwidth * w / width
@@ -105,6 +105,7 @@ module GR
105
105
  vp[0] *= ratio
106
106
  vp[1] *= ratio
107
107
  end
108
+
108
109
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
109
110
  extent = [vp[1] - vp[0], vp[3] - vp[2]].min
110
111
  vp1 = 0.5 * (vp[0] + vp[1] - extent)
@@ -114,10 +115,12 @@ module GR
114
115
  else
115
116
  vp1, vp2, vp3, vp4 = vp
116
117
  end
117
- viewport[0] = vp1 + 0.125 * (vp2 - vp1)
118
- viewport[1] = vp1 + 0.925 * (vp2 - vp1)
119
- viewport[2] = vp3 + 0.125 * (vp4 - vp3)
120
- viewport[3] = vp3 + 0.925 * (vp4 - vp3)
118
+
119
+ viewport = [vp1 + 0.125 * (vp2 - vp1),
120
+ vp1 + 0.925 * (vp2 - vp1),
121
+ vp3 + 0.125 * (vp4 - vp3),
122
+ vp3 + 0.925 * (vp4 - vp3)]
123
+
121
124
  if %i[contour contourf hexbin heatmap nonuniformheatmap polarheatmap
122
125
  surface trisurf volume].include?(kind)
123
126
  viewport[1] -= 0.1
@@ -131,11 +134,11 @@ module GR
131
134
  end
132
135
  end
133
136
 
134
- GR.setviewport(viewport[0], viewport[1], viewport[2], viewport[3])
137
+ GR.setviewport(*viewport)
135
138
 
136
139
  kvs[:viewport] = viewport
137
- kvs[:vp] = vp
138
- kvs[:ratio] = ratio
140
+ kvs[:vp] = vp
141
+ kvs[:ratio] = ratio
139
142
 
140
143
  if kvs[:backgroundcolor]
141
144
  GR.savestate
@@ -165,14 +168,15 @@ module GR
165
168
  def set_window(kind)
166
169
  scale = 0
167
170
  unless %i[polar polarhist polarheatmap].include?(kind)
168
- scale |= GR::OPTION_X_LOG if kvs[:xlog]
169
- scale |= GR::OPTION_Y_LOG if kvs[:ylog]
170
- scale |= GR::OPTION_Z_LOG if kvs[:zlog]
171
+ scale |= GR::OPTION_X_LOG if kvs[:xlog]
172
+ scale |= GR::OPTION_Y_LOG if kvs[:ylog]
173
+ scale |= GR::OPTION_Z_LOG if kvs[:zlog]
171
174
  scale |= GR::OPTION_FLIP_X if kvs[:xflip]
172
175
  scale |= GR::OPTION_FLIP_Y if kvs[:yflip]
173
176
  scale |= GR::OPTION_FLIP_Z if kvs[:zflip]
174
177
  end
175
178
  kvs[:scale] = scale
179
+
176
180
  if kvs.has_key?(:panzoom)
177
181
  xmin, xmax, ymin, ymax = GR.panzoom(*kvs[:panzoom])
178
182
  kvs[:xrange] = [xmin, xmax]
@@ -188,65 +192,74 @@ module GR
188
192
  5
189
193
  end
190
194
 
195
+ kvs[:xticks] = [kvs[:xticks], major_count] if kvs[:xticks].is_a? Numeric
196
+ kvs[:yticks] = [kvs[:yticks], major_count] if kvs[:yticks].is_a? Numeric
197
+ kvs[:zticks] = [kvs[:zticks], major_count] if kvs[:zticks].is_a? Numeric
198
+
191
199
  xmin, xmax = kvs[:xrange]
192
- if (scale & GR::OPTION_X_LOG) == 0
193
- xmin, xmax = GR.adjustlimits(xmin, xmax) unless kvs.has_key?(:xlim) || kvs.has_key?(:panzoom)
194
- if kvs.has_key?(:xticks)
195
- xtick, majorx = kvs[:xticks]
196
- else
197
- majorx = major_count
198
- xtick = GR.tick(xmin, xmax) / majorx
199
- end
200
- else
201
- xtick = majorx = 1
200
+ if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:xlim)
201
+ xmin -= 0.5
202
+ xmax += 0.5
202
203
  end
203
- xorg = if (scale & GR::OPTION_FLIP_X) == 0
204
- [xmin, xmax]
205
- else
206
- [xmax, xmin]
207
- end
204
+ xtick, majorx = if (scale & GR::OPTION_X_LOG) == 0
205
+ unless %i[heatmap polarheatmap].include?(kind)
206
+ unless kvs.has_key?(:xlim)
207
+ xmin, xmax = GR.adjustlimits(xmin, xmax) unless kvs[:panzoom]
208
+ end
209
+ end
210
+ if kvs.has_key?(:xticks)
211
+ kvs[:xticks]
212
+ else
213
+ [GR.tick(xmin, xmax) / major_count, major_count]
214
+ end
215
+ else
216
+ [1, 1]
217
+ end
218
+ xorg = (scale & GR::OPTION_FLIP_X) == 0 ? [xmin, xmax] : [xmax, xmin]
208
219
  kvs[:xaxis] = xtick, xorg, majorx
209
220
 
210
221
  ymin, ymax = kvs[:yrange]
211
- if kind == :hist && !kvs.has_key?(:ylim)
212
- ymin = (scale & GR::OPTION_Y_LOG) == 0 ? 0 : 1
222
+ if %i[heatmap polarheatmap].include?(kind) && kvs.has_key?(:ylim)
223
+ ymin -= 0.5
224
+ ymax += 0.5
213
225
  end
214
- if (scale & GR::OPTION_Y_LOG) == 0
215
- ymin, ymax = GR.adjustlimits(ymin, ymax) unless kvs.has_key?(:ylim) || kvs.has_key?(:panzoom)
216
- if kvs.has_key?(:yticks)
217
- ytick, majory = kvs[:yticks]
218
- else
219
- majory = major_count
220
- ytick = GR.tick(ymin, ymax) / majory
226
+ if kind == :hist
227
+ if kvs[:horizontal] && !kvs.has_key?(:xlim)
228
+ xmin = (scale & GR::OPTION_X_LOG) == 0 ? 0 : 1
229
+ elsif !kvs.has_key?(:ylim)
230
+ ymin = (scale & GR::OPTION_Y_LOG) == 0 ? 0 : 1
221
231
  end
222
- else
223
- ytick = majory = 1
224
232
  end
225
- yorg = if (scale & GR::OPTION_FLIP_Y) == 0
226
- [ymin, ymax]
227
- else
228
- [ymax, ymin]
229
- end
233
+ ytick, majory = if (scale & GR::OPTION_Y_LOG) == 0
234
+ unless %i[heatmap polarheatmap].include?(kind)
235
+ unless kvs.has_key?(:ylim)
236
+ ymin, ymax = GR.adjustlimits(ymin, ymax) unless kvs[:panzoom]
237
+ end
238
+ end
239
+ if kvs.has_key?(:yticks)
240
+ kvs[:yticks]
241
+ else
242
+ [GR.tick(ymin, ymax) / major_count, major_count]
243
+ end
244
+ else
245
+ [1, 1]
246
+ end
247
+ yorg = (scale & GR::OPTION_FLIP_Y) == 0 ? [ymin, ymax] : [ymax, ymin]
230
248
  kvs[:yaxis] = ytick, yorg, majory
231
249
 
232
250
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
233
251
  zmin, zmax = kvs[:zrange]
234
- if (scale & GR::OPTION_Z_LOG) == 0
235
- zmin, zmax = GR.adjustlimits(zmin, zmax) if kvs.has_key?(:zlim)
236
- if kvs.has_key?(:zticks)
237
- ztick, majorz = kvs[:zticks]
238
- else
239
- majorz = major_count
240
- ztick = GR.tick(zmin, zmax) / majorz
241
- end
242
- else
243
- ztick = majorz = 1
244
- end
245
- zorg = if (scale & GR::OPTION_FLIP_Z) == 0
246
- [zmin, zmax]
247
- else
248
- [zmax, zmin]
249
- end
252
+ ztick, majorz = if (scale & GR::OPTION_Z_LOG) == 0
253
+ zmin, zmax = GR.adjustlimits(zmin, zmax) if kvs.has_key?(:zlim)
254
+ if kvs.has_key?(:zticks)
255
+ kvs[:zticks]
256
+ else
257
+ [GR.tick(zmin, zmax) / major_count, major_count]
258
+ end
259
+ else
260
+ [1, 1]
261
+ end
262
+ zorg = (scale & GR::OPTION_FLIP_Z) == 0 ? [zmin, zmax] : [zmax, zmin]
250
263
  kvs[:zaxis] = ztick, zorg, majorz
251
264
  end
252
265
 
@@ -258,7 +271,7 @@ module GR
258
271
  end
259
272
  if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
260
273
  rotation = kvs[:rotation] || 40
261
- tilt = kvs[:tilt] || 70
274
+ tilt = kvs[:tilt] || 70
262
275
  GR.setspace(zmin, zmax, rotation, tilt)
263
276
  end
264
277
 
@@ -272,7 +285,7 @@ module GR
272
285
  ratio = kvs[:ratio]
273
286
  xtick, xorg, majorx = kvs[:xaxis]
274
287
  ytick, yorg, majory = kvs[:yaxis]
275
- drawgrid = kvs[:grid] || true
288
+ drawgrid = kvs.has_key?(:grid) ? kvs[:grid] : true
276
289
  xtick = 10 if kvs[:scale] & GR::OPTION_X_LOG != 0
277
290
  ytick = 10 if kvs[:scale] & GR::OPTION_Y_LOG != 0
278
291
  GR.setlinecolorind(1)
@@ -293,8 +306,8 @@ module GR
293
306
  else
294
307
  if %i[heatmap nonuniformheatmap shade].include?(kind)
295
308
  ticksize = -ticksize
296
- else
297
- drawgrid && GR.grid(xtick, ytick, 0, 0, majorx, majory)
309
+ elsif drawgrid
310
+ GR.grid(xtick, ytick, 0, 0, majorx, majory)
298
311
  end
299
312
  if kvs.has_key?(:xticklabels) || kvs.has_key?(:yticklabels)
300
313
  fx = if kvs.has_key?(:xticklabels)
@@ -332,7 +345,7 @@ module GR
332
345
  GR.axes(xtick, ytick, xorg[1], yorg[1], -majorx, -majory, -ticksize)
333
346
  end
334
347
 
335
- if kvs.has_key?(:title)
348
+ if kvs[:title]
336
349
  GR.savestate
337
350
  GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
338
351
  text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title])
@@ -564,7 +577,9 @@ module GR
564
577
  # Not yet.
565
578
  end
566
579
 
567
- GR.settextfontprec(232, 3)
580
+ # The following fonts are the default in GR.jl
581
+ # Japanese, Chinese, Korean, etc. cannot be displayed.
582
+ # GR.settextfontprec(232, 3) # CM Serif Roman
568
583
 
569
584
  set_viewport(kind, kvs[:subplot])
570
585
  unless kvs[:ax]
@@ -632,8 +647,7 @@ module GR
632
647
  if z || c
633
648
  if c
634
649
  cmin, cmax = kvs[:crange]
635
- c = c.to_a if narray?(c)
636
- c.map! { |i| normalize_color(i, cmin, cmax) }
650
+ c = c.map { |i| normalize_color(i, cmin, cmax) }
637
651
  cind = c.map { |i| (1000 + i * 255).round }
638
652
  end
639
653
  x.length.times do |i|
@@ -658,14 +672,26 @@ module GR
658
672
  GR.polymarker(x, y)
659
673
 
660
674
  when :hist
661
- ymin = kvs[:window][2]
662
- y.length.times do |i|
663
- GR.setfillcolorind(989)
664
- GR.setfillintstyle(GR::INTSTYLE_SOLID)
665
- GR.fillrect(x[i], x[i + 1], ymin, y[i])
666
- GR.setfillcolorind(1)
667
- GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
668
- GR.fillrect(x[i], x[i + 1], ymin, y[i])
675
+ if kvs[:horizontal]
676
+ xmin = kvs[:window][0]
677
+ x.length.times do |i|
678
+ GR.setfillcolorind(989)
679
+ GR.setfillintstyle(GR::INTSTYLE_SOLID)
680
+ GR.fillrect(xmin, x[i], y[i], y[i + 1])
681
+ GR.setfillcolorind(1)
682
+ GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
683
+ GR.fillrect(xmin, x[i], y[i], y[i + 1])
684
+ end
685
+ else
686
+ ymin = kvs[:window][2]
687
+ y.length.times do |i|
688
+ GR.setfillcolorind(989)
689
+ GR.setfillintstyle(GR::INTSTYLE_SOLID)
690
+ GR.fillrect(x[i], x[i + 1], ymin, y[i])
691
+ GR.setfillcolorind(1)
692
+ GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
693
+ GR.fillrect(x[i], x[i + 1], ymin, y[i])
694
+ end
669
695
  end
670
696
 
671
697
  when :polarhist
@@ -686,9 +712,10 @@ module GR
686
712
  cmap = colormap
687
713
  cmin, cmax = kvs[:zrange]
688
714
  data = z.map { |i| normalize_color(i, cmin, cmax) }
689
- colors = data.map { |i| 1000 + i * 255 }
690
- # if kvs[:xflip]
691
- # if kvs[;yflip]
715
+ data.reverse(axis: 0) if kvs[:xflip]
716
+ data.reverse(axis: 1) if kvs[:yflip]
717
+ colors = data * 255 + 1000
718
+ colors = colors.transpose # Julia is column major
692
719
  GR.polarcellarray(0, 0, 0, 360, 0, 1, w, h, colors)
693
720
  draw_polar_axes
694
721
  kvs[:zrange] = [cmin, cmax]
@@ -700,11 +727,18 @@ module GR
700
727
  a, b = z.shape
701
728
  x = (1..b).to_a
702
729
  y = (1..a).to_a
703
- zmin, zmax = kvs[:zlim] || z.minmax
730
+ zmin, zmax = z.minmax
704
731
  elsif equal_length(x, y, z)
705
732
  x, y, z = GR.gridit(x, y, z, 200, 200)
706
- zmin, zmax = kvs[:zlim] || z.compact.minmax # compact : removed nil
733
+ zmin, zmax = z.compact.minmax # compact : removed nil
734
+ end
735
+
736
+ # kvs[:zlim] is supposed to be Array or Range
737
+ if kvs.has_key?(:zlim)
738
+ zmin = kvs[:zlim].first if kvs[:zlim].first
739
+ zmax = kvs[:zlim].last if kvs[:zlim].last
707
740
  end
741
+
708
742
  GR.setspace(zmin, zmax, 0, 90)
709
743
  levels = kvs[:levels] || 0
710
744
  clabels = kvs[:clabels] || false
@@ -805,7 +839,7 @@ module GR
805
839
  GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
806
840
  if c
807
841
  cmin, cmax = kvs[:crange]
808
- c = c.map { |i| normalize_color(i, cmin, cmax) } # NArray -> Array
842
+ c = c.map { |i| normalize_color(i, cmin, cmax) }
809
843
  cind = c.map { |i| (1000 + i * 255).round }
810
844
  x.length.times do |i|
811
845
  GR.setmarkercolorind(cind[i])
@@ -1011,7 +1045,9 @@ module GR
1011
1045
 
1012
1046
  # Normalize a color c with the range [cmin, cmax]
1013
1047
  # 0 <= normalize_color(c, cmin, cmax) <= 1
1048
+ # Note: narray.map{|i| normalize_color(i)} There's room for speedup.
1014
1049
  def normalize_color(c, cmin, cmax)
1050
+ c = c.to_f # if c is Integer
1015
1051
  c = c.clamp(cmin, cmax) - cmin
1016
1052
  c /= (cmax - cmin) if cmin != cmax
1017
1053
  c
@@ -1052,7 +1088,8 @@ module GR
1052
1088
  args.each do |x, y, z, c|
1053
1089
  if x
1054
1090
  if scale & GR::OPTION_X_LOG != 0
1055
- x.map! { |v| v > 0 ? v : Float::NAN }
1091
+ # duck typing for NArray
1092
+ x = x.map { |v| v > 0 ? v : Float::NAN }
1056
1093
  end
1057
1094
  x0, x1 = x.minmax
1058
1095
  xmin = [x0, xmin].min
@@ -1063,7 +1100,7 @@ module GR
1063
1100
  end
1064
1101
  if y
1065
1102
  if scale & GR::OPTION_Y_LOG != 0
1066
- y.map! { |v| v > 0 ? v : Float::NAN }
1103
+ y = y.map { |v| v > 0 ? v : Float::NAN }
1067
1104
  end
1068
1105
  y0, y1 = y.minmax
1069
1106
  ymin = [y0, ymin].min
@@ -1074,7 +1111,7 @@ module GR
1074
1111
  end
1075
1112
  if z
1076
1113
  if scale & GR::OPTION_Z_LOG != 0
1077
- z.map! { |v| v > 0 ? v : Float::NAN }
1114
+ z = z.map { |v| v > 0 ? v : Float::NAN }
1078
1115
  end
1079
1116
  z0, z1 = z.minmax
1080
1117
  zmin = [z0, zmin].min
@@ -1093,30 +1130,12 @@ module GR
1093
1130
  xmin, xmax = fix_minmax(xmin, xmax)
1094
1131
  ymin, ymax = fix_minmax(ymin, ymax)
1095
1132
  zmin, zmax = fix_minmax(zmin, zmax)
1096
- if kvs.has_key?(:xlim)
1097
- x0, x1 = kvs[:xlim]
1098
- x0 ||= xmin
1099
- x1 ||= xmax
1100
- kvs[:xrange] = [x0, x1]
1101
- else
1102
- kvs[:xrange] = [xmin, xmax]
1103
- end
1104
- if kvs.has_key?(:ylim)
1105
- y0, y1 = kvs[:ylim]
1106
- y0 ||= ymin
1107
- y1 ||= ymax
1108
- kvs[:yrange] = [y0, y1]
1109
- else
1110
- kvs[:yrange] = [ymin, ymax]
1111
- end
1112
- if kvs.has_key?(:zlim)
1113
- z0, z1 = kvs[:zlim]
1114
- z0 ||= zmin
1115
- z1 ||= zmax
1116
- kvs[:zrange] = [z0, z1]
1117
- else
1118
- kvs[:zrange] = [zmin, zmax]
1119
- end
1133
+
1134
+ # kvs[:xlim], kvs[:ylim], kvs[:zlim] is supposed to be Array or Range
1135
+ kvs[:xrange] = [(kvs[:xlim]&.first || xmin), (kvs[:xlim]&.last || xmax)]
1136
+ kvs[:yrange] = [(kvs[:ylim]&.first || ymin), (kvs[:ylim]&.last || ymax)]
1137
+ kvs[:zrange] = [(kvs[:zlim]&.first || zmin), (kvs[:zlim]&.last || zmax)]
1138
+
1120
1139
  if kvs.has_key?(:clim)
1121
1140
  c0, c1 = kvs[:clim]
1122
1141
  c0 ||= cmin
@@ -1292,9 +1311,8 @@ module GR
1292
1311
  def barplot(labels, heights, kv = {})
1293
1312
  labels = labels.map(&:to_s)
1294
1313
  wc, hc = barcoordinates(heights)
1295
- horizontal = kv[:horizontal] || false
1296
1314
  create_plot(:bar, labels, heights, kv) do |plt|
1297
- if horizontal
1315
+ if kv[:horizontal]
1298
1316
  plt.args = [[hc, wc, nil, nil, '']]
1299
1317
  plt.kvs[:yticks] = [1, 1]
1300
1318
  plt.kvs[:yticklabels] = labels
@@ -1307,11 +1325,15 @@ module GR
1307
1325
  end
1308
1326
 
1309
1327
  # (Plot) Draw a histogram.
1310
- def histogram(x, kv = {})
1311
- create_plot(:hist, x, kv) do |plt|
1328
+ def histogram(series, kv = {})
1329
+ create_plot(:hist, series, kv) do |plt|
1312
1330
  nbins = plt.kvs[:nbins] || 0
1313
- x, y = hist(x, nbins)
1314
- plt.args = [[x, y, nil, nil, '']]
1331
+ x, y = hist(series, nbins)
1332
+ plt.args = if kv[:horizontal]
1333
+ [[y, x, nil, nil, '']]
1334
+ else
1335
+ [[x, y, nil, nil, '']]
1336
+ end
1315
1337
  end
1316
1338
  end
1317
1339
 
@@ -1337,7 +1359,7 @@ module GR
1337
1359
  end
1338
1360
 
1339
1361
  # Set current subplot index.
1340
- def subplot(nr, nc, p)
1362
+ def subplot(nr, nc, p, kv = {})
1341
1363
  xmin = 1
1342
1364
  xmax = 0
1343
1365
  ymin = 1
@@ -1353,9 +1375,10 @@ module GR
1353
1375
  end
1354
1376
  {
1355
1377
  subplot: [xmin, xmax, ymin, ymax],
1378
+ # The policy of clearing when p[0]==1 is controversial
1356
1379
  clear: p[0] == 1,
1357
1380
  update: p[-1] == nr * nc
1358
- }
1381
+ }.merge kv
1359
1382
  end
1360
1383
 
1361
1384
  # (Plot) Save the current figure to a file.