galaaz 0.4.2 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +25 -0
  3. data/Rakefile +8 -0
  4. data/bin/gknit +9 -5
  5. data/bin/gstudio +4 -2
  6. data/bin/gstudio.rb +32 -2
  7. data/blogs/dev/dev.html +219 -34
  8. data/blogs/dev/dev.md +26 -26
  9. data/blogs/dev/dev_files/figure-html/bubble-1.png +0 -0
  10. data/blogs/dev/dev_files/figure-html/diverging_bar.png +0 -0
  11. data/blogs/dplyr/dplyr.rb +63 -0
  12. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +38 -26
  13. data/blogs/galaaz_ggplot/galaaz_ggplot.aux +16 -17
  14. data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
  15. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +65 -31
  16. data/blogs/oh_my/not_so.rb +2342 -0
  17. data/blogs/oh_my/oh_my.Rmd +493 -0
  18. data/blogs/oh_my/oh_my.html +680 -0
  19. data/blogs/oh_my/oh_my.md +597 -0
  20. data/blogs/oh_my/old.Rmd +2100 -0
  21. data/blogs/ruby_plot/figures/facets_with_decorations.png +0 -0
  22. data/blogs/ruby_plot/figures/facets_with_jitter.png +0 -0
  23. data/blogs/ruby_plot/figures/final_box_plot.png +0 -0
  24. data/blogs/ruby_plot/figures/final_violin_plot.png +0 -0
  25. data/blogs/ruby_plot/figures/violin_with_jitter.png +0 -0
  26. data/blogs/ruby_plot/ruby_plot.Rmd +147 -122
  27. data/blogs/ruby_plot/ruby_plot.Rmd_external_figs +662 -0
  28. data/blogs/ruby_plot/ruby_plot.html +49 -54
  29. data/blogs/ruby_plot/ruby_plot.md +147 -122
  30. data/blogs/ruby_plot/ruby_plot.pdf +0 -0
  31. data/blogs/ruby_plot/ruby_plot.tex +776 -157
  32. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.svg +57 -0
  33. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.svg +106 -0
  34. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.svg +110 -0
  35. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.svg +174 -0
  36. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.svg +236 -0
  37. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  38. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.svg +296 -0
  39. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.svg +236 -0
  40. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.svg +218 -0
  41. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.svg +128 -0
  42. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.svg +150 -0
  43. data/examples/islr/ch2.spec.rb +21 -18
  44. data/examples/islr/ch3_boston.rb +14 -5
  45. data/examples/islr/ch3_multiple_regression.rb +2 -3
  46. data/examples/islr/ch6.spec.rb +1 -1
  47. data/examples/islr/x_y_rnorm.jpg +0 -0
  48. data/lib/R_interface/r.rb +14 -10
  49. data/lib/R_interface/r_libs.R +9 -0
  50. data/lib/R_interface/r_methods.rb +77 -6
  51. data/lib/R_interface/{expression.rb → r_module_s.rb} +13 -14
  52. data/lib/R_interface/rbinary_operators.rb +58 -71
  53. data/lib/R_interface/rdata_frame.rb +2 -1
  54. data/lib/R_interface/rdevices.R +4 -0
  55. data/lib/R_interface/rdevices.rb +1 -1
  56. data/lib/R_interface/renvironment.rb +34 -1
  57. data/lib/R_interface/rexpression.rb +108 -2
  58. data/lib/R_interface/rindexed_object.rb +3 -1
  59. data/lib/R_interface/rlanguage.rb +18 -2
  60. data/lib/R_interface/rmatrix.rb +14 -0
  61. data/lib/R_interface/rmd_indexed_object.rb +5 -1
  62. data/lib/R_interface/robject.rb +61 -23
  63. data/lib/R_interface/rsupport.rb +111 -53
  64. data/lib/R_interface/rsymbol.rb +6 -5
  65. data/lib/R_interface/ruby_extensions.rb +130 -4
  66. data/lib/R_interface/runary_operators.rb +35 -3
  67. data/lib/R_interface/rvector.rb +1 -0
  68. data/lib/galaaz.rb +0 -2
  69. data/lib/gknit/knitr_engine.rb +58 -4
  70. data/lib/gknit/ruby_engine.rb +5 -6
  71. data/lib/util/exec_ruby.rb +55 -9
  72. data/specs/all.rb +13 -3
  73. data/specs/figures/dose_len.png +0 -0
  74. data/specs/r_dataframe.spec.rb +49 -26
  75. data/specs/r_environment.spec.rb +140 -0
  76. data/specs/r_eval.spec.rb +0 -15
  77. data/specs/r_formula.spec.rb +232 -0
  78. data/specs/r_function.spec.rb +7 -8
  79. data/specs/r_list.spec.rb +4 -0
  80. data/specs/r_list_apply.spec.rb +11 -11
  81. data/specs/r_matrix.spec.rb +3 -3
  82. data/specs/{r_plots.spec.rb~ → r_nse.spec.rb} +29 -6
  83. data/specs/r_vector_creation.spec.rb +6 -0
  84. data/specs/r_vector_object.spec.rb +2 -2
  85. data/specs/r_vector_operators.spec.rb +3 -3
  86. data/specs/r_vector_subsetting.spec.rb +4 -4
  87. data/specs/ruby_expression.spec.rb +324 -0
  88. data/specs/tmp.rb +12 -524
  89. data/sty/galaaz.sty +71 -0
  90. data/version.rb +1 -1
  91. metadata +31 -41
  92. data/bin/gknit2~ +0 -6
  93. data/bin/ogk~ +0 -4
  94. data/bin/prepareR.rb~ +0 -1
  95. data/blogs/dev/dev.Rmd~ +0 -104
  96. data/blogs/galaaz_ggplot/galaaz_ggplot.dvi +0 -0
  97. data/blogs/galaaz_ggplot/midwest_external_png~ +0 -1
  98. data/blogs/gknit/gknit.Rmd~ +0 -184
  99. data/blogs/gknit/gknit.Rnd~ +0 -17
  100. data/blogs/gknit/model.rb~ +0 -46
  101. data/blogs/ruby_plot/ruby_plot.Rmd~ +0 -215
  102. data/examples/islr/Figure.jpg +0 -0
  103. data/examples/misc/moneyball.rb~ +0 -16
  104. data/examples/misc/subsetting.rb~ +0 -372
  105. data/lib/R/eng_ruby.R~ +0 -63
  106. data/lib/R_interface/capture_plot.rb~ +0 -23
  107. data/lib/R_interface/r.rb~ +0 -121
  108. data/lib/R_interface/rdevices.rb~ +0 -27
  109. data/lib/gknit.rb~ +0 -26
  110. data/lib/gknit/knitr_engine.rb~ +0 -102
  111. data/lib/gknit/ruby_engine.rb~ +0 -72
  112. data/lib/util/inline_file.rb~ +0 -23
  113. data/r_requires/knitr.rb~ +0 -4
  114. data/specs/r_language.spec.rb +0 -157
