ruby-gr 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -0
- data/README.md +12 -10
- data/lib/gr.rb +339 -292
- data/lib/gr/ffi.rb +188 -180
- data/lib/gr/grbase.rb +1 -0
- data/lib/gr/plot.rb +1344 -0
- data/lib/gr/plot.rb.md +207 -0
- data/lib/gr3.rb +99 -81
- data/lib/gr3/ffi.rb +114 -78
- data/lib/gr3/gr3base.rb +5 -0
- data/lib/gr_commons.rb +1 -1
- data/lib/gr_commons/define_methods.rb +3 -1
- data/lib/gr_commons/extern.rb +16 -0
- data/lib/gr_commons/fiddley.rb +419 -0
- data/lib/gr_commons/gr_common_utils.rb +19 -48
- data/lib/gr_commons/jupyter_support.rb +5 -2
- data/lib/gr_commons/version.rb +1 -1
- metadata +37 -20
- data/lib/gr_commons/attach_function.rb +0 -15
data/lib/gr/ffi.rb
CHANGED
@@ -1,198 +1,206 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'fiddle/import'
|
4
4
|
|
5
5
|
module GR
|
6
6
|
# FFI Wrapper module for GR
|
7
7
|
module FFI
|
8
|
-
extend ::
|
8
|
+
extend Fiddle::Importer
|
9
9
|
|
10
10
|
begin
|
11
|
-
|
11
|
+
dlload GR.ffi_lib
|
12
12
|
rescue LoadError
|
13
13
|
raise LoadError, 'Could not find GR Framework'
|
14
14
|
end
|
15
15
|
|
16
|
-
extend GRCommons::
|
16
|
+
extend GRCommons::Extern
|
17
17
|
|
18
18
|
# https://github.com/sciapp/gr/blob/master/lib/gr/gr.h
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
20
|
+
extern 'void gr_initgr(void)'
|
21
|
+
extern 'void gr_opengks(void)'
|
22
|
+
extern 'void gr_closegks(void)'
|
23
|
+
extern 'void gr_inqdspsize(double *, double *, int *, int *)'
|
24
|
+
extern 'void gr_openws(int, char *, int)'
|
25
|
+
extern 'void gr_closews(int)'
|
26
|
+
extern 'void gr_activatews(int)'
|
27
|
+
extern 'void gr_deactivatews(int)'
|
28
|
+
extern 'void gr_configurews(void)'
|
29
|
+
extern 'void gr_clearws(void)'
|
30
|
+
extern 'void gr_updatews(void)'
|
31
|
+
extern 'void gr_polyline(int, double *, double *)'
|
32
|
+
extern 'void gr_polymarker(int, double *, double *)'
|
33
|
+
extern 'void gr_text(double, double, char *)'
|
34
|
+
extern 'void gr_inqtext(double, double, char *, double *, double *)'
|
35
|
+
extern 'void gr_fillarea(int, double *, double *)'
|
36
|
+
extern 'void gr_cellarray(double, double, double, double, ' \
|
37
|
+
'int, int, int, int, int, int, int *)'
|
38
|
+
extern 'void gr_nonuniformcellarray(double *, double *, ' \
|
39
|
+
'int, int, int, int, int, int, int *)'
|
40
|
+
extern 'void gr_polarcellarray(double, double, double, double, double, double, ' \
|
41
|
+
'int, int, int, int, int, int, int *)'
|
42
|
+
extern 'void gr_gdp(int, double *, double *, int, int, int *)'
|
43
|
+
extern 'void gr_spline(int, double *, double *, int, int)'
|
44
|
+
extern 'void gr_gridit(int, double *, double *, double *, int, int, ' \
|
45
|
+
'double *, double *, double *)'
|
46
|
+
extern 'void gr_setlinetype(int)'
|
47
|
+
extern 'void gr_inqlinetype(int *)'
|
48
|
+
extern 'void gr_setlinewidth(double)'
|
49
|
+
extern 'void gr_inqlinewidth(double *)'
|
50
|
+
extern 'void gr_setlinecolorind(int)'
|
51
|
+
extern 'void gr_inqlinecolorind(int *)'
|
52
|
+
extern 'void gr_setmarkertype(int)'
|
53
|
+
extern 'void gr_inqmarkertype(int *)'
|
54
|
+
extern 'void gr_setmarkersize(double)'
|
55
|
+
extern 'void gr_inqmarkersize(double *)'
|
56
|
+
extern 'void gr_setmarkercolorind(int)'
|
57
|
+
extern 'void gr_inqmarkercolorind(int *)'
|
58
|
+
extern 'void gr_settextfontprec(int, int)'
|
59
|
+
extern 'void gr_setcharexpan(double)'
|
60
|
+
extern 'void gr_setcharspace(double)'
|
61
|
+
extern 'void gr_settextcolorind(int)'
|
62
|
+
extern 'void gr_setcharheight(double)'
|
63
|
+
extern 'void gr_setcharup(double, double)'
|
64
|
+
extern 'void gr_settextpath(int)'
|
65
|
+
extern 'void gr_settextalign(int, int)'
|
66
|
+
extern 'void gr_setfillintstyle(int)'
|
67
|
+
extern 'void gr_inqfillintstyle(int *)'
|
68
|
+
extern 'void gr_setfillstyle(int)'
|
69
|
+
extern 'void gr_inqfillstyle(int *)'
|
70
|
+
extern 'void gr_setfillcolorind(int)'
|
71
|
+
extern 'void gr_inqfillcolorind(int *)'
|
72
|
+
extern 'void gr_setcolorrep(int, double, double, double)'
|
73
|
+
extern 'void gr_setwindow(double, double, double, double)'
|
74
|
+
extern 'void gr_inqwindow(double *, double *, double *, double *)'
|
75
|
+
extern 'void gr_setviewport(double, double, double, double)'
|
76
|
+
extern 'void gr_inqviewport(double *, double *, double *, double *)'
|
77
|
+
extern 'void gr_selntran(int)'
|
78
|
+
extern 'void gr_setclip(int)'
|
79
|
+
extern 'void gr_setwswindow(double, double, double, double)'
|
80
|
+
extern 'void gr_setwsviewport(double, double, double, double)'
|
81
|
+
extern 'void gr_createseg(int)'
|
82
|
+
extern 'void gr_copysegws(int)'
|
83
|
+
extern 'void gr_redrawsegws(void)'
|
84
|
+
extern 'void gr_setsegtran(int, double, double, double, double, double, double, double)'
|
85
|
+
extern 'void gr_closeseg(void)'
|
86
|
+
extern 'void gr_emergencyclosegks(void)'
|
87
|
+
extern 'void gr_updategks(void)'
|
88
|
+
extern 'int gr_setspace(double, double, int, int)'
|
89
|
+
extern 'void gr_inqspace(double *, double *, int *, int *)'
|
90
|
+
extern 'int gr_setscale(int)'
|
91
|
+
extern 'void gr_inqscale(int *)'
|
92
|
+
extern 'int gr_textext(double, double, char *)'
|
93
|
+
extern 'void gr_inqtextext(double, double, char *, double *, double *)'
|
94
|
+
extern 'void gr_axes(double, double, double, double, int, int, double)'
|
95
|
+
extern 'void gr_axeslbl(double, double, double, double, int, int, double,' \
|
96
|
+
'void (*)(double, double, const char *, double),' \
|
97
|
+
'void (*)(double, double, const char *, double))'
|
98
|
+
extern 'void gr_grid(double, double, double, double, int, int)'
|
99
|
+
extern 'void gr_grid3d(double, double, double, double, double, double, int, int, int)'
|
100
|
+
extern 'void gr_verrorbars(int, double *, double *, double *, double *)'
|
101
|
+
extern 'void gr_herrorbars(int, double *, double *, double *, double *)'
|
102
|
+
extern 'void gr_polyline3d(int, double *, double *, double *)'
|
103
|
+
extern 'void gr_polymarker3d(int, double *, double *, double *)'
|
104
|
+
extern 'void gr_axes3d(double, double, double, double, double, double, int, int, int, double)'
|
105
|
+
extern 'void gr_titles3d(char *, char *, char *)'
|
106
|
+
extern 'void gr_surface(int, int, double *, double *, double *, int)'
|
107
|
+
extern 'void gr_contour(int, int, int, double *, double *, double *, double *, int)'
|
108
|
+
extern 'void gr_contourf(int, int, int, double *, double *, double *, double *, int)'
|
109
|
+
extern 'void gr_tricontour(int, double *, double *, double *, int, double *)'
|
110
|
+
extern 'int gr_hexbin(int, double *, double *, int)'
|
111
|
+
extern 'void gr_setcolormap(int)'
|
112
|
+
extern 'void gr_inqcolormap(int *)'
|
113
|
+
extern 'void gr_setcolormapfromrgb(int n, double *r, double *g, double *b, double *x)'
|
114
|
+
extern 'void gr_colorbar(void)'
|
115
|
+
extern 'void gr_inqcolor(int, int *)'
|
116
|
+
extern 'int gr_inqcolorfromrgb(double, double, double)'
|
117
|
+
extern 'void gr_hsvtorgb(double h, double s, double v, double *r, double *g, double *b)'
|
118
|
+
extern 'double gr_tick(double, double)'
|
119
|
+
extern 'int gr_validaterange(double, double)'
|
120
|
+
extern 'void gr_adjustlimits(double *, double *)'
|
121
|
+
extern 'void gr_adjustrange(double *, double *)'
|
122
|
+
extern 'void gr_beginprint(char *)'
|
123
|
+
extern 'void gr_beginprintext(char *, char *, char *, char *)'
|
124
|
+
extern 'void gr_endprint(void)'
|
125
|
+
extern 'void gr_ndctowc(double *, double *)'
|
126
|
+
extern 'void gr_wctondc(double *, double *)'
|
127
|
+
extern 'void gr_wc3towc(double *, double *, double *)'
|
128
|
+
extern 'void gr_drawrect(double, double, double, double)'
|
129
|
+
extern 'void gr_fillrect(double, double, double, double)'
|
130
|
+
extern 'void gr_drawarc(double, double, double, double, double, double)'
|
131
|
+
extern 'void gr_fillarc(double, double, double, double, double, double)'
|
132
|
+
extern 'void gr_drawpath(int, vertex_t *, unsigned char *, int)'
|
133
|
+
extern 'void gr_setarrowstyle(int)'
|
134
|
+
extern 'void gr_setarrowsize(double)'
|
135
|
+
extern 'void gr_drawarrow(double, double, double, double)'
|
136
|
+
extern 'int gr_readimage(char *, int *, int *, int **)'
|
137
|
+
extern 'void gr_drawimage(double, double, double, double, int, int, int *, int)'
|
138
|
+
extern 'int gr_importgraphics(char *)'
|
139
|
+
extern 'void gr_setshadow(double, double, double)'
|
140
|
+
extern 'void gr_settransparency(double)'
|
141
|
+
extern 'void gr_setcoordxform(double[3][2])'
|
142
|
+
extern 'void gr_begingraphics(char *)'
|
143
|
+
extern 'void gr_endgraphics(void)'
|
144
|
+
extern 'char *gr_getgraphics(void)'
|
145
|
+
extern 'int gr_drawgraphics(char *)'
|
146
|
+
extern 'void gr_mathtex(double, double, char *)'
|
147
|
+
extern 'void gr_inqmathtex(double, double, char *, double *, double *)'
|
148
|
+
extern 'void gr_beginselection(int, int)'
|
149
|
+
extern 'void gr_endselection(void)'
|
150
|
+
extern 'void gr_moveselection(double, double)'
|
151
|
+
extern 'void gr_resizeselection(int, double, double)'
|
152
|
+
extern 'void gr_inqbbox(double *, double *, double *, double *)'
|
153
|
+
extern 'double gr_precision(void)'
|
154
|
+
extern 'void gr_setregenflags(int)'
|
155
|
+
extern 'int gr_inqregenflags(void)'
|
156
|
+
extern 'void gr_savestate(void)'
|
157
|
+
extern 'void gr_restorestate(void)'
|
158
|
+
extern 'void gr_selectcontext(int)'
|
159
|
+
extern 'void gr_destroycontext(int)'
|
160
|
+
extern 'int gr_uselinespec(char *)'
|
161
|
+
# extern 'void gr_delaunay(int, const double *, const double *, int *, int **)'
|
162
|
+
extern 'void gr_reducepoints(int, const double *, const double *, int, double *, double *)'
|
163
|
+
extern 'void gr_trisurface(int, double *, double *, double *)'
|
164
|
+
extern 'void gr_gradient(int, int, double *, double *, double *, double *, double *)'
|
165
|
+
extern 'void gr_quiver(int, int, double *, double *, double *, double *, int)'
|
166
|
+
extern 'void gr_interp2(int nx, int ny, const double *x, const double *y, const double *z,' \
|
167
|
+
'int nxq, int nyq, const double *xq, const double *yq, double *zq, int method, double extrapval)'
|
168
|
+
# extern :gr_newmeta
|
169
|
+
# extern :gr_deletemeta
|
170
|
+
# extern :gr_finalizemeta
|
171
|
+
# extern :gr_meta_args_push
|
172
|
+
# extern :gr_meta_args_push_buf
|
173
|
+
# extern :gr_meta_args_contains
|
174
|
+
# extern :gr_meta_args_clear
|
175
|
+
# extern :gr_meta_args_remove
|
176
|
+
# extern :gr_meta_get_box
|
177
|
+
# extern :gr_openmeta
|
178
|
+
# extern :gr_recvmeta
|
179
|
+
# extern :gr_sendmeta
|
180
|
+
# extern :gr_sendmeta_buf
|
181
|
+
# extern :gr_sendmeta_ref
|
182
|
+
# extern :gr_sendmeta_args
|
183
|
+
# extern :gr_closemeta
|
184
|
+
# extern :gr_clearmeta
|
185
|
+
# extern :gr_inputmeta
|
186
|
+
# extern :gr_mergemeta
|
187
|
+
# extern :gr_plotmeta
|
188
|
+
# extern :gr_readmeta
|
189
|
+
# extern :gr_switchmeta
|
190
|
+
# extern :gr_registermeta
|
191
|
+
# extern :gr_unregistermeta
|
192
|
+
# extern :gr_meta_max_plotid
|
193
|
+
# extern :gr_dumpmeta
|
194
|
+
# extern :gr_dumpmeta_json
|
161
195
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
#
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
# attach_function :gr_openmeta
|
172
|
-
# attach_function :gr_recvmeta
|
173
|
-
# attach_function :gr_sendmeta
|
174
|
-
# attach_function :gr_sendmeta_buf
|
175
|
-
# attach_function :gr_sendmeta_ref
|
176
|
-
# attach_function :gr_sendmeta_args
|
177
|
-
# attach_function :gr_closemeta
|
178
|
-
# attach_function :gr_clearmeta
|
179
|
-
# attach_function :gr_inputmeta
|
180
|
-
# attach_function :gr_mergemeta
|
181
|
-
# attach_function :gr_plotmeta
|
182
|
-
# attach_function :gr_readmeta
|
183
|
-
# attach_function :gr_switchmeta
|
184
|
-
# attach_function :gr_registermeta
|
185
|
-
# attach_function :gr_unregistermeta
|
186
|
-
# attach_function :gr_meta_max_plotid
|
187
|
-
# attach_function :gr_dumpmeta
|
188
|
-
# attach_function :gr_dumpmeta_json
|
189
|
-
|
190
|
-
attach_function :gr_version, %i[], :pointer
|
191
|
-
attach_function :gr_shadepoints, %i[int pointer pointer int int int], :void
|
192
|
-
attach_function :gr_shadelines, %i[int pointer pointer int int int], :void
|
193
|
-
attach_function :gr_panzoom, %i[double double double double pointer pointer pointer pointer], :void
|
194
|
-
# attach_function :gr_findboundary
|
195
|
-
attach_function :gr_setresamplemethod, %i[uint], :void
|
196
|
-
attach_function :gr_inqresamplemethod, %i[pointer], :void
|
196
|
+
extern 'const char *gr_version(void)'
|
197
|
+
extern 'void gr_shade(int, double *, double *, int, int, double *, int, int, int *)'
|
198
|
+
extern 'void gr_shadepoints(int, double *, double *, int, int, int)'
|
199
|
+
extern 'void gr_shadelines(int, double *, double *, int, int, int)'
|
200
|
+
extern 'void gr_panzoom(double, double, double, double, double *, double *, double *, double *)'
|
201
|
+
# extern 'int gr_findboundary(int, double *, double *, double, double (*)(double, double), int, int *)'
|
202
|
+
extern 'void gr_setresamplemethod(unsigned int flag)'
|
203
|
+
extern 'void gr_inqresamplemethod(unsigned int *flag)'
|
204
|
+
extern 'void gr_path(int, double *, double *, char *)'
|
197
205
|
end
|
198
206
|
end
|
data/lib/gr/grbase.rb
CHANGED
data/lib/gr/plot.rb
ADDED
@@ -0,0 +1,1344 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gr'
|
4
|
+
autoload :GR3, 'gr3'
|
5
|
+
|
6
|
+
# FIXME: Plot should not depend on Numo::Narrray unless the GR3 module is required.
|
7
|
+
require 'numo/narray'
|
8
|
+
|
9
|
+
module GR
|
10
|
+
class Plot # should be Figure ?
|
11
|
+
# Why is the Plot class NOT object-oriented?
|
12
|
+
#
|
13
|
+
# Because the code here is mainly ported from GR.jl.
|
14
|
+
# https://github.com/jheinen/GR.jl/blob/master/src/jlgr.jl
|
15
|
+
#
|
16
|
+
# The Python implementation is also Julia compliant.
|
17
|
+
# https://github.com/sciapp/python-gr
|
18
|
+
#
|
19
|
+
# Julia is not an object-oriented language (at least in 2019).
|
20
|
+
# So, you will see many if branches here.
|
21
|
+
# This is not the Ruby code style. But it WORKS.
|
22
|
+
#
|
23
|
+
# I want to thank the Josef Heinen(@jheinen), the creator of GR.jl
|
24
|
+
# and Florian Rhiem(@FlorianRhiem), the creator of python-gr.
|
25
|
+
#
|
26
|
+
# If you are interested in an object-oriented implementation,
|
27
|
+
# See rubyplot.
|
28
|
+
# https://github.com/SciRuby/rubyplot
|
29
|
+
|
30
|
+
# Plot kinds conform to GR.jl
|
31
|
+
PLOT_KIND = %i[line step scatter stem hist contour contourf hexbin heatmap
|
32
|
+
nonuniformheatmap wireframe surface plot3 scatter3 imshow
|
33
|
+
isosurface polar polarhist polarheatmap trisurf tricont shade
|
34
|
+
volume].freeze # the name might be changed in the future.
|
35
|
+
|
36
|
+
# Keyword options conform to GR.jl.
|
37
|
+
KW_ARGS = %i[accelerate algorithm alpha backgroundcolor barwidth baseline
|
38
|
+
clabels color colormap figsize isovalue labels levels location
|
39
|
+
nbins rotation size tilt title where xflip xform xlabel xlim
|
40
|
+
xlog yflip ylabel ylim ylog zflip zlabel zlim zlog clim
|
41
|
+
subplot].freeze
|
42
|
+
|
43
|
+
def initialize(*args)
|
44
|
+
@kvs = if args[-1].is_a? Hash
|
45
|
+
args.pop
|
46
|
+
else
|
47
|
+
{}
|
48
|
+
end
|
49
|
+
@args = plot_args(args) # method name is the same as Julia/Python
|
50
|
+
@kvs[:size] ||= [600, 450]
|
51
|
+
@kvs[:ax] ||= false
|
52
|
+
@kvs[:subplot] ||= [0, 1, 0, 1]
|
53
|
+
@kvs[:clear] ||= true
|
54
|
+
@kvs[:update] ||= true
|
55
|
+
@scheme = 0
|
56
|
+
@background = 0xffffff
|
57
|
+
@handle = nil
|
58
|
+
end
|
59
|
+
attr_accessor :args, :kvs, :scheme
|
60
|
+
|
61
|
+
def set_viewport(kind, subplot)
|
62
|
+
mwidth, mheight, width, height = GR.inqdspsize
|
63
|
+
if kvs[:figsize]
|
64
|
+
w = 0.0254 * width * kvs[:figsize][0] / mwidth
|
65
|
+
h = 0.0254 * height * kvs[:figsize][1] / mheight
|
66
|
+
else
|
67
|
+
dpi = width / mwidth * 0.0254
|
68
|
+
if dpi > 200
|
69
|
+
w, h = kvs[:size].map { |x| x * dpi / 100 }
|
70
|
+
else
|
71
|
+
w, h = kvs[:size]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
viewport = [0, 0, 0, 0]
|
75
|
+
vp = subplot.clone
|
76
|
+
if w > h
|
77
|
+
ratio = h / w.to_f
|
78
|
+
msize = mwidth * w / width
|
79
|
+
GR.setwsviewport(0, msize, 0, msize * ratio)
|
80
|
+
GR.setwswindow(0, 1, 0, ratio)
|
81
|
+
vp[2] *= ratio
|
82
|
+
vp[3] *= ratio
|
83
|
+
else
|
84
|
+
ratio = w / h.to_f
|
85
|
+
msize = mheight * h / height
|
86
|
+
GR.setwsviewport(0, msize * ratio, 0, msize)
|
87
|
+
GR.setwswindow(0, ratio, 0, 1)
|
88
|
+
vp[0] *= ratio
|
89
|
+
vp[1] *= ratio
|
90
|
+
end
|
91
|
+
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
92
|
+
extent = [vp[1] - vp[0], vp[3] - vp[2]].min
|
93
|
+
vp1 = 0.5 * (vp[0] + vp[1] - extent)
|
94
|
+
vp2 = 0.5 * (vp[0] + vp[1] + extent)
|
95
|
+
vp3 = 0.5 * (vp[2] + vp[3] - extent)
|
96
|
+
vp4 = 0.5 * (vp[2] + vp[3] + extent)
|
97
|
+
else
|
98
|
+
vp1, vp2, vp3, vp4 = vp
|
99
|
+
end
|
100
|
+
viewport[0] = vp1 + 0.125 * (vp2 - vp1)
|
101
|
+
viewport[1] = vp1 + 0.925 * (vp2 - vp1)
|
102
|
+
viewport[2] = vp3 + 0.125 * (vp4 - vp3)
|
103
|
+
viewport[3] = vp3 + 0.925 * (vp4 - vp3)
|
104
|
+
if %i[contour contourf hexbin heatmap nonuniformheatmap polarheatmap
|
105
|
+
surface trisurf volume].include?(kind)
|
106
|
+
viewport[1] -= 0.1
|
107
|
+
end
|
108
|
+
|
109
|
+
if %i[line step scatter stem].include?(kind) && kvs[:labels]
|
110
|
+
location = kvs[:location] || 1
|
111
|
+
if [11, 12, 13].include?(location)
|
112
|
+
w, h = legend_size
|
113
|
+
viewport[1] -= w + 0.1
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
GR.setviewport(viewport[0], viewport[1], viewport[2], viewport[3])
|
118
|
+
|
119
|
+
kvs[:viewport] = viewport
|
120
|
+
kvs[:vp] = vp
|
121
|
+
kvs[:ratio] = ratio
|
122
|
+
|
123
|
+
if kvs[:backgroundcolor]
|
124
|
+
GR.savestate
|
125
|
+
GR.selntran(0)
|
126
|
+
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
127
|
+
GR.setfillcolorind(kvs[:backgroundcolor])
|
128
|
+
if w > h
|
129
|
+
GR.fillrect(subplot[0], subplot[1],
|
130
|
+
ratio * subplot[2], ratio * subplot[3])
|
131
|
+
else
|
132
|
+
GR.fillrect(ratio * subplot[0], ratio * subplot[1],
|
133
|
+
subplot[2], subplot[3])
|
134
|
+
end
|
135
|
+
GR.selntran(1)
|
136
|
+
GR.restorestate
|
137
|
+
end
|
138
|
+
|
139
|
+
if %i[polar polarhist polarheatmap].include? kind
|
140
|
+
xmin, xmax, ymin, ymax = viewport
|
141
|
+
xcenter = 0.5 * (xmin + xmax)
|
142
|
+
ycenter = 0.5 * (ymin + ymax)
|
143
|
+
r = 0.5 * [xmax - xmin, ymax - ymin].min
|
144
|
+
GR.setviewport(xcenter - r, xcenter + r, ycenter - r, ycenter + r)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def set_window(kind)
|
149
|
+
scale = 0
|
150
|
+
unless %i[polar polarhist polarheatmap].include?(kind)
|
151
|
+
scale |= GR::OPTION_X_LOG if kvs[:xlog]
|
152
|
+
scale |= GR::OPTION_Y_LOG if kvs[:ylog]
|
153
|
+
scale |= GR::OPTION_Z_LOG if kvs[:zlog]
|
154
|
+
scale |= GR::OPTION_FLIP_X if kvs[:xflip]
|
155
|
+
scale |= GR::OPTION_FLIP_Y if kvs[:yflip]
|
156
|
+
scale |= GR::OPTION_FLIP_Z if kvs[:zflip]
|
157
|
+
end
|
158
|
+
if kvs.key?(:panzoom)
|
159
|
+
xmin, xmax, ymin, ymax = GR.panzoom(*kvs[:panzoom])
|
160
|
+
kvs[:xrange] = [xmin, xmax]
|
161
|
+
kvs[:yrange] = [ymin, ymax]
|
162
|
+
else
|
163
|
+
minmax
|
164
|
+
end
|
165
|
+
|
166
|
+
major_count = if %i[wireframe surface plot3 scatter3 polar polarhist
|
167
|
+
polarheatmap trisurf volume].include?(kind)
|
168
|
+
2
|
169
|
+
else
|
170
|
+
5
|
171
|
+
end
|
172
|
+
|
173
|
+
xmin, xmax = kvs[:xrange]
|
174
|
+
if (scale & GR::OPTION_X_LOG) == 0
|
175
|
+
xmin, xmax = GR.adjustlimits(xmin, xmax) unless kvs.key?(:xlim) || kvs.key?(:panzoom)
|
176
|
+
if kvs.key?(:xticks)
|
177
|
+
xtick, majorx = kvs[:xticks]
|
178
|
+
else
|
179
|
+
majorx = major_count
|
180
|
+
xtick = GR.tick(xmin, xmax) / majorx
|
181
|
+
end
|
182
|
+
else
|
183
|
+
xtick = majorx = 1
|
184
|
+
end
|
185
|
+
xorg = if (scale & GR::OPTION_FLIP_X) == 0
|
186
|
+
[xmin, xmax]
|
187
|
+
else
|
188
|
+
[xmax, xmin]
|
189
|
+
end
|
190
|
+
kvs[:xaxis] = xtick, xorg, majorx
|
191
|
+
|
192
|
+
ymin, ymax = kvs[:yrange]
|
193
|
+
if kind == :hist && kvs.key?(:ylim)
|
194
|
+
ymin = (scale & GR::OPTION_Y_LOG) == 0 ? 0 : 1
|
195
|
+
end
|
196
|
+
if (scale & GR::OPTION_Y_LOG) == 0
|
197
|
+
ymin, ymax = GR.adjustlimits(ymin, ymax) unless kvs.key?(:ylim) || kvs.key?(:panzoom)
|
198
|
+
if kvs.key?(:yticks)
|
199
|
+
ytick, majory = kvs[:yticks]
|
200
|
+
else
|
201
|
+
majory = major_count
|
202
|
+
ytick = GR.tick(ymin, ymax) / majory
|
203
|
+
end
|
204
|
+
else
|
205
|
+
ytick = majory = 1
|
206
|
+
end
|
207
|
+
yorg = if (scale & GR::OPTION_FLIP_Y) == 0
|
208
|
+
[ymin, ymax]
|
209
|
+
else
|
210
|
+
[ymax, ymin]
|
211
|
+
end
|
212
|
+
kvs[:yaxis] = ytick, yorg, majory
|
213
|
+
|
214
|
+
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
215
|
+
zmin, zmax = kvs[:zrange]
|
216
|
+
if (scale & GR::OPTION_Z_LOG) == 0
|
217
|
+
zmin, zmax = GR.adjustlimits(zmin, zmax) if kvs.key?(:zlim)
|
218
|
+
if kvs.key?(:zticks)
|
219
|
+
ztick, majorz = kvs[:zticks]
|
220
|
+
else
|
221
|
+
majorz = major_count
|
222
|
+
ztick = GR.tick(zmin, zmax) / majorz
|
223
|
+
end
|
224
|
+
else
|
225
|
+
ztick = majorz = 1
|
226
|
+
end
|
227
|
+
zorg = if (scale & GR::OPTION_FLIP_Z) == 0
|
228
|
+
[zmin, zmax]
|
229
|
+
else
|
230
|
+
[zmax, zmin]
|
231
|
+
end
|
232
|
+
kvs[:zaxis] = ztick, zorg, majorz
|
233
|
+
end
|
234
|
+
|
235
|
+
kvs[:window] = xmin, xmax, ymin, ymax
|
236
|
+
if %i[polar polarhist polarheatmap].include?(kind)
|
237
|
+
GR.setwindow(-1, 1, -1, 1)
|
238
|
+
else
|
239
|
+
GR.setwindow(xmin, xmax, ymin, ymax)
|
240
|
+
end
|
241
|
+
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
242
|
+
rotation = kvs[:rotation] || 40
|
243
|
+
tilt = kvs[:tilt] || 70
|
244
|
+
GR.setspace(zmin, zmax, rotation, tilt)
|
245
|
+
end
|
246
|
+
|
247
|
+
kvs[:scale] = scale
|
248
|
+
GR.setscale(scale)
|
249
|
+
end
|
250
|
+
|
251
|
+
def draw_axes(kind, pass = 1)
|
252
|
+
viewport = kvs[:viewport]
|
253
|
+
vp = kvs[:vp]
|
254
|
+
ratio = kvs[:ratio]
|
255
|
+
xtick, xorg, majorx = kvs[:xaxis]
|
256
|
+
ytick, yorg, majory = kvs[:yaxis]
|
257
|
+
drawgrid = kvs[:grid] || true
|
258
|
+
xtick = 10 if kvs[:scale] & GR::OPTION_X_LOG != 0
|
259
|
+
ytick = 10 if kvs[:scale] & GR::OPTION_Y_LOG != 0
|
260
|
+
GR.setlinecolorind(1)
|
261
|
+
diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
|
262
|
+
GR.setlinewidth(1)
|
263
|
+
charheight = [0.018 * diag, 0.012].max
|
264
|
+
GR.setcharheight(charheight)
|
265
|
+
ticksize = 0.0075 * diag
|
266
|
+
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
267
|
+
ztick, zorg, majorz = kvs[:zaxis]
|
268
|
+
if pass == 1 && drawgrid
|
269
|
+
GR.grid3d(xtick, 0, ztick, xorg[0], yorg[1], zorg[0], 2, 0, 2)
|
270
|
+
GR.grid3d(0, ytick, 0, xorg[0], yorg[1], zorg[0], 0, 2, 0)
|
271
|
+
else
|
272
|
+
GR.axes3d(xtick, 0, ztick, xorg[0], yorg[0], zorg[0], majorx, 0, majorz, -ticksize)
|
273
|
+
GR.axes3d(0, ytick, 0, xorg[1], yorg[0], zorg[0], 0, majory, 0, ticksize)
|
274
|
+
end
|
275
|
+
else
|
276
|
+
if %i[heatmap nonuniformheatmap shade].include?(kind)
|
277
|
+
ticksize = -ticksize
|
278
|
+
else
|
279
|
+
drawgrid && GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
280
|
+
end
|
281
|
+
if kvs.key?(:xticklabels) || kvs.key?(:yticklabels)
|
282
|
+
fx = if kvs.key?(:xticklabels)
|
283
|
+
GRCommons::Fiddley::Function.new(
|
284
|
+
:void, %i[double double string double]
|
285
|
+
) do |x, y, _svalue, value|
|
286
|
+
label = value < 0 ? '' : kvs[:xticklabels][value] || ''
|
287
|
+
GR.textext(x, y, label)
|
288
|
+
end
|
289
|
+
else
|
290
|
+
GRCommons::Fiddley::Function.new(
|
291
|
+
:void, %i[double double string double]
|
292
|
+
) do |x, y, _svalue, value|
|
293
|
+
GR.textext(x, y, value.to_s)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
fy = if kvs.key?(:yticklabels)
|
297
|
+
GRCommons::Fiddley::Function.new(
|
298
|
+
:void, %i[double double string double]
|
299
|
+
) do |x, y, _svalue, value|
|
300
|
+
label = value < 0 ? '' : kvs[:yticklabels][value] || ''
|
301
|
+
GR.textext(x, y, label)
|
302
|
+
end
|
303
|
+
else
|
304
|
+
GRCommons::Fiddley::Function.new(
|
305
|
+
:void, %i[double double string double]
|
306
|
+
) do |x, y, _svalue, value|
|
307
|
+
GR.textext(x, y, value.to_s)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
GR.axeslbl(xtick, ytick, xorg[0], yorg[0], majorx, majory, ticksize, fx, fy)
|
311
|
+
else
|
312
|
+
GR.axes(xtick, ytick, xorg[0], yorg[0], majorx, majory, ticksize)
|
313
|
+
end
|
314
|
+
GR.axes(xtick, ytick, xorg[1], yorg[1], -majorx, -majory, -ticksize)
|
315
|
+
end
|
316
|
+
|
317
|
+
if kvs.key?(:title)
|
318
|
+
GR.savestate
|
319
|
+
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
|
320
|
+
text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title])
|
321
|
+
GR.restorestate
|
322
|
+
end
|
323
|
+
if %i[wireframe surface plot3 scatter3 trisurf volume].include?(kind)
|
324
|
+
xlabel = kvs[:xlabel] || ''
|
325
|
+
ylabel = kvs[:ylabel] || ''
|
326
|
+
zlabel = kvs[:zlabel] || ''
|
327
|
+
GR.titles3d(xlabel, ylabel, zlabel)
|
328
|
+
else
|
329
|
+
if kvs.key?(:xlabel)
|
330
|
+
GR.savestate
|
331
|
+
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_BOTTOM)
|
332
|
+
text(0.5 * (viewport[0] + viewport[1]), vp[2] + 0.5 * charheight, kvs[:xlabel])
|
333
|
+
GR.restorestate
|
334
|
+
end
|
335
|
+
if kvs.key?(:ylabel)
|
336
|
+
GR.savestate
|
337
|
+
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
|
338
|
+
GR.setcharup(-1, 0)
|
339
|
+
text(vp[0] + 0.5 * charheight, 0.5 * (viewport[2] + viewport[3]), kvs[:ylabel])
|
340
|
+
GR.restorestate
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def draw_polar_axes
|
346
|
+
viewport = kvs[:viewport]
|
347
|
+
diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
|
348
|
+
charheight = [0.018 * diag, 0.012].max
|
349
|
+
|
350
|
+
window = kvs[:window]
|
351
|
+
rmin = window[2]
|
352
|
+
rmax = window[3]
|
353
|
+
|
354
|
+
GR.savestate
|
355
|
+
GR.setcharheight(charheight)
|
356
|
+
GR.setlinetype(GR::LINETYPE_SOLID)
|
357
|
+
|
358
|
+
tick = 0.5 * GR.tick(rmin, rmax)
|
359
|
+
n = ((rmax - rmin) / tick + 0.5).round
|
360
|
+
(n + 1).times do |i|
|
361
|
+
r = i.to_f / n
|
362
|
+
if i.even?
|
363
|
+
GR.setlinecolorind(88)
|
364
|
+
GR.drawarc(-r, r, -r, r, 0, 359) if i > 0
|
365
|
+
GR.settextalign(GR::TEXT_HALIGN_LEFT, GR::TEXT_VALIGN_HALF)
|
366
|
+
x, y = GR.wctondc(0.05, r)
|
367
|
+
GR.text(x, y, (rmin + i * tick).to_s) # FIXME: round. significant digits.
|
368
|
+
else
|
369
|
+
GR.setlinecolorind(90)
|
370
|
+
GR.drawarc(-r, r, -r, r, 0, 359)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
linspace(0, 315, 8).each do |alpha|
|
374
|
+
sinf = Math.sin(alpha * Math::PI / 180)
|
375
|
+
cosf = Math.cos(alpha * Math::PI / 180)
|
376
|
+
GR.polyline([cosf, 0], [sinf, 0])
|
377
|
+
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_HALF)
|
378
|
+
x, y = GR.wctondc(1.1 * cosf, 1.1 * sinf)
|
379
|
+
GR.textext(x, y, "%<alpha>g\xb0")
|
380
|
+
end
|
381
|
+
GR.restorestate
|
382
|
+
end
|
383
|
+
|
384
|
+
def plot_polar(θ, ρ)
|
385
|
+
ρ = Numo::DFloat.cast(ρ) if ρ.is_a? Array
|
386
|
+
window = kvs[:window]
|
387
|
+
rmin = window[2]
|
388
|
+
rmax = window[3]
|
389
|
+
ρ = (ρ - rmin) / (rmax - rmin)
|
390
|
+
n = ρ.length
|
391
|
+
x = []
|
392
|
+
y = []
|
393
|
+
n.times do |i|
|
394
|
+
x << ρ[i] * Math.cos(θ[i])
|
395
|
+
y << ρ[i] * Math.sin(θ[i])
|
396
|
+
end
|
397
|
+
GR.polyline(x, y)
|
398
|
+
end
|
399
|
+
|
400
|
+
def plot_img(img)
|
401
|
+
viewport = kvs[:vp].clone
|
402
|
+
viewport[3] -= 0.05 if kvs.key?(:title)
|
403
|
+
vp = kvs[:vp]
|
404
|
+
|
405
|
+
if img.is_a? String
|
406
|
+
width, height, data = GR.readimage(img)
|
407
|
+
else
|
408
|
+
width, height = img.shape
|
409
|
+
cmin, cmax = kvs[:crange]
|
410
|
+
data = img.map { |i| normalize_color(i, cmin, cmax) }
|
411
|
+
data = data.map { |i| (1000 + i * 255).round }
|
412
|
+
end
|
413
|
+
|
414
|
+
if width * (viewport[3] - viewport[2]) < height * (viewport[1] - viewport[0])
|
415
|
+
w = width.to_f / height * (viewport[3] - viewport[2])
|
416
|
+
xmin = [0.5 * (viewport[0] + viewport[1] - w), viewport[0]].max
|
417
|
+
xmax = [0.5 * (viewport[0] + viewport[1] + w), viewport[1]].min
|
418
|
+
ymin = viewport[2]
|
419
|
+
ymax = viewport[3]
|
420
|
+
else
|
421
|
+
h = height.to_f / width * (viewport[1] - viewport[0])
|
422
|
+
xmin = viewport[0]
|
423
|
+
xmax = viewport[1]
|
424
|
+
ymin = [0.5 * (viewport[3] + viewport[2] - h), viewport[2]].max
|
425
|
+
ymax = [0.5 * (viewport[3] + viewport[2] + h), viewport[3]].min
|
426
|
+
end
|
427
|
+
|
428
|
+
GR.selntran(0)
|
429
|
+
GR.setscale(0)
|
430
|
+
if kvs.key?(:xflip)
|
431
|
+
tmp = xmax
|
432
|
+
xmax = xmin
|
433
|
+
xmin = tmp
|
434
|
+
end
|
435
|
+
if kvs.key?(:yflip)
|
436
|
+
tmp = ymax
|
437
|
+
ymax = ymin
|
438
|
+
ymin = tmp
|
439
|
+
end
|
440
|
+
if img.is_a? String
|
441
|
+
GR.drawimage(xmin, xmax, ymin, ymax, width, height, data)
|
442
|
+
else
|
443
|
+
GR.cellarray(xmin, xmax, ymin, ymax, width, height, data)
|
444
|
+
end
|
445
|
+
|
446
|
+
if kvs.key?(:title)
|
447
|
+
GR.savestate
|
448
|
+
GR.settextalign(GR::TEXT_HALIGN_CENTER, GR::TEXT_VALIGN_TOP)
|
449
|
+
text(0.5 * (viewport[0] + viewport[1]), vp[3], kvs[:title])
|
450
|
+
GR.restorestate
|
451
|
+
end
|
452
|
+
GR.selntran(1)
|
453
|
+
end
|
454
|
+
|
455
|
+
def plot_iso(v)
|
456
|
+
viewport = kvs[:viewport]
|
457
|
+
|
458
|
+
if viewport[3] - viewport[2] < viewport[1] - viewport[0]
|
459
|
+
width = viewport[3] - viewport[2]
|
460
|
+
centerx = 0.5 * (viewport[0] + viewport[1])
|
461
|
+
xmin = [centerx - 0.5 * width, viewport[0]].max
|
462
|
+
xmax = [centerx + 0.5 * width, viewport[1]].min
|
463
|
+
ymin = viewport[2]
|
464
|
+
ymax = viewport[3]
|
465
|
+
else
|
466
|
+
height = viewport[1] - viewport[0]
|
467
|
+
centery = 0.5 * (viewport[2] + viewport[3])
|
468
|
+
xmin = viewport[0]
|
469
|
+
xmax = viewport[1]
|
470
|
+
ymin = [centery - 0.5 * height, viewport[2]].max
|
471
|
+
ymax = [centery + 0.5 * height, viewport[3]].min
|
472
|
+
end
|
473
|
+
|
474
|
+
GR.selntran(0)
|
475
|
+
values = ((v - v.min) / (v.max - v.min) * (2 ^ 16 - 1)).round
|
476
|
+
nx, ny, nz = v.shape
|
477
|
+
isovalue = ((kvs[:isovalue] || 0.5) - v.min) / (v.max - v.min)
|
478
|
+
rotation = ((kvs[:rotation] || 40) * Math::PI / 180.0)
|
479
|
+
tilt = ((kvs[:tilt] || 70) * Math::PI / 180.0)
|
480
|
+
r = 2.5
|
481
|
+
GR3.clear
|
482
|
+
mesh = GR3.createisosurfacemesh(values, [2.0 / (nx - 1), 2.0 / (ny - 1), 2.0 / (nz - 1)],
|
483
|
+
[-1, -1, -1],
|
484
|
+
(isovalue * (2 ^ 16 - 1)).round)
|
485
|
+
color = kvs[:color] || [0.0, 0.5, 0.8]
|
486
|
+
GR3.setbackgroundcolor(1, 1, 1, 0)
|
487
|
+
GR3.drawmesh(mesh, 1, [0, 0, 0], [0, 0, 1], [0, 1, 0], color, [1, 1, 1])
|
488
|
+
GR3.cameralookat(r * Math.sin(tilt) * Math.sin(rotation),
|
489
|
+
r * Math.cos(tilt), r * Math.sin(tilt) * Math.cos(rotation),
|
490
|
+
0, 0, 0, 0, 1, 0)
|
491
|
+
GR3.drawimage(xmin, xmax, ymin, ymax, 500, 500, GR3::DRAWABLE_GKS)
|
492
|
+
GR3.deletemesh(mesh)
|
493
|
+
GR.selntran(1)
|
494
|
+
end
|
495
|
+
|
496
|
+
def colorbar(off = 0, colors = 256)
|
497
|
+
GR.savestate
|
498
|
+
viewport = kvs[:viewport]
|
499
|
+
zmin, zmax = kvs[:zrange]
|
500
|
+
mask = (GR::OPTION_Z_LOG | GR::OPTION_FLIP_Y | GR::OPTION_FLIP_Z)
|
501
|
+
options = if kvs.key?(:zflip)
|
502
|
+
(GR.inqscale | GR::OPTION_FLIP_Y)
|
503
|
+
elsif kvs.key?(:yflip)
|
504
|
+
GR.inqscale & ~GR::OPTION_FLIP_Y
|
505
|
+
else
|
506
|
+
GR.inqscale
|
507
|
+
end
|
508
|
+
GR.setscale(options & mask)
|
509
|
+
h = 0.5 * (zmax - zmin) / (colors - 1)
|
510
|
+
GR.setwindow(0, 1, zmin, zmax)
|
511
|
+
GR.setviewport(viewport[1] + 0.02 + off, viewport[1] + 0.05 + off,
|
512
|
+
viewport[2], viewport[3])
|
513
|
+
l = linspace(1000, 1255, colors).map(&:round)
|
514
|
+
GR.cellarray(0, 1, zmax + h, zmin - h, 1, colors, l)
|
515
|
+
GR.setlinecolorind(1)
|
516
|
+
diag = Math.sqrt((viewport[1] - viewport[0])**2 + (viewport[3] - viewport[2])**2)
|
517
|
+
charheight = [0.016 * diag, 0.012].max
|
518
|
+
GR.setcharheight(charheight)
|
519
|
+
if kvs[:scale] & GR::OPTION_Z_LOG == 0
|
520
|
+
ztick = 0.5 * GR.tick(zmin, zmax)
|
521
|
+
GR.axes(0, ztick, 1, zmin, 0, 1, 0.005)
|
522
|
+
else
|
523
|
+
GR.setscale(GR::OPTION_Y_LOG)
|
524
|
+
GR.axes(0, 2, 1, zmin, 0, 1, 0.005)
|
525
|
+
end
|
526
|
+
GR.restorestate
|
527
|
+
end
|
528
|
+
|
529
|
+
def plot_data(_figure = true)
|
530
|
+
# GR.init
|
531
|
+
|
532
|
+
# target = GR.displayname
|
533
|
+
# if flag && target != None
|
534
|
+
# if target == "js" || target == "meta"
|
535
|
+
# send_meta(0)
|
536
|
+
# else
|
537
|
+
# send_serialized(target)
|
538
|
+
# end
|
539
|
+
# return
|
540
|
+
# end
|
541
|
+
|
542
|
+
kind = kvs[:kind] || :line
|
543
|
+
GR.clearws if kvs[:clear]
|
544
|
+
|
545
|
+
if scheme != 0
|
546
|
+
# Not yet.
|
547
|
+
end
|
548
|
+
|
549
|
+
set_viewport(kind, kvs[:subplot])
|
550
|
+
unless kvs[:ax]
|
551
|
+
set_window(kind)
|
552
|
+
if %i[polar polarhist].include?(kind)
|
553
|
+
draw_polar_axes
|
554
|
+
elsif !%i[imshow isosurface polarheatmap].include?(kind)
|
555
|
+
draw_axes(kind)
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
if kvs.key?(:colormap)
|
560
|
+
GR.setcolormap(kvs[:colormap])
|
561
|
+
else
|
562
|
+
GR.setcolormap(GR::COLORMAP_VIRIDIS)
|
563
|
+
end
|
564
|
+
|
565
|
+
GR.uselinespec(' ')
|
566
|
+
args.each do |x, y, z, c, spec|
|
567
|
+
# FIXME
|
568
|
+
spec ||= ''
|
569
|
+
GR.savestate
|
570
|
+
GR.settransparency(kvs[:alpha]) if kvs.key?(:alpha)
|
571
|
+
case kind
|
572
|
+
when :line
|
573
|
+
mask = GR.uselinespec(spec)
|
574
|
+
GR.polyline(x, y) if hasline(mask)
|
575
|
+
GR.polymarker(x, y) if hasmarker(mask)
|
576
|
+
when :step
|
577
|
+
mask = GR.uselinespec(spec)
|
578
|
+
if hasline(mask)
|
579
|
+
where = kvs[:where] || 'mid'
|
580
|
+
n = x.length
|
581
|
+
xs = [x[0]]
|
582
|
+
case where
|
583
|
+
when 'pre'
|
584
|
+
ys = [y[0]]
|
585
|
+
(n - 1).times do |i|
|
586
|
+
xs << x[i] << x[i + 1]
|
587
|
+
ys << y[i + 1] << y[i + 1]
|
588
|
+
end
|
589
|
+
when 'post'
|
590
|
+
ys = [y[0]]
|
591
|
+
(n - 1).times do |i|
|
592
|
+
xs << x[i + 1] << x[i + 1]
|
593
|
+
ys << y[i] << y[i + 1]
|
594
|
+
end
|
595
|
+
else
|
596
|
+
ys = []
|
597
|
+
(n - 1).times do |i|
|
598
|
+
xs << 0.5 * (x[i] + x[i + 1]) << 0.5 * (x[i] + x[i + 1])
|
599
|
+
ys << y[i] << y[i]
|
600
|
+
end
|
601
|
+
xs << x[n - 1]
|
602
|
+
ys << y[n - 1] << y[n - 1]
|
603
|
+
end
|
604
|
+
GR.polyline(xs, ys)
|
605
|
+
end
|
606
|
+
GR.polymarker(x, y) if hasmarker(mask)
|
607
|
+
when :scatter
|
608
|
+
GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
|
609
|
+
if z || c
|
610
|
+
if c
|
611
|
+
cmin, cmax = kvs[:crange]
|
612
|
+
c = c.to_a if narray?(c)
|
613
|
+
c.map! { |i| normalize_color(i, cmin, cmax) }
|
614
|
+
cind = c.map { |i| (1000 + i * 255).round }
|
615
|
+
end
|
616
|
+
x.length.times do |i|
|
617
|
+
GR.setmarkersize(z[i] / 100.0) if z
|
618
|
+
GR.setmarkercolorind(cind[i]) if c
|
619
|
+
GR.polymarker([x[i]], [y[i]])
|
620
|
+
end
|
621
|
+
else
|
622
|
+
GR.polymarker(x, y)
|
623
|
+
end
|
624
|
+
when :stem
|
625
|
+
GR.setlinecolorind(1)
|
626
|
+
GR.polyline(kvs[:window][0..1], [0, 0])
|
627
|
+
GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
|
628
|
+
GR.uselinespec(spec)
|
629
|
+
x = x.to_a if narray?(x)
|
630
|
+
y = y.to_a if narray?(y)
|
631
|
+
x.zip(y).each do |xi, yi|
|
632
|
+
GR.polyline([xi, xi], [0, yi])
|
633
|
+
end
|
634
|
+
GR.polymarker(x, y)
|
635
|
+
when :hist
|
636
|
+
ymin = kvs[:window][2]
|
637
|
+
y.length.times do |i|
|
638
|
+
GR.setfillcolorind(989)
|
639
|
+
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
640
|
+
GR.fillrect(x[i], x[i + 1], ymin, y[i])
|
641
|
+
GR.setfillcolorind(1)
|
642
|
+
GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
|
643
|
+
GR.fillrect(x[i], x[i + 1], ymin, y[i])
|
644
|
+
end
|
645
|
+
# when :polarhist
|
646
|
+
# xmin, xmax = x.minmax
|
647
|
+
# ymax = kvs[:window][3]
|
648
|
+
# ρ = y.map { |i| 2 * (i.to_f / ymax - 0.5) }
|
649
|
+
# θ = x.map { |i| 2 * Math::PI * (i.to_f - xmin) / (xmax - xmin) }
|
650
|
+
# ρ.length.times do |i|
|
651
|
+
# GR.setfillcolorind(989)
|
652
|
+
# GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
653
|
+
# GR.fillarea([0, ρ[i] * Math.cos(θ[i]), ρ[i] * Math.cos(θ[i + 1])],
|
654
|
+
# [0, ρ[i] * Math.sin(θ[i]), ρ[i] * Math.sin(θ[i + 1])])
|
655
|
+
# GR.setfillcolorind(1)
|
656
|
+
# GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
|
657
|
+
# GR.fillarea([0, ρ[i] * Math.cos(θ[i]), ρ[i] * Math.cos(θ[i + 1])],
|
658
|
+
# [0, ρ[i] * Math.sin(θ[i]), ρ[i] * Math.sin(θ[i + 1])])
|
659
|
+
# end
|
660
|
+
when :polarheatmap
|
661
|
+
w, h = z.shape
|
662
|
+
cmap = colormap
|
663
|
+
cmin, cmax = kvs[:zrange]
|
664
|
+
data = z.map { |i| normalize_color(i, cmin, cmax) }
|
665
|
+
colors = data.map { |i| 1000 + i * 255 }
|
666
|
+
# if kvs[:xflip]
|
667
|
+
# if kvs[;yflip]
|
668
|
+
GR.polarcellarray(0, 0, 0, 360, 0, 1, w, h, colors)
|
669
|
+
draw_polar_axes
|
670
|
+
kvs[:zrange] = [cmin, cmax]
|
671
|
+
colorbar
|
672
|
+
when :contour
|
673
|
+
zmin, zmax = kvs[:zrange]
|
674
|
+
if x.length == y.length && y.length == z.length
|
675
|
+
x, y, z = GR.gridit(x, y, z, 200, 200)
|
676
|
+
zmin, zmax = kvs[:zlim] || z.compact.minmax # compact : removed nil
|
677
|
+
end
|
678
|
+
GR.setspace(zmin, zmax, 0, 90)
|
679
|
+
levels = kvs[:levels] || 0
|
680
|
+
clabels = kvs[:clabels] || false
|
681
|
+
if levels.is_a? Integer
|
682
|
+
hmin, hmax = GR.adjustrange(zmin, zmax)
|
683
|
+
h = linspace(hmin, hmax, levels == 0 ? 21 : levels + 1)
|
684
|
+
else
|
685
|
+
h = levels
|
686
|
+
end
|
687
|
+
GR.contour(x, y, h, z, clabels ? 1 : 1000)
|
688
|
+
colorbar(0, h.length)
|
689
|
+
when :contourf
|
690
|
+
zmin, zmax = kvs[:zrange]
|
691
|
+
if x.length == y.length && y.length == z.length
|
692
|
+
x, y, z = GR.gridit(x, y, z, 200, 200)
|
693
|
+
zmin, zmax = kvs[:zlim] || z.compact.minmax # compact : removed nil
|
694
|
+
end
|
695
|
+
GR.setspace(zmin, zmax, 0, 90)
|
696
|
+
levels = kvs[:levels] || 0
|
697
|
+
clabels = kvs[:clabels] || false
|
698
|
+
if levels.is_a? Integer
|
699
|
+
hmin, hmax = GR.adjustrange(zmin, zmax)
|
700
|
+
h = linspace(hmin, hmax, levels == 0 ? 21 : levels + 1)
|
701
|
+
else
|
702
|
+
h = levels
|
703
|
+
end
|
704
|
+
GR.contourf(x, y, h, z, clabels ? 1 : 0)
|
705
|
+
colorbar(0, h.length)
|
706
|
+
when :hexbin
|
707
|
+
nbins = kvs[:nbins] || 40
|
708
|
+
cntmax = GR.hexbin(x, y, nbins)
|
709
|
+
if cntmax > 0
|
710
|
+
kvs[:zrange] = [0, cntmax]
|
711
|
+
colorbar
|
712
|
+
end
|
713
|
+
when :heatmap, :nonuniformheatmap
|
714
|
+
case z
|
715
|
+
when Array
|
716
|
+
if z.all? { |zi| zi.size = z[0].size }
|
717
|
+
w = z.size
|
718
|
+
h = z[0].size
|
719
|
+
else
|
720
|
+
raise
|
721
|
+
end
|
722
|
+
when ->(obj) { narray?(obj) }
|
723
|
+
w, h = z.shape
|
724
|
+
else
|
725
|
+
raise
|
726
|
+
end
|
727
|
+
cmap = colormap
|
728
|
+
cmin, cmax = kvs[:crange]
|
729
|
+
levels = kvs[:levels] || 256
|
730
|
+
data = z.flatten.to_a.map { |i| normalize_color(i, cmin, cmax) } # NArray -> Array
|
731
|
+
if kind == :heatmap
|
732
|
+
rgba = data.map { |v| to_rgba(v, cmap) }
|
733
|
+
GR.drawimage(0.5, w + 0.5, h + 0.5, 0.5, w, h, rgba)
|
734
|
+
else
|
735
|
+
colors = data.map { |i| (1000 + i * 255).round }
|
736
|
+
GR.nonuniformcellarray(x, y, w, h, colors)
|
737
|
+
end
|
738
|
+
colorbar(0, levels)
|
739
|
+
when :wireframe
|
740
|
+
x, y, z = GR.gridit(x, y, z, 50, 50) if equal_length(x, y, z)
|
741
|
+
GR.setfillcolorind(0)
|
742
|
+
GR.surface(x, y, z, GR::OPTION_FILLED_MESH)
|
743
|
+
draw_axes(kind, 2)
|
744
|
+
when :surface
|
745
|
+
x, y, z = GR.gridit(x, y, z, 200, 200) if equal_length(x, y, z)
|
746
|
+
if kvs[:accelerate] == false
|
747
|
+
GR.surface(x, y, z, GR::OPTION_COLORED_MESH)
|
748
|
+
else
|
749
|
+
require 'gr3'
|
750
|
+
GR3.clear
|
751
|
+
GR3.surface(x, y, z, GR::OPTION_COLORED_MESH)
|
752
|
+
end
|
753
|
+
draw_axes(kind, 2)
|
754
|
+
colorbar(0.05)
|
755
|
+
when :volume
|
756
|
+
algorithm = kvs[:algorithm] || 0
|
757
|
+
require 'gr3'
|
758
|
+
GR3.clear
|
759
|
+
dmin, dmax = GR3.volume(z, algorithm)
|
760
|
+
draw_axes(kind, 2)
|
761
|
+
kvs[:zrange] = [dmin, dmax]
|
762
|
+
colorbar(0.05)
|
763
|
+
when :plot3
|
764
|
+
GR.polyline3d(x, y, z)
|
765
|
+
draw_axes(kind, 2)
|
766
|
+
when :scatter3
|
767
|
+
GR.setmarkertype(GR::MARKERTYPE_SOLID_CIRCLE)
|
768
|
+
if c
|
769
|
+
cmin, cmax = kvs[:crange]
|
770
|
+
c = c.map { |i| normalize_color(i, cmin, cmax) } # NArray -> Array
|
771
|
+
cind = c.map { |i| (1000 + i * 255).round }
|
772
|
+
x.length.times do |i|
|
773
|
+
GR.setmarkercolorind(cind[i])
|
774
|
+
GR.polymarker3d([x[i]], [y[i]], [z[i]])
|
775
|
+
end
|
776
|
+
else
|
777
|
+
GR.polymarker3d(x, y, z)
|
778
|
+
end
|
779
|
+
draw_axes(kind, 2)
|
780
|
+
when :imshow
|
781
|
+
plot_img(z)
|
782
|
+
when :isosurface
|
783
|
+
plot_iso(z)
|
784
|
+
when :polar
|
785
|
+
GR.uselinespec(spec)
|
786
|
+
plot_polar(x, y)
|
787
|
+
when :trisurf
|
788
|
+
GR.trisurface(x, y, z)
|
789
|
+
draw_axes(kind, 2)
|
790
|
+
colorbar(0.05)
|
791
|
+
when :tricont
|
792
|
+
zmin, zmax = kvs[:zrange]
|
793
|
+
levels = linspace(zmin, zmax, 20)
|
794
|
+
GR.tricontour(x, y, z, levels)
|
795
|
+
when :shade
|
796
|
+
xform = kvs[:xform] || 5
|
797
|
+
if x.to_a.include? Float::NAN # FIXME: Ruby is different from Julia?
|
798
|
+
# How to check NArray?
|
799
|
+
GR.shadelines(x, y, xform: xform)
|
800
|
+
else
|
801
|
+
GR.shadepoints(x, y, xform: xform)
|
802
|
+
end
|
803
|
+
when :bar
|
804
|
+
0.step(x.length - 1, 2) do |i|
|
805
|
+
GR.setfillcolorind(989)
|
806
|
+
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
807
|
+
GR.fillrect(x[i], x[i + 1], y[i], y[i + 1])
|
808
|
+
GR.setfillcolorind(1)
|
809
|
+
GR.setfillintstyle(GR::INTSTYLE_HOLLOW)
|
810
|
+
GR.fillrect(x[i], x[i + 1], y[i], y[i + 1])
|
811
|
+
end
|
812
|
+
end
|
813
|
+
GR.restorestate
|
814
|
+
end
|
815
|
+
|
816
|
+
draw_legend if %i[line step scatter stem].include?(kind) && kvs.key?(:labels)
|
817
|
+
|
818
|
+
if kvs.key?(:update)
|
819
|
+
GR.updatews
|
820
|
+
# if GR.isinline()
|
821
|
+
# restore_context()
|
822
|
+
# return GR.show()
|
823
|
+
# end
|
824
|
+
end
|
825
|
+
|
826
|
+
# flag && restore_context()
|
827
|
+
end
|
828
|
+
|
829
|
+
def draw_legend
|
830
|
+
w, h = legend_size
|
831
|
+
viewport = kvs[:viewport]
|
832
|
+
location = kvs[:location] || 1
|
833
|
+
num_labels = kvs[:labels].length
|
834
|
+
GR.savestate
|
835
|
+
GR.selntran 0
|
836
|
+
GR.setscale 0
|
837
|
+
px = case location
|
838
|
+
when 11, 12, 13
|
839
|
+
viewport[1] + 0.11
|
840
|
+
when 8, 9, 10
|
841
|
+
0.5 * (viewport[0] + viewport[1] - w + 0.05)
|
842
|
+
when 2, 3, 6
|
843
|
+
viewport[0] + 0.11
|
844
|
+
else
|
845
|
+
viewport[1] - 0.05 - w
|
846
|
+
end
|
847
|
+
py = case location
|
848
|
+
when 5, 6, 7, 10, 12
|
849
|
+
0.5 * (viewport[2] + viewport[3] + h - 0.03)
|
850
|
+
when 13
|
851
|
+
viewport[2] + h
|
852
|
+
when 3, 4, 8
|
853
|
+
viewport[2] + h + 0.03
|
854
|
+
when 11
|
855
|
+
viewport[3] - 0.03
|
856
|
+
else
|
857
|
+
viewport[3] - 0.06
|
858
|
+
end
|
859
|
+
GR.setfillintstyle(GR::INTSTYLE_SOLID)
|
860
|
+
GR.setfillcolorind(0)
|
861
|
+
GR.fillrect(px - 0.08, px + w + 0.02, py + 0.03, py - h)
|
862
|
+
GR.setlinetype(GR::LINETYPE_SOLID)
|
863
|
+
GR.setlinecolorind(1)
|
864
|
+
GR.setlinewidth(1)
|
865
|
+
GR.drawrect(px - 0.08, px + w + 0.02, py + 0.03, py - h)
|
866
|
+
i = 0
|
867
|
+
GR.uselinespec(' ')
|
868
|
+
args.each do |_x, _y, _z, _c, spec|
|
869
|
+
if i < num_labels
|
870
|
+
label = kvs[:labels][i]
|
871
|
+
tbx, tby = inqtext(0, 0, label)
|
872
|
+
dy = [(tby[2] - tby[0]) - 0.03, 0].max
|
873
|
+
py -= 0.5 * dy
|
874
|
+
end
|
875
|
+
GR.savestate
|
876
|
+
mask = GR.uselinespec(spec || '')
|
877
|
+
GR.polyline([px - 0.07, px - 0.01], [py, py]) if hasline(mask)
|
878
|
+
GR.polymarker([px - 0.06, px - 0.02], [py, py]) if hasmarker(mask)
|
879
|
+
GR.restorestate
|
880
|
+
GR.settextalign(GR::TEXT_HALIGN_LEFT, GR::TEXT_VALIGN_HALF)
|
881
|
+
if i < num_labels
|
882
|
+
GR.text(px, py, label)
|
883
|
+
py -= 0.5 * dy
|
884
|
+
i += 1
|
885
|
+
end
|
886
|
+
py -= 0.03
|
887
|
+
GR.selntran(1)
|
888
|
+
GR.restorestate
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
private
|
893
|
+
|
894
|
+
def hasline(mask)
|
895
|
+
mask == 0x00 || (mask & 0x01 != 0)
|
896
|
+
end
|
897
|
+
|
898
|
+
def hasmarker(mask)
|
899
|
+
mask & 0x02 != 0
|
900
|
+
end
|
901
|
+
|
902
|
+
def colormap
|
903
|
+
# rgb
|
904
|
+
Array.new(256) do |colorind|
|
905
|
+
color = GR.inqcolor(1000 + colorind)
|
906
|
+
[(color & 0xff) / 255.0,
|
907
|
+
((color >> 8) & 0xff) / 255.0,
|
908
|
+
((color >> 16) & 0xff) / 255.0]
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
def to_rgba(value, cmap)
|
913
|
+
begin
|
914
|
+
r, g, b = cmap[(value * 255).round]
|
915
|
+
a = 1.0
|
916
|
+
rescue StandardError # nil
|
917
|
+
r = 0
|
918
|
+
g = 0
|
919
|
+
b = 0
|
920
|
+
a = 0
|
921
|
+
end
|
922
|
+
|
923
|
+
((a * 255).round << 24) + ((b * 255).round << 16) +
|
924
|
+
((g * 255).round << 8) + (r * 255).round
|
925
|
+
end
|
926
|
+
|
927
|
+
# https://gist.github.com/rysk-t/8d1aef0fb67abde1d259#gistcomment-1925021
|
928
|
+
def linspace(low, high, num)
|
929
|
+
[*0..(num - 1)].collect { |i| low + i.to_f * (high - low) / (num - 1) }
|
930
|
+
end
|
931
|
+
|
932
|
+
def plot_args(args, _fmt = :xys)
|
933
|
+
# :construction:
|
934
|
+
x, y, z, c = args
|
935
|
+
[[x, y, z, c]]
|
936
|
+
end
|
937
|
+
|
938
|
+
# Normalize a color c with the range [cmin, cmax]
|
939
|
+
# 0 <= normalize_color(c, cmin, cmax) <= 1
|
940
|
+
def normalize_color(c, cmin, cmax)
|
941
|
+
c = c.clamp(cmin, cmax) - cmin
|
942
|
+
c /= (cmax - cmin) if cmin != cmax
|
943
|
+
c
|
944
|
+
end
|
945
|
+
|
946
|
+
def inqtext(x, y, s)
|
947
|
+
if s.length >= 2 && s[0] == '$' && s[-1] == '$'
|
948
|
+
GR.inqmathtex(x, y, s[1..-2])
|
949
|
+
elsif s.include?('\\') || s.include?('_') || s.include?('^')
|
950
|
+
GR.inqtextext(x, y, s)
|
951
|
+
else
|
952
|
+
GR.inqtext(x, y, s)
|
953
|
+
end
|
954
|
+
end
|
955
|
+
|
956
|
+
def text(x, y, s)
|
957
|
+
if s.length >= 2 && s[0] == '$' && s[-1] == '$'
|
958
|
+
GR.mathtex(x, y, s[1..-2])
|
959
|
+
elsif s.include?('\\') || s.include?('_') || s.include?('^')
|
960
|
+
GR.textext(x, y, s)
|
961
|
+
else
|
962
|
+
GR.text(x, y, s)
|
963
|
+
end
|
964
|
+
end
|
965
|
+
|
966
|
+
def fix_minmax(a, b)
|
967
|
+
if a == b
|
968
|
+
a -= a != 0 ? 0.1 * a : 0.1
|
969
|
+
b += b != 0 ? 0.1 * b : 0.1
|
970
|
+
end
|
971
|
+
[a, b]
|
972
|
+
end
|
973
|
+
|
974
|
+
def minmax
|
975
|
+
xmin = ymin = zmin = cmin = Float::INFINITY
|
976
|
+
xmax = ymax = zmax = cmax = -Float::INFINITY
|
977
|
+
|
978
|
+
args.each do |x, y, z, c|
|
979
|
+
if x
|
980
|
+
x0, x1 = x.minmax
|
981
|
+
xmin = [x0, xmin].min
|
982
|
+
xmax = [x1, xmax].max
|
983
|
+
else
|
984
|
+
xmin = 0
|
985
|
+
xmax = 1
|
986
|
+
end
|
987
|
+
if y
|
988
|
+
y0, y1 = y.minmax
|
989
|
+
ymin = [y0, ymin].min
|
990
|
+
ymax = [y1, ymax].max
|
991
|
+
else
|
992
|
+
ymin = 0
|
993
|
+
ymax = 1
|
994
|
+
end
|
995
|
+
if z
|
996
|
+
z0, z1 = z.minmax
|
997
|
+
zmin = [z0, zmin].min
|
998
|
+
zmax = [z1, zmax].max
|
999
|
+
end
|
1000
|
+
if c
|
1001
|
+
c0, c1 = c.minmax
|
1002
|
+
cmin = [c0, cmin].min
|
1003
|
+
cmax = [c1, cmax].max
|
1004
|
+
elsif z
|
1005
|
+
z0, z1 = z.minmax
|
1006
|
+
cmin = [z0, zmin].min
|
1007
|
+
cmax = [z1, zmax].max
|
1008
|
+
end
|
1009
|
+
end
|
1010
|
+
xmin, xmax = fix_minmax(xmin, xmax)
|
1011
|
+
ymin, ymax = fix_minmax(ymin, ymax)
|
1012
|
+
zmin, zmax = fix_minmax(zmin, zmax)
|
1013
|
+
if kvs.key?(:xlim)
|
1014
|
+
x0, x1 = kvs[:xlim]
|
1015
|
+
x0 ||= xmin
|
1016
|
+
x1 ||= xmax
|
1017
|
+
kvs[:xrange] = [x0, x1]
|
1018
|
+
else
|
1019
|
+
kvs[:xrange] = [xmin, xmax]
|
1020
|
+
end
|
1021
|
+
if kvs.key?(:ylim)
|
1022
|
+
y0, y1 = kvs[:ylim]
|
1023
|
+
y0 ||= ymin
|
1024
|
+
y1 ||= ymax
|
1025
|
+
kvs[:yrange] = [y0, y1]
|
1026
|
+
else
|
1027
|
+
kvs[:yrange] = [ymin, ymax]
|
1028
|
+
end
|
1029
|
+
if kvs.key?(:zlim)
|
1030
|
+
z0, z1 = kvs[:zlim]
|
1031
|
+
z0 ||= zmin
|
1032
|
+
z1 ||= zmax
|
1033
|
+
kvs[:zrange] = [z0, z1]
|
1034
|
+
else
|
1035
|
+
kvs[:zrange] = [zmin, zmax]
|
1036
|
+
end
|
1037
|
+
if kvs.key?(:clim)
|
1038
|
+
c0, c1 = kvs[:clim]
|
1039
|
+
c0 ||= cmin
|
1040
|
+
c1 ||= cmax
|
1041
|
+
kvs[:crange] = [c0, c1]
|
1042
|
+
else
|
1043
|
+
kvs[:crange] = [cmin, cmax]
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
def legend_size
|
1048
|
+
scale = GR.inqscale
|
1049
|
+
GR.selntran(0)
|
1050
|
+
GR.setscale(0)
|
1051
|
+
w = 0
|
1052
|
+
h = 0
|
1053
|
+
kvs[:labels].each do |label|
|
1054
|
+
tbx, tby = inqtext(0, 0, label)
|
1055
|
+
w = [w, tbx[2]].max
|
1056
|
+
h += [tby[2] - tby[0], 0.03].max
|
1057
|
+
end
|
1058
|
+
GR.setscale(scale)
|
1059
|
+
GR.selntran(1)
|
1060
|
+
[w, h]
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
# NOTE: duplicated definition (GRCommonUtils)
|
1064
|
+
def equal_length(*args)
|
1065
|
+
lengths = args.map(&:length)
|
1066
|
+
unless lengths.all? { |l| l == lengths[0] }
|
1067
|
+
raise ArgumentError,
|
1068
|
+
'Sequences must have same length.'
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
lengths[0]
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
# NOTE: duplicated definition (GRCommonUtils)
|
1075
|
+
def narray?(data)
|
1076
|
+
defined?(Numo::NArray) && data.is_a?(Numo::NArray)
|
1077
|
+
end
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
class << self
|
1081
|
+
def lineplot(*args)
|
1082
|
+
plt = GR::Plot.new(*args)
|
1083
|
+
plt.plot_data
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
def stepplot(*args)
|
1087
|
+
plt = GR::Plot.new(*args)
|
1088
|
+
plt.kvs[:kind] = :step
|
1089
|
+
plt.plot_data
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
def scatterplot(*args)
|
1093
|
+
plt = GR::Plot.new(*args)
|
1094
|
+
plt.kvs[:kind] = :scatter
|
1095
|
+
plt.plot_data
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
def scatterplot3(*args)
|
1099
|
+
plt = GR::Plot.new(*args)
|
1100
|
+
plt.kvs[:kind] = :scatter3
|
1101
|
+
plt.plot_data
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
def stemplot(*args)
|
1105
|
+
plt = GR::Plot.new(*args)
|
1106
|
+
plt.kvs[:kind] = :stem
|
1107
|
+
plt.plot_data
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
def histogram(x, kv = {})
|
1111
|
+
plt = GR::Plot.new(x, kv)
|
1112
|
+
plt.kvs[:kind] = :hist
|
1113
|
+
nbins = plt.kvs[:nbins] || 0
|
1114
|
+
x, y = hist(x, nbins)
|
1115
|
+
plt.args = [[x, y, nil, nil, '']]
|
1116
|
+
plt.plot_data
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
# def polarhistogram(x, kv = {})
|
1120
|
+
# plt = GR::Plot.new(x, kv)
|
1121
|
+
# plt.kvs[:kind] = :polarhist
|
1122
|
+
# nbins = plt.kvs[:nbins] || 0
|
1123
|
+
# x, y = hist(x, nbins)
|
1124
|
+
# plt.args = [[x, y, nil, nil, '']]
|
1125
|
+
# plt.plot_data
|
1126
|
+
# end
|
1127
|
+
|
1128
|
+
def heatmap(*args)
|
1129
|
+
plt = GR::Plot.new(*args)
|
1130
|
+
plt.kvs[:kind] = :heatmap
|
1131
|
+
# FIXME
|
1132
|
+
if narray?(args.first)
|
1133
|
+
z = args.first
|
1134
|
+
width, height = z.shape
|
1135
|
+
plt.kvs[:xlim] ||= [0.5, width + 0.5]
|
1136
|
+
plt.kvs[:ylim] ||= [0.5, height + 0.5]
|
1137
|
+
plt.args = [[[*1..width], [*1..height], z, nil, '']]
|
1138
|
+
else
|
1139
|
+
raise 'not implemented'
|
1140
|
+
end
|
1141
|
+
plt.plot_data
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
def polarheatmap(*args)
|
1145
|
+
d = args.shift
|
1146
|
+
# FIXME
|
1147
|
+
z = Numo::DFloat.cast(d)
|
1148
|
+
raise 'expected 2-D array' unless z.ndim == 2
|
1149
|
+
|
1150
|
+
plt = GR::Plot.new(*args)
|
1151
|
+
plt.kvs[:kind] = :polarheatmap
|
1152
|
+
width, height = z.shape
|
1153
|
+
plt.kvs[:xlim] ||= [0.5, width + 0.5]
|
1154
|
+
plt.kvs[:ylim] ||= [0.5, height + 0.5]
|
1155
|
+
plt.args = [[(1..width).to_a, (1..height).to_a, z, nil, '']]
|
1156
|
+
plt.plot_data
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
def contourplot(*args)
|
1160
|
+
kv = if args[-1].is_a? Hash
|
1161
|
+
args.pop
|
1162
|
+
else
|
1163
|
+
{}
|
1164
|
+
end
|
1165
|
+
if args.size == 1
|
1166
|
+
if args[0].is_a? Array
|
1167
|
+
z = Numo::DFloat.cast(args[0])
|
1168
|
+
xsize, ysize = z.shape
|
1169
|
+
elsif narray?(args[0])
|
1170
|
+
z = args[0]
|
1171
|
+
xsize, ysize = z.shape
|
1172
|
+
end
|
1173
|
+
x = (1..xsize).to_a
|
1174
|
+
y = (1..ysize).to_a
|
1175
|
+
elsif args.size == 3
|
1176
|
+
x, y, z = args
|
1177
|
+
else
|
1178
|
+
raise
|
1179
|
+
end
|
1180
|
+
plt = GR::Plot.new(x, y, z, kv)
|
1181
|
+
plt.kvs[:kind] = :contour
|
1182
|
+
plt.plot_data
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
def contourfplot(*args)
|
1186
|
+
kv = if args[-1].is_a? Hash
|
1187
|
+
args.pop
|
1188
|
+
else
|
1189
|
+
{}
|
1190
|
+
end
|
1191
|
+
if args.size == 1
|
1192
|
+
if args[0].is_a? Array
|
1193
|
+
z = Numo::DFloat.cast(args[0])
|
1194
|
+
xsize, ysize = z.shape
|
1195
|
+
elsif narray?(args[0])
|
1196
|
+
z = args[0]
|
1197
|
+
xsize, ysize = z.shape
|
1198
|
+
end
|
1199
|
+
x = (1..xsize).to_a
|
1200
|
+
y = (1..ysize).to_a
|
1201
|
+
elsif args.size == 3
|
1202
|
+
x, y, z = args
|
1203
|
+
else
|
1204
|
+
raise
|
1205
|
+
end
|
1206
|
+
plt = GR::Plot.new(x, y, z, kv)
|
1207
|
+
plt.kvs[:kind] = :contourf
|
1208
|
+
plt.plot_data
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
def hexbinplot(*args)
|
1212
|
+
plt = GR::Plot.new(*args)
|
1213
|
+
plt.kvs[:kind] = :hexbin
|
1214
|
+
plt.plot_data
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
def tricontourplot(*args)
|
1218
|
+
plt = GR::Plot.new(*args)
|
1219
|
+
plt.kvs[:kind] = :tricont
|
1220
|
+
plt.plot_data
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
def surfaceplot(*args)
|
1224
|
+
kv = if args[-1].is_a? Hash
|
1225
|
+
args.pop
|
1226
|
+
else
|
1227
|
+
{}
|
1228
|
+
end
|
1229
|
+
if args.size == 1
|
1230
|
+
if args[0].is_a? Array
|
1231
|
+
z = Numo::DFloat.cast(args[0])
|
1232
|
+
xsize, ysize = z.shape
|
1233
|
+
elsif narray?(args[0])
|
1234
|
+
z = args[0]
|
1235
|
+
xsize, ysize = z.shape
|
1236
|
+
end
|
1237
|
+
x = ([(1..xsize).to_a] * ysize).flatten
|
1238
|
+
y = ((1..ysize).to_a.map { |i| [i] * xsize }).flatten
|
1239
|
+
elsif args.size == 3
|
1240
|
+
x, y, z = args
|
1241
|
+
else
|
1242
|
+
raise
|
1243
|
+
end
|
1244
|
+
plt = GR::Plot.new(x, y, z, kv)
|
1245
|
+
plt.kvs[:kind] = :surface
|
1246
|
+
plt.plot_data
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
def polarplot(*args)
|
1250
|
+
plt = GR::Plot.new(*args)
|
1251
|
+
plt.kvs[:kind] = :polar
|
1252
|
+
plt.plot_data
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
def trisurfaceplot(*args)
|
1256
|
+
plt = GR::Plot.new(*args)
|
1257
|
+
plt.kvs[:kind] = :trisurf
|
1258
|
+
plt.plot_data
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
def wireframe(*args)
|
1262
|
+
plt = GR::Plot.new(*args)
|
1263
|
+
plt.kvs[:kind] = :wireframe
|
1264
|
+
plt.plot_data
|
1265
|
+
end
|
1266
|
+
|
1267
|
+
def lineplot3(*args)
|
1268
|
+
plt = GR::Plot.new(*args)
|
1269
|
+
plt.kvs[:kind] = :plot3
|
1270
|
+
plt.plot_data
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
# Note: GR.shade exists
|
1274
|
+
def shade(*args)
|
1275
|
+
plt = GR::Plot.new(*args)
|
1276
|
+
plt.kvs[:kind] = :shade
|
1277
|
+
plt.plot_data
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
def volumeplot(v, kv = {})
|
1281
|
+
plt = GR::Plot.new(v, kv)
|
1282
|
+
plt.kvs[:kind] = :volume
|
1283
|
+
plt.args = [[nil, nil, v, nil, '']]
|
1284
|
+
plt.plot_data
|
1285
|
+
end
|
1286
|
+
|
1287
|
+
def barplot(labels, heights, kv = {})
|
1288
|
+
wc, hc = barcoordinates(heights)
|
1289
|
+
horizontal = kv[:horizontal] || false
|
1290
|
+
plt = GR::Plot.new(labels, heights, kv)
|
1291
|
+
plt.kvs[:kind] = :bar
|
1292
|
+
if horizontal
|
1293
|
+
plt.args = [[hc, wc, nil, nil, '']]
|
1294
|
+
plt.kvs[:yticks] = [1, 1]
|
1295
|
+
plt.kvs[:yticklabels] = labels
|
1296
|
+
else
|
1297
|
+
plt.args = [[wc, hc, nil, nil, '']]
|
1298
|
+
plt.kvs[:xticks] = [1, 1]
|
1299
|
+
plt.kvs[:xticklabels] = labels
|
1300
|
+
end
|
1301
|
+
plt.plot_data
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
def imshow(img, kv = {})
|
1305
|
+
img = Numo::DFloat.cast(img) # Umm...
|
1306
|
+
plt = GR::Plot.new(kv)
|
1307
|
+
plt.kvs[:kind] = :imshow
|
1308
|
+
plt.args = [[nil, nil, img, nil, '']]
|
1309
|
+
plt.plot_data
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
def isosurface(v, kv = {})
|
1313
|
+
v = Numo::DFloat.cast(v) # Umm...
|
1314
|
+
plt = GR::Plot.new(kv)
|
1315
|
+
plt.kvs[:kind] = :isosurface
|
1316
|
+
plt.args = [[nil, nil, v, nil, '']]
|
1317
|
+
plt.plot_data
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
private
|
1321
|
+
|
1322
|
+
def hist(x, nbins = 0)
|
1323
|
+
nbins = (3.3 * Math.log10(x.length)).round + 1 if nbins <= 1
|
1324
|
+
require 'histogram/array' # dependency
|
1325
|
+
x = x.to_a if narray?(x)
|
1326
|
+
x, y = x.histogram(nbins, bin_boundary: :min)
|
1327
|
+
x.unshift(x.min)
|
1328
|
+
[x, y]
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
def barcoordinates(heights, barwidth = 0.8, baseline = 0.0)
|
1332
|
+
halfw = barwidth / 2.0
|
1333
|
+
wc = []
|
1334
|
+
hc = []
|
1335
|
+
heights.each_with_index do |value, i|
|
1336
|
+
wc << i - halfw
|
1337
|
+
wc << i + halfw
|
1338
|
+
hc << baseline
|
1339
|
+
hc << value
|
1340
|
+
end
|
1341
|
+
[wc, hc]
|
1342
|
+
end
|
1343
|
+
end
|
1344
|
+
end
|