@@ -0,0 +1,597 @@
1
+ ---
2
+ title: "Extending R with classes, modules, procs, lambdas, oh my!"
3
+ author:
4
+ - "Rodrigo Botafogo"
5
+ - "Daniel Mossé - University of Pittsburgh"
6
+ tags: [Tech, Data Science, Ruby, R, GraalVM]
7
+ date: "November 19th, 2018"
8
+ output:
9
+ html_document:
10
+ self_contained: true
11
+ keep_md: true
12
+ pdf_document:
13
+ includes:
14
+ in_header: "../../sty/galaaz.sty"
15
+ keep_tex: yes
16
+ number_sections: yes
17
+ toc: true
18
+ toc_depth: 2
19
+ fontsize: 11pt
20
+ ---
21
+
22
+
23
+
24
+ # Introduction
25
+
26
+ This paper introduces and compares Galaaz with R's S4. It is a shameless rip off of
27
+ ["A '(not so)' Short Introduction to S4"](https://cran.r-project.org/doc/contrib/Genolini-S4tutorialV0-5en.pdf) by Christophe Genolini and follows the same structure and examples presented there.
28
+
29
+ Galaaz is a Ruby Gem (library) that allows very tight integration between Ruby and R.
30
+ It's integration is much tigher and transparent from what one can get beetween RinRuby
31
+ or similar solutions in Python
32
+ such as [PypeR](https://pypi.python.org/pypi/PypeR/1.1.0), [rpy2](http://rpy2.bitbucket.org/)
33
+ and other similar solutions. Galaaz targets the GraalVM and it
34
+ integrates with FastR, a high performance R interpreter for the GraalVM.
35
+
36
+ GraalVM:
37
+
38
+
39
+ # Bases of Object Programming
40
+
41
+ In this paper, we will start our discussion from Part II of "The (not so) Short Introduction
42
+ to S4", which from now on we will reference as SS4 for "short S4". Interested readers are directed
43
+ to this paper to understand the motivation and examples in that paper. In this paper we will
44
+ present the S4 code from SS4 and then the same code in Ruby/Galaaz. We will not comment on the
45
+ S4 code, as all the comments can be found in SS4, we will only focus on the Ruby/Galaaz
46
+ description.
47
+
48
+ S4 defines classes by using the setClass function:
49
+
50
+ # Classes Declaration
51
+
52
+ ```
53
+ # > setClass(
54
+ # + Class="Trajectories",
55
+ # + representation=representation(
56
+ # + times = "numeric",
57
+ # + traj = "matrix"
58
+ # + )
59
+ # + )
60
+ ```
61
+
62
+ # Instance Variables
63
+
64
+ In Ruby a class is defined by the keyword 'class'. Every class should start with a capital
65
+ letter. S4 'slots' are called 'instance variables' in Ruby. Differently from R's S4,
66
+ instance variables in Ruby do not have type information. It should be clear though, that S4
67
+ type information is also not a "compile" time type, since R is not compiled. The type is
68
+ checked at runtime. The same checking can be done in Ruby and we will do it later in this
69
+ document.
70
+
71
+ In the example bellow, we create
72
+ class Trajectories with two instance variables, 'times' and 'matrix'. We will not go over
73
+ the details of instance variables in Ruby, but here we created those variables with the
74
+ keyword 'attr_reader' and a colom before the variables name:
75
+
76
+
77
+
78
+ ```
79
+ ## class Trajectories
80
+ ## attr_reader :times
81
+ ## attr_reader :matrix
82
+ ## end
83
+ ```
84
+
85
+
86
+ In order to create a new instance of object Trajectories we call method new on the class and
87
+ we can store the result in a varible (not an instance variable) as bellow:
88
+
89
+
90
+ ```
91
+ ## @traj = Trajectories.new
92
+ ```
93
+
94
+ We now have in variable '@traj' a Trajectories object. In Ruby, printing variable 'traj' will
95
+ only print the class name of the object and not it contents as in R.
96
+
97
+
98
+ ```
99
+ ## puts @traj
100
+ ```
101
+
102
+ ```
103
+ ## #<GalaazUtil::Trajectories:0x628>
104
+ ```
105
+
106
+ To see the contents of an object, one needs to access its components using the '.' operator:
107
+
108
+
109
+ ```
110
+ ## puts @traj.times
111
+ ```
112
+
113
+ # Constructor
114
+
115
+ Since there is no content stored in 'times' nor 'matrix', nil is returned. In order to add
116
+ a value in the variables, we need to add a constructor to the class Trajectories. In R, a
117
+ constructor is build by default, in Ruby, this has to be created by adding a method called
118
+ 'initialize'. In the example bellow, we will create the initializer that accepts two values,
119
+ a 'times' value and a 'matrix' value and they are used to initialize the value of the
120
+ instance variables:
121
+
122
+
123
+ ```
124
+ ## class Trajectories
125
+ ##
126
+ ## attr_reader :times
127
+ ## attr_reader :matrix
128
+ ##
129
+ ## #----------------------------------------------------------
130
+ ## # Initializes the Trajectories class. Takes two parameters
131
+ ## # @param times
132
+ ## # @param matrix
133
+ ## #----------------------------------------------------------
134
+ ##
135
+ ## def initialize(times: nil, matrix: nil)
136
+ ## @times = times
137
+ ## @matrix = matrix
138
+ ## end
139
+ ##
140
+ ## end
141
+ ```
142
+
143
+ Up to this point, everything described is pure Ruby code and has absolutely no relationship
144
+ with R.
145
+ We now want to create a Trajectories with a 'times' vector. Ruby has a vector class and we could
146
+ use this class to create a vector and add it to the 'times' instance variable; however, in order
147
+ to make use of R's functions, we want to create a R vector to add to 'times'. In Galaaz,
148
+ creating R objects is done using the corresponding R functions by just preceding them with 'R.',
149
+ i.e., R functions are all defined in Galaaz in the R namespace.
150
+
151
+ Since Galaaz is Ruby and not R, some syntax adjustments are sometimes necessary. For instance,
152
+ in R, a range is represented as '(1:4)', in Ruby, the same range is represented as '(1..4)'.
153
+ When passing arguments to an R function in R one uses the '=' sign after the slot name; in R,
154
+ one uses the ':' operator after parameter's name as we can see bellow:
155
+
156
+
157
+ ```
158
+ ## # Create a Trajectories passing a times vector, but no matrix parameter
159
+ ## @traj = Trajectories.new(times: R.c(1, 2, 3, 4))
160
+ ##
161
+ ## # Create a Trajectories with times and matrix
162
+ ## @traj2 = Trajectories.new(times: R.c(1, 3), matrix: R.matrix((1..4), ncol: 2))
163
+ ```
164
+
165
+ # Access to Instance Variables (to reach a slot)
166
+
167
+ In order to access data in an instance variable the operator '.' is used. In R, a similar
168
+ result is obtained by use of the '@' operator, but SS4 does not recommend its use. In Galaaz,
169
+ the '.' operator is the recommended way of accessing an instance variable.
170
+
171
+ Now that we have created two trajectories, let's try to print its instance variables to see
172
+ that everything is fine:
173
+
174
+
175
+
176
+ ```
177
+ ## puts @traj.times
178
+ ```
179
+
180
+ ```
181
+ ## [1] 1 2 3 4
182
+ ```
183
+
184
+ We now have the expected value. Note that the 'times' vector is printed exactly as it would
185
+ if we were using GNU R. Let's now take a look at variable 'traj2':
186
+
187
+
188
+ ```
189
+ ## puts @traj2.times
190
+ ## puts
191
+ ## puts @traj2.matrix
192
+ ```
193
+
194
+ ```
195
+ ## [1] 1 3
196
+ ##
197
+ ## [,1] [,2]
198
+ ## [1,] 1 3
199
+ ## [2,] 2 4
200
+ ```
201
+
202
+ Let's now build the same examples as in SS4: Three hospitals take part in a
203
+ study. The Pitié Salpêtriere (which has not yet returned its data file, shame on them!),
204
+ Cochin and Saint-Anne. We first show the code in R and the corresponding Galaaz:
205
+
206
+ ```
207
+ > trajPitie <- new(Class="Trajectories")
208
+ > trajCochin <- new(
209
+ + Class= "Trajectories",
210
+ + times=c(1,3,4,5),
211
+ + traj=rbind (
212
+ + c(15,15.1, 15.2, 15.2),
213
+ + c(16,15.9, 16,16.4),
214
+ + c(15.2, NA, 15.3, 15.3),
215
+ + c(15.7, 15.6, 15.8, 16)
216
+ + )
217
+ + )
218
+ > trajStAnne <- new(
219
+ + Class= "Trajectories",
220
+ + times=c(1: 10, (6: 16) *2),
221
+ + traj=rbind(
222
+ + matrix (seq (16,19, length=21), ncol=21, nrow=50, byrow=TRUE),
223
+ + matrix (seq (15.8, 18, length=21), ncol=21, nrow=30, byrow=TRUE)
224
+ + )+rnorm (21*80,0,0.2)
225
+ + )
226
+ ```
227
+
228
+ This same code in Galaaz becomes:
229
+
230
+
231
+ ```
232
+ ## @trajPitie = Trajectories.new
233
+ ##
234
+ ## @trajCochin = Trajectories.new(times: R.c(1,3,4,5),
235
+ ## matrix: R.rbind(
236
+ ## R.c(15,15.1, 15.2, 15.2),
237
+ ## R.c(16,15.9, 16,16.4),
238
+ ## R.c(15.2, R::NA, 15.3, 15.3),
239
+ ## R.c(15.7, 15.6, 15.8, 16)))
240
+ ##
241
+ ## @trajStAnne =
242
+ ## Trajectories.new(times: R.c((1..10), R.c(6..16) * 2),
243
+ ## matrix: (R.rbind(
244
+ ## R.matrix(R.seq(16, 19, length: 21), ncol: 21,
245
+ ## nrow: 50, byrow: true),
246
+ ## R.matrix(R.seq(15.8, 18, length: 21), ncol: 21,
247
+ ## nrow: 30, byrow: true)) + R.rnorm(21*80, 0, 0.2)))
248
+ ```
249
+
250
+ Let's check that the 'times' and 'matrix' instance variables were correctly set:
251
+
252
+
253
+ ```
254
+ ## puts @trajCochin.times
255
+ ## puts
256
+ ## puts @trajCochin.matrix
257
+ ## puts
258
+ ## puts @trajStAnne.times
259
+ ```
260
+
261
+ ```
262
+ ## [1] 1 3 4 5
263
+ ##
264
+ ## [,1] [,2] [,3] [,4]
265
+ ## [1,] 15.0 15.1 15.2 15.2
266
+ ## [2,] 16.0 15.9 16.0 16.4
267
+ ## [3,] 15.2 NA 15.3 15.3
268
+ ## [4,] 15.7 15.6 15.8 16.0
269
+ ##
270
+ ## [1] 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30 32
271
+ ```
272
+
273
+ We will not at this time print trajStAnne.matrix, since this is a huge matrix and the result
274
+ would just take too much space. Later we will print just a partial view of the matrix.
275
+
276
+ # Default Values
277
+
278
+ Default values are very useful and quite often used in Ruby programs. Although SS4 does not
279
+ recommend its use, there are many cases in which default values are useful and make code simpler.
280
+ We have already seen default values in this document, with the default being 'nil'. This was
281
+ necessary in order to be able to create our constructor and passing it the proper values.
282
+
283
+ In the example bellow, a class TrajectoriesBis is created with default value 1 for times and a
284
+ matrix with no elements in matrix.
285
+
286
+
287
+ ```
288
+ ## class TrajectoriesBis
289
+ ##
290
+ ## attr_reader :times
291
+ ## attr_reader :matrix
292
+ ##
293
+ ## #----------------------------------------------------------
294
+ ## # Initializes the Trajectories class. Takes two parameters
295
+ ## # @param times
296
+ ## # @param matrix
297
+ ## #----------------------------------------------------------
298
+ ##
299
+ ## def initialize(times: 1, matrix: R.matrix(0))
300
+ ## @times = times
301
+ ## @matrix = matrix
302
+ ## end
303
+ ##
304
+ ## end
305
+ ##
306
+ ## @traj_bis = TrajectoriesBis.new
307
+ ```
308
+
309
+ Let's take a look at our new class:
310
+
311
+
312
+ ```
313
+ ## puts @traj_bis.times
314
+ ## puts
315
+ ## puts @traj_bis.matrix
316
+ ```
317
+
318
+ ```
319
+ ## 1
320
+ ##
321
+ ## [,1]
322
+ ## [1,] 0
323
+ ```
324
+
325
+ Note that '@traj_bis.times' is the numeric 1, and what we actually want is a vector
326
+ with [1] in it.
327
+
328
+
329
+ ```
330
+ ## class TrajectoriesBis
331
+ ##
332
+ ## attr_reader :times
333
+ ## attr_reader :matrix
334
+ ##
335
+ ## #----------------------------------------------------------
336
+ ## # Initializes the Trajectories class. Takes two parameters
337
+ ## # @param times [R::Vector] should be an R vector.
338
+ ## # @param matrix [R::Matrix] should be an R matrix.
339
+ ## #----------------------------------------------------------
340
+ ##
341
+ ## # Use R.c to convert number 1 to a vector
342
+ ## def initialize(times: R.c(1), matrix: R.matrix(0))
343
+ ## @times = times
344
+ ## @matrix = matrix
345
+ ## end
346
+ ##
347
+ ## end
348
+ ##
349
+ ## @traj_bis = TrajectoriesBis.new
350
+ ```
351
+
352
+
353
+ ```
354
+ ## puts @traj_bis.times
355
+ ## puts
356
+ ## puts @traj_bis.matrix
357
+ ```
358
+
359
+ ```
360
+ ## [1] 1
361
+ ##
362
+ ## [,1]
363
+ ## [1,] 0
364
+ ```
365
+
366
+
367
+ # The Empty Object
368
+
369
+ When a Trajectories is created with new, and no argument is given, all its instance variables
370
+ will have the default nil value. Since Ruby has no type information, then there is only one
371
+ type (or actually no type) of nil. To check if a variable is empty, we check it against the nil
372
+ value.
373
+
374
+ # To See an Object
375
+
376
+ Ruby has very strong meta-programming features, in particular, one can use introspection to
377
+ see methods and instance variables from a given class. Method 'instance_variables' shows all
378
+ the instance variables of an object:
379
+
380
+ ```
381
+ puts @traj.instance_variables
382
+ ```
383
+
384
+ The description of all meta-programming features of Ruby is well beyond the scope of this
385
+ document, but it is a very frequent a powerful feature of Ruby, that makes programming in
386
+ Ruby a different experience than programming in other languages.
387
+
388
+ # Methods
389
+
390
+ Methods are a fundamental feature of object oriented programming. We will now extend our class
391
+ Trajectories to add methods to it. In SS4, a method 'plot' is added to Trajectories. At this
392
+ point, Renjin and Galaaz do not yet have plotting capabilities, so we will have to skip this
393
+ method and go directly to the implementation of the 'print' method.
394
+
395
+ Bellow is the R code for method print:
396
+
397
+ ```
398
+ > setMethod ("print","Trajectories",
399
+ + function(x,...){
400
+ + cat("*** Class Trajectories, method Print *** \\n")
401
+ + cat("* Times ="); print (x@times)
402
+ + cat("* Traj = \\n"); print (x@traj)
403
+ + cat("******* End Print (trajectories) ******* \\n")
404
+ + }
405
+ + )
406
+ ```
407
+
408
+ Now the same code for class Trajectories in Galaaz. In general methods are defined in a class
409
+ together with all the class definition. We will first use this approach. Later, we will show
410
+ how to 'reopen' a class to add new methods to it.
411
+
412
+ In this example, we are defining a method named 'print'. We have being using method 'puts' to
413
+ output data. There is a Ruby method that is more flexible than puts and that we need to use to
414
+ implement our function: 'print'. However, trying to use Ruby print inside the definition of
415
+ Trajectories's print will not work, as Ruby will understand that as a recursive call to print.
416
+ Ruby's print is defined inside the Kernel class, so, in order to call Ruby's print inside the
417
+ definition of Trajectories's print we need to write 'Kernel.print'.
418
+
419
+
420
+ ```
421
+ ## class Trajectories
422
+ ##
423
+ ## attr_reader :times
424
+ ## attr_reader :matrix
425
+ ##
426
+ ##
427
+ ## #----------------------------------------------------------
428
+ ## # Initializes the Trajectories class. Takes two parameters
429
+ ## # @param times [R::Vector] should be an R vector.
430
+ ## # @param matrix [R::Matrix] should be an R matrix.
431
+ ## #----------------------------------------------------------
432
+ ##
433
+ ## def initialize(times: nil, matrix: nil)
434
+ ## @times = times
435
+ ## @matrix = matrix
436
+ ## end
437
+ ##
438
+ ## #----------------------------------------------------------
439
+ ## #
440
+ ## #----------------------------------------------------------
441
+ ##
442
+ ## def print
443
+ ## puts("*** Class Trajectories, method Print *** ")
444
+ ## Kernel.print("times = ")
445
+ ## puts @times
446
+ ## puts("traj =")
447
+ ## puts @matrix
448
+ ## puts("******* End Print (trajectories) ******* ")
449
+ ## end
450
+ ##
451
+ ## end
452
+ ```
453
+
454
+
455
+ ```
456
+ ## @trajCochin.print
457
+ ```
458
+
459
+ ```
460
+ ## *** Class Trajectories, method Print ***
461
+ ## times = [1] 1 3 4 5
462
+ ## traj =
463
+ ## [,1] [,2] [,3] [,4]
464
+ ## [1,] 15.0 15.1 15.2 15.2
465
+ ## [2,] 16.0 15.9 16.0 16.4
466
+ ## [3,] 15.2 NA 15.3 15.3
467
+ ## [4,] 15.7 15.6 15.8 16.0
468
+ ## ******* End Print (trajectories) *******
469
+ ```
470
+
471
+ For Cochin, the result is correct. For Saint-Anne, print will display too much
472
+ information. So we need a second method.
473
+
474
+ Show is the default R method used to show an object when its name is written in the
475
+ console. We thus define 'show' by taking into account the size of the object: if there are too
476
+ many trajectories, 'show' posts only part of them.
477
+
478
+ Here is the R code for method 'show':
479
+
480
+ ```
481
+ > setMethod("show","Trajectories",
482
+ + function(object){
483
+ + cat("*** Class Trajectories, method Show *** \\n")
484
+ + cat("* Times ="); print(object@times)
485
+ + nrowShow <- min(10,nrow(object@traj))
486
+ + ncolShow <- min(10,ncol(object@traj))
487
+ + cat("* Traj (limited to a matrix 10x10) = \\n")
488
+ + print(formatC(object@traj[1:nrowShow,1:ncolShow]),quote=FALSE)
489
+ + cat("******* End Show (trajectories) ******* \\n")
490
+ + }
491
+ + )
492
+ ```
493
+
494
+ Now, let's write it with Galaaz. This time though, we will not rewrite the whole Trajectories
495
+ class, but just reopen it to add this specific method. The next example has many interesting
496
+ features of Galaaz, some we have already seen, others will be described now:
497
+
498
+ * As we have already seen, to call an R function one uses the R.<function> notation. There
499
+ is however another way: when the first argument to the R function is an R object such as a
500
+ matrix, a list, a vector, etc. we can use '.' notation to call the function. This makes the
501
+ function look like a method of the object. For instance, R.nrow(@matrix), can be called by
502
+ doing @matrix.nrow;
503
+
504
+ * In R, every number is converted to a vector and this can be done with method R.i. Converting
505
+ a vector with only one number back to a number can be done with method '.gz'. So if @num is
506
+ an R vector that holds a number, then @num.gz is a number that can be used normally with Ruby
507
+ methods;
508
+
509
+ * R functions and Ruby methods can be used freely in Galaaz. We show bellow two different ways
510
+ of getting the minimum of a number, either by calling R.min or by getting the minimum of an
511
+ array, with the min method;
512
+
513
+ * Galaaz allows for method 'chaining'. Method chaining, also known as named parameter idiom, is
514
+ a common syntax for invoking multiple method calls in object-oriented programming languages.
515
+ Each method returns an object, allowing the calls to be chained together in a single statement
516
+ without requiring variables to store the intermediate results. For instance @matrix.nrow.gz,
517
+ which returns the number of rows of the matrix as a number;
518
+
519
+ * Ranges in Ruby are represented by (x..y), where x is the beginning of the range and y its end.
520
+ An R matrix can be indexed by range, object@traj[1:nrowShow,1:ncolShow], the same result is
521
+ obtained in Galaaz by indexing @matrix[(1..nrow_show), (1..ncol_show)]. Observe that this
522
+ statement is then chained with the format function and with the pp method to print the matrix.
523
+
524
+
525
+
526
+ ```
527
+ ## class Trajectories
528
+ ##
529
+ ## #----------------------------------------------------------
530
+ ## #
531
+ ## #----------------------------------------------------------
532
+ ##
533
+ ## def show
534
+ ## puts("*** Class Trajectories, method Show *** ")
535
+ ## Kernel.print("times = ")
536
+ ## puts @times
537
+ ## nrow_show = [10, @matrix.nrow << 0].min
538
+ ## ncol_show = R.min(10, @matrix.ncol) << 0
539
+ ## puts("* Traj (limited to a matrix 10x10) = ")
540
+ ## puts @matrix[(1..nrow_show), (1..ncol_show)].format(digits: 2, nsmall: 2)
541
+ ## puts("******* End Show (trajectories) ******* ")
542
+ ## end
543
+ ##
544
+ ## end
545
+ ```
546
+
547
+
548
+ ```
549
+ ## @trajStAnne.show
550
+ ```
551
+
552
+ ```
553
+ ## *** Class Trajectories, method Show ***
554
+ ## times = [1] 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30 32
555
+ ## * Traj (limited to a matrix 10x10) =
556
+ ## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
557
+ ## [1,] "16.20" "15.61" "16.22" "16.34" "16.16" "16.75" "16.72" "17.25"
558
+ ## [2,] "15.65" "16.44" "16.32" "16.58" "16.78" "17.04" "17.00" "16.88"
559
+ ## [3,] "16.12" "16.23" "16.42" "16.51" "16.67" "16.77" "17.05" "16.98"
560
+ ## [4,] "15.82" "16.22" "16.48" "16.79" "16.52" "16.71" "16.90" "17.06"
561
+ ## [5,] "15.92" "16.39" "16.33" "16.61" "16.56" "16.81" "16.76" "17.25"
562
+ ## [6,] "15.89" "16.03" "16.43" "16.09" "16.70" "16.80" "17.06" "16.95"
563
+ ## [7,] "15.83" "16.03" "16.43" "16.79" "16.27" "16.79" "16.68" "16.98"
564
+ ## [8,] "15.90" "16.38" "16.27" "16.59" "16.41" "16.17" "16.91" "17.22"
565
+ ## [9,] "15.90" "15.83" "16.50" "16.24" "16.46" "16.52" "16.65" "16.94"
566
+ ## [10,] "15.99" "15.94" "16.70" "16.41" "16.51" "16.62" "16.98" "16.67"
567
+ ## [,9] [,10]
568
+ ## [1,] "17.17" "16.92"
569
+ ## [2,] "17.23" "17.46"
570
+ ## [3,] "17.13" "17.17"
571
+ ## [4,] "17.31" "17.39"
572
+ ## [5,] "17.17" "17.63"
573
+ ## [6,] "17.31" "17.05"
574
+ ## [7,] "17.11" "17.54"
575
+ ## [8,] "17.55" "17.58"
576
+ ## [9,] "16.86" "16.85"
577
+ ## [10,] "17.65" "17.45"
578
+ ## ******* End Show (trajectories) *******
579
+ ```
580
+
581
+ Our show method has the same problem as SS4, i.e., if an empty trajectories object is created and
582
+ we try to 'show' it, it will generate an error. Let's see it:
583
+
584
+
585
+ ```
586
+ ## @empty_traj = Trajectories.new
587
+ ```
588
+
589
+
590
+ ```
591
+ ## @empty_traj.show
592
+ ```
593
+
594
+ ```
595
+ ## undefined method `nrow' for nil:NilClass
596
+ ```
597
+