galaaz 0.4.7 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1179 -39
  3. data/Rakefile +4 -2
  4. data/bin/grun +1 -1
  5. data/bin/gstudio +1 -1
  6. data/blogs/dev/dev.Rmd +2 -56
  7. data/blogs/dev/dev.md +32 -61
  8. data/blogs/dev/dev2.Rmd +65 -0
  9. data/blogs/dplyr/dplyr.Rmd +29 -0
  10. data/blogs/{dev/dev.html → dplyr/dplyr.html} +88 -57
  11. data/blogs/dplyr/dplyr.md +58 -0
  12. data/blogs/gknit/gknit.html +1262 -25
  13. data/blogs/gknit/gknit.md +471 -27
  14. data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
  15. data/blogs/manual/graph.rb +29 -0
  16. data/blogs/manual/manual.Rmd +567 -29
  17. data/blogs/manual/manual.html +743 -46
  18. data/blogs/manual/manual.md +1179 -39
  19. data/blogs/nse_dplyr/nse_dplyr.Rmd +466 -11
  20. data/blogs/nse_dplyr/nse_dplyr.html +472 -37
  21. data/blogs/nse_dplyr/nse_dplyr.md +645 -32
  22. data/blogs/ruby_plot/ruby_plot.Rmd +4 -4
  23. data/blogs/ruby_plot/ruby_plot.html +217 -2
  24. data/blogs/ruby_plot/ruby_plot.md +226 -1
  25. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  26. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.svg +2 -2
  27. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  28. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.svg +70 -70
  29. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  30. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.svg +72 -72
  31. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  32. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.svg +116 -116
  33. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  34. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.svg +176 -176
  35. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  36. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  37. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.svg +236 -236
  38. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  39. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.svg +176 -176
  40. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  41. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.svg +160 -160
  42. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  43. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.svg +105 -105
  44. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  45. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.svg +121 -121
  46. data/examples/islr/ch2.spec.rb +1 -1
  47. data/examples/islr/ch3_boston.rb +4 -4
  48. data/examples/islr/x_y_rnorm.jpg +0 -0
  49. data/lib/R_interface/r.rb +1 -1
  50. data/lib/R_interface/r_methods.rb +2 -2
  51. data/lib/R_interface/rdata_frame.rb +8 -5
  52. data/lib/R_interface/rindexed_object.rb +1 -2
  53. data/lib/R_interface/rlist.rb +1 -0
  54. data/lib/R_interface/robject.rb +0 -1
  55. data/lib/R_interface/rpkg.rb +14 -6
  56. data/lib/R_interface/rsupport.rb +7 -9
  57. data/lib/R_interface/ruby_extensions.rb +17 -5
  58. data/lib/gknit/knitr_engine.rb +9 -2
  59. data/lib/util/exec_ruby.rb +2 -2
  60. data/specs/r_dataframe.spec.rb +173 -0
  61. data/specs/r_list.spec.rb +4 -4
  62. data/specs/ruby_expression.spec.rb +2 -11
  63. data/specs/tmp.rb +76 -34
  64. data/version.rb +1 -1
  65. metadata +17 -6
  66. data/blogs/dev/dev_files/figure-html/bubble-1.png +0 -0
  67. data/blogs/dev/dev_files/figure-html/diverging_bar. +0 -0
  68. data/blogs/dev/dev_files/figure-html/diverging_bar.png +0 -0
@@ -283,6 +283,9 @@ img {
283
283
  button.code-folding-btn:focus {
284
284
  outline: none;
285
285
  }
286
+ summary {
287
+ display: list-item;
288
+ }
286
289
  </style>
287
290
 
288
291
 
@@ -290,10 +293,71 @@ button.code-folding-btn:focus {
290
293
  <div class="container-fluid main-container">
291
294
 
292
295
  <!-- tabsets -->
296
+
297
+ <style type="text/css">
298
+ .tabset-dropdown > .nav-tabs {
299
+ display: inline-table;
300
+ max-height: 500px;
301
+ min-height: 44px;
302
+ overflow-y: auto;
303
+ background: white;
304
+ border: 1px solid #ddd;
305
+ border-radius: 4px;
306
+ }
307
+
308
+ .tabset-dropdown > .nav-tabs > li.active:before {
309
+ content: "";
310
+ font-family: 'Glyphicons Halflings';
311
+ display: inline-block;
312
+ padding: 10px;
313
+ border-right: 1px solid #ddd;
314
+ }
315
+
316
+ .tabset-dropdown > .nav-tabs.nav-tabs-open > li.active:before {
317
+ content: "";
318
+ border: none;
319
+ }
320
+
321
+ .tabset-dropdown > .nav-tabs.nav-tabs-open:before {
322
+ content: "";
323
+ font-family: 'Glyphicons Halflings';
324
+ display: inline-block;
325
+ padding: 10px;
326
+ border-right: 1px solid #ddd;
327
+ }
328
+
329
+ .tabset-dropdown > .nav-tabs > li.active {
330
+ display: block;
331
+ }
332
+
333
+ .tabset-dropdown > .nav-tabs > li > a,
334
+ .tabset-dropdown > .nav-tabs > li > a:focus,
335
+ .tabset-dropdown > .nav-tabs > li > a:hover {
336
+ border: none;
337
+ display: inline-block;
338
+ border-radius: 4px;
339
+ }
340
+
341
+ .tabset-dropdown > .nav-tabs.nav-tabs-open > li {
342
+ display: block;
343
+ float: none;
344
+ }
345
+
346
+ .tabset-dropdown > .nav-tabs > li {
347
+ display: none;
348
+ }
349
+ </style>
350
+
293
351
  <script>
294
352
  $(document).ready(function () {
295
353
  window.buildTabsets("TOC");
296
354
  });
355
+
356
+ $(document).ready(function () {
357
+ $('.tabset-dropdown > .nav-tabs > li').click(function () {
358
+ $(this).parent().toggleClass('nav-tabs-open')
359
+ });
360
+ });
297
361
  </script>
298
362
 
299
363
  <!-- code folding -->
@@ -302,7 +366,6 @@ $(document).ready(function () {
302
366
 
303
367
 
304
368
 
305
-
306
369
  <div class="fluid-row" id="header">
307
370
 
308
371
 
@@ -382,10 +445,18 @@ $(document).ready(function () {
382
445
  </blockquote></li>
383
446
  </ul>
384
447
  </div>
385
- <div id="basic-types" class="section level1">
386
- <h1>Basic Types</h1>
387
- <div id="vectors" class="section level2">
388
- <h2>Vectors</h2>
448
+ <div id="gknitting-a-document" class="section level1">
449
+ <h1>gKnitting a Document</h1>
450
+ <p>This manual has been formatted usign gKnit. gKnit uses Knitr and R markdown to knit a document in Ruby or R and output it in any of the available formats for R markdown.<br />
451
+ gKnit runs atop of GraalVM, and Galaaz. In gKnit, Ruby variables are persisted between chunks, making it an ideal solution for literate programming.<br />
452
+ Also, since it is based on Galaaz, Ruby chunks can have access to R variables and Polyglot Programming with Ruby and R is quite natural.</p>
453
+ <p>gknit was describe in more depth in:</p>
454
+ <ul>
455
+ <li>xxx.xxxx.xxx</li>
456
+ </ul>
457
+ </div>
458
+ <div id="vector" class="section level1">
459
+ <h1>Vector</h1>
389
460
  <p>Vectors can be thought of as contiguous cells containing data. Cells are accessed through indexing operations such as x[5]. Galaaz has six basic (‘atomic’) vector types: logical, integer, real, complex, string (or character) and raw. The modes and storage modes for the different vector types are listed in the following table.</p>
390
461
  <table>
391
462
  <thead>
@@ -433,8 +504,8 @@ $(document).ready(function () {
433
504
  <pre class="ruby"><code>@vec = R.c(1, 2, 3)
434
505
  puts @vec</code></pre>
435
506
  <pre><code>## [1] 1 2 3</code></pre>
436
- <p>Lets take a look at the type, mode and storage.mode of our vector <span class="citation">@vec</span>. In order to print this out, we are creating a data frame ‘df’ and printing it out. A data frame, for those not familiar with it, it basically a table. Here we create the data frame and add the column name by passing named parameters for each column, such as ‘typeof:’, ‘mode:’ and ’storage__mode’. You should also note here that the double underscore is converted to a ‘.’.</p>
437
- <p>In R, the method used to create a data frame is ‘data.frame’, in Galaaz we use data__frame’.</p>
507
+ <p>Lets take a look at the type, mode and storage.mode of our vector <span class="citation">@vec</span>. In order to print this out, we are creating a data frame ‘df’ and printing it out. A data frame, for those not familiar with it, is basically a table. Here we create the data frame and add the column name by passing named parameters for each column, such as ‘typeof:’, ‘mode:’ and ’storage__mode?‘. You should also note here that the double underscore is converted to a’.’. So, when printed ‘storage__mode’ will actually print as ‘storage.mode’.</p>
508
+ <p>Data frames will later be more carefully described. In R, the method used to create a data frame is ‘data.frame’, in Galaaz we use data__frame’.</p>
438
509
  <pre class="ruby"><code>df = R.data__frame(typeof: @vec.typeof, mode: @vec.mode, storage__mode: @vec.storage__mode)
439
510
  puts df</code></pre>
440
511
  <pre><code>## typeof mode storage.mode
@@ -479,23 +550,104 @@ double
479
550
  ## undefined local variable or method `hello' for RubyChunk:Class</code></pre>
480
551
  <pre><code>## Message:
481
552
  ## (eval):1:in `exec_ruby'
482
- ## /home/rbotafogo/desenv/galaaz/lib/util/exec_ruby.rb:137:in `instance_eval'
483
- ## /home/rbotafogo/desenv/galaaz/lib/util/exec_ruby.rb:137:in `exec_ruby'
484
- ## /home/rbotafogo/desenv/galaaz/lib/gknit/ruby_engine.rb:55:in `block in initialize'
553
+ ## /home/rbotafogo/desenv/galaaz/lib/util/exec_ruby.rb:141:in `instance_eval'
554
+ ## /home/rbotafogo/desenv/galaaz/lib/util/exec_ruby.rb:141:in `exec_ruby'
555
+ ## /home/rbotafogo/desenv/galaaz/lib/gknit/knitr_engine.rb:657:in `block in initialize'
485
556
  ## /home/rbotafogo/desenv/galaaz/lib/R_interface/ruby_callback.rb:77:in `call'
486
557
  ## /home/rbotafogo/desenv/galaaz/lib/R_interface/ruby_callback.rb:77:in `callback'
487
558
  ## (eval):3:in `function(...) {\n rb_method(...)'
488
559
  ## unknown.r:1:in `in_dir'
489
- ## unknown.r:1:in `block_exec'
490
- ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc12/jre/languages/R/library/knitr/R/block.R:91:in `call_block'
491
- ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc12/jre/languages/R/library/knitr/R/block.R:6:in `process_group.block'
492
- ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc12/jre/languages/R/library/knitr/R/block.R:3:in `&lt;no source&gt;'
560
+ ## unknown.r:1:in `block_exec:BLOCK0'
561
+ ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc15/jre/languages/R/library/knitr/R/block.R:102:in `block_exec'
562
+ ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc15/jre/languages/R/library/knitr/R/block.R:92:in `call_block'
563
+ ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc15/jre/languages/R/library/knitr/R/block.R:6:in `process_group.block'
564
+ ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc15/jre/languages/R/library/knitr/R/block.R:3:in `&lt;no source&gt;'
493
565
  ## unknown.r:1:in `withCallingHandlers'
494
566
  ## unknown.r:1:in `process_file'
495
- ## unknown.r:1:in `&lt;no source&gt;'
496
- ## unknown.r:1:in `&lt;no source&gt;'
497
- ## &lt;REPL&gt;:4:in `&lt;repl wrapper&gt;'
567
+ ## unknown.r:1:in `&lt;no source&gt;:BLOCK1'
568
+ ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc15/jre/languages/R/library/knitr/R/output.R:129:in `&lt;no source&gt;'
569
+ ## unknown.r:1:in `&lt;no source&gt;:BLOCK1'
570
+ ## /home/rbotafogo/lib/graalvm-ce-1.0.0-rc15/jre/languages/R/library/rmarkdown/R/render.R:162:in `&lt;no source&gt;'
571
+ ## &lt;REPL&gt;:5:in `&lt;repl wrapper&gt;'
498
572
  ## &lt;REPL&gt;:1</code></pre>
573
+ <p>Here is a vector with logical values</p>
574
+ <pre class="ruby"><code>@vec = R.c(true, true, false, false, true)
575
+ puts @vec</code></pre>
576
+ <pre><code>## [1] TRUE TRUE FALSE FALSE TRUE</code></pre>
577
+ <div id="combining-vectors" class="section level2">
578
+ <h2>Combining Vectors</h2>
579
+ <p>The ‘c’ functions used to create vectors can also be used to combine two vectors:</p>
580
+ <pre class="ruby"><code>@vec1 = R.c(10.0, 20.0, 30.0)
581
+ @vec2 = R.c(4.0, 5.0, 6.0)
582
+ @vec = R.c(@vec1, @vec2)
583
+ puts @vec</code></pre>
584
+ <pre><code>## [1] 10 20 30 4 5 6</code></pre>
585
+ <p>In galaaz, methods can be chainned (somewhat like the pipe operator in R %&gt;%, but more generic). In this next example, method ‘c’ is chainned after ‘<span class="citation">@vec1</span>’. This also looks like ‘c’ is a method of the vector, but in reallity, this is actually closer to the pipe operator. When Galaaz identifies that ‘c’ is not a method of ‘vec’ it actually tries to call ‘R.c’ with ‘<span class="citation">@vec1</span>’ as the first argument concatenated with all the other available arguments. The code bellow is automatically converted to the code above.</p>
586
+ <pre class="ruby"><code>@vec = @vec1.c(@vec2)
587
+ puts @vec</code></pre>
588
+ <pre><code>## [1] 10 20 30 4 5 6</code></pre>
589
+ </div>
590
+ <div id="vector-arithmetic" class="section level2">
591
+ <h2>Vector Arithmetic</h2>
592
+ <p>Arithmetic operations on vectors are performed element by element:</p>
593
+ <pre class="ruby"><code>puts @vec1 + @vec2</code></pre>
594
+ <pre><code>## [1] 14 25 36</code></pre>
595
+ <pre class="ruby"><code>puts @vec1 * 5</code></pre>
596
+ <pre><code>## [1] 50 100 150</code></pre>
597
+ <p>When vectors have different length, a recycling rule is applied to the shorter vector:</p>
598
+ <pre class="ruby"><code>@vec3 = R.c(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
599
+ puts @vec4 = @vec1 + @vec3</code></pre>
600
+ <pre><code>## [1] 11 22 33 14 25 36 17 28 39</code></pre>
601
+ </div>
602
+ <div id="vector-indexing" class="section level2">
603
+ <h2>Vector Indexing</h2>
604
+ <p>Vectors can be indexed by using the ‘[]’ operator:</p>
605
+ <pre class="ruby"><code>puts @vec4[3]</code></pre>
606
+ <pre><code>## [1] 33</code></pre>
607
+ <p>We can also index a vector with another vector. For example, in the code bellow, we take elements 1, 3, 5, and 7 from <span class="citation">@vec3</span>:</p>
608
+ <pre class="ruby"><code>puts @vec4[R.c(1, 3, 5, 7)]</code></pre>
609
+ <pre><code>## [1] 11 33 25 17</code></pre>
610
+ <p>Repeating an index and having indices out of order is valid code:</p>
611
+ <pre class="ruby"><code>puts @vec4[R.c(1, 3, 3, 1)]</code></pre>
612
+ <pre><code>## [1] 11 33 33 11</code></pre>
613
+ <p>It is also possible to index a vector with a negative number or negative vector. In these cases the indexed values are not returned:</p>
614
+ <pre class="ruby"><code>puts @vec4[-3]
615
+ puts @vec4[-R.c(1, 3, 5, 7)]</code></pre>
616
+ <pre><code>## [1] 11 22 14 25 36 17 28 39
617
+ ## [1] 22 14 36 28 39</code></pre>
618
+ <p>If an index is out of range, a missing value (NA) will be reported.</p>
619
+ <pre class="ruby"><code>puts @vec4[30]</code></pre>
620
+ <pre><code>## [1] NA</code></pre>
621
+ <p>It is also possible to index a vector by range:</p>
622
+ <pre class="ruby"><code>puts @vec4[(2..5)]</code></pre>
623
+ <pre><code>## [1] 22 33 14 25</code></pre>
624
+ <p>Elements in a vector can be named using the ‘names’ attribute of a vector:</p>
625
+ <pre class="ruby"><code>full_name = R.c(&quot;Rodrigo&quot;, &quot;A&quot;, &quot;Botafogo&quot;)
626
+ full_name.names = R.c(&quot;First&quot;, &quot;Middle&quot;, &quot;Last&quot;)
627
+ puts full_name</code></pre>
628
+ <pre><code>## First Middle Last
629
+ ## &quot;Rodrigo&quot; &quot;A&quot; &quot;Botafogo&quot;</code></pre>
630
+ <p>Or it can also be named by using the ‘c’ function with named paramenters:</p>
631
+ <pre class="ruby"><code>full_name = R.c(First: &quot;Rodrigo&quot;, Middle: &quot;A&quot;, Last: &quot;Botafogo&quot;)
632
+ puts full_name</code></pre>
633
+ <pre><code>## First Middle Last
634
+ ## &quot;Rodrigo&quot; &quot;A&quot; &quot;Botafogo&quot;</code></pre>
635
+ </div>
636
+ <div id="extracting-native-ruby-types-from-a-vector" class="section level2">
637
+ <h2>Extracting Native Ruby Types from a Vector</h2>
638
+ <p>Vectors created with ‘R.c’ are of class R::Vector. You might have noticed that when indexing a vector, a new vector is returned, even if this vector has one single element. In order to use R::Vector with other ruby classes it might be necessary to extract the actual Ruby native type from the vector. In order to do this extraction the ‘&gt;&gt;’ operator is used.</p>
639
+ <pre class="ruby"><code>puts @vec4
640
+ puts @vec4 &gt;&gt; 0
641
+ puts @vec4 &gt;&gt; 4</code></pre>
642
+ <pre><code>## [1] 11 22 33 14 25 36 17 28 39
643
+ ## 11.0
644
+ ## 25.0</code></pre>
645
+ <p>Note that indexing with ‘&gt;&gt;’ starts at 0 and not at 1, also, we cannot do negative indexing.</p>
646
+ </div>
647
+ </div>
648
+ <div id="accessing-r-variables" class="section level1">
649
+ <h1>Accessing R variables</h1>
650
+ <p>Galaaz allows Ruby to access variables created in R. For example, the ‘mtcars’ data set is available in R and can be accessed from Ruby by using the ‘tilda’ operator followed by the symbol for the variable, in this case ‘:mtcar’. In the code bellow method ‘outputs’ is used to output the ‘mtcars’ data set nicely formatted in HTML by use of the ‘kable’ and ‘kable_styling’ functions. Method ‘outputs’ is only available when used with ‘gknit’.</p>
499
651
  <pre class="ruby"><code>outputs (~:mtcars).kable.kable_styling</code></pre>
500
652
  <table class="table" style="margin-left: auto; margin-right: auto;">
501
653
  <thead>
@@ -1757,36 +1909,581 @@ Volvo 142E
1757
1909
  </tbody>
1758
1910
  </table>
1759
1911
  </div>
1760
- <div id="graphics-with-ggplot" class="section level2">
1761
- <h2>Graphics with ggplot</h2>
1762
- <pre class="ruby"><code>require 'ggplot'
1763
-
1764
- R.theme_set R.theme_bw
1765
-
1766
- # Data Prep
1767
- mtcars = ~:mtcars
1768
- mtcars.car_name = R.rownames(:mtcars)
1769
- # compute normalized mpg
1770
- mtcars.mpg_z = ((mtcars.mpg - mtcars.mpg.mean)/mtcars.mpg.sd).round 2
1771
- mtcars.mpg_type = mtcars.mpg_z &lt; 0 ? &quot;below&quot; : &quot;above&quot;
1772
- mtcars = mtcars[mtcars.mpg_z.order, :all]
1773
- # convert to factor to retain sorted order in plot
1774
- mtcars.car_name = mtcars.car_name.factor levels: mtcars.car_name
1775
-
1776
- # Diverging Barcharts
1777
- gg = mtcars.ggplot(E.aes(x: :car_name, y: :mpg_z, label: :mpg_z)) +
1778
- R.geom_bar(E.aes(fill: :mpg_type), stat: 'identity', width: 0.5) +
1779
- R.scale_fill_manual(name: &quot;Mileage&quot;,
1780
- labels: R.c(&quot;Above Average&quot;, &quot;Below Average&quot;),
1781
- values: R.c(&quot;above&quot;: &quot;#00ba38&quot;, &quot;below&quot;: &quot;#f8766d&quot;)) +
1782
- R.labs(subtitle: &quot;Normalised mileage from 'mtcars'&quot;,
1783
- title: &quot;Diverging Bars&quot;) +
1784
- R.coord_flip()
1785
-
1786
- puts gg</code></pre>
1787
- <p><img src="data:image/png;base64,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" /><!-- --></p>
1788
- <p>[TO BE CONTINUED…]</p>
1912
+ <div id="matrix" class="section level1">
1913
+ <h1>Matrix</h1>
1914
+ <p>A matrix is a collection of elements organized as a two dimensional table. A matrix can be created by the ‘matrix’ function:</p>
1915
+ <pre class="ruby"><code>@mat = R.matrix(R.c(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0),
1916
+ nrow: 3,
1917
+ ncol: 3)
1918
+
1919
+ puts @mat</code></pre>
1920
+ <pre><code>## [,1] [,2] [,3]
1921
+ ## [1,] 1 4 7
1922
+ ## [2,] 2 5 8
1923
+ ## [3,] 3 6 9</code></pre>
1924
+ <p>Note that matrices data is organized by column first. It is possible to organize the matrix memory by row first passing an extra argument to the ‘matrix’ function:</p>
1925
+ <pre class="ruby"><code>@mat_row = R.matrix(R.c(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0),
1926
+ nrow: 3,
1927
+ ncol: 3,
1928
+ byrow: true)
1929
+
1930
+ puts @mat_row</code></pre>
1931
+ <pre><code>## [,1] [,2] [,3]
1932
+ ## [1,] 1 2 3
1933
+ ## [2,] 4 5 6
1934
+ ## [3,] 7 8 9</code></pre>
1935
+ <div id="indexing-a-matrix" class="section level2">
1936
+ <h2>Indexing a Matrix</h2>
1937
+ <p>A matrix can be indexed by [row, column]:</p>
1938
+ <pre class="ruby"><code>puts @mat_row[1, 1]
1939
+ puts @mat_row[2, 3]</code></pre>
1940
+ <pre><code>## [1] 1
1941
+ ## [1] 6</code></pre>
1942
+ <p>It is possible to index an entire row or column with the ‘:all’ keyword</p>
1943
+ <pre class="ruby"><code>puts @mat_row[1, :all]
1944
+ puts @mat_row[:all, 2]</code></pre>
1945
+ <pre><code>## [1] 1 2 3
1946
+ ## [1] 2 5 8</code></pre>
1947
+ <p>Indexing with a vector is also possible for matrices. In the following example we want rows 1 and 3 and columns 2 and 3 building a 2 x 2 matrix.</p>
1948
+ <pre class="ruby"><code>puts @mat_row[R.c(1, 3), R.c(2, 3)]</code></pre>
1949
+ <pre><code>## [,1] [,2]
1950
+ ## [1,] 2 3
1951
+ ## [2,] 8 9</code></pre>
1952
+ <p>Matrices can be combined with functions ‘rbind’ and ‘cbind’</p>
1953
+ <pre class="ruby"><code>puts @mat_row.rbind(@mat)
1954
+ puts @mat_row.cbind(@mat)</code></pre>
1955
+ <pre><code>## [,1] [,2] [,3]
1956
+ ## [1,] 1 2 3
1957
+ ## [2,] 4 5 6
1958
+ ## [3,] 7 8 9
1959
+ ## [4,] 1 4 7
1960
+ ## [5,] 2 5 8
1961
+ ## [6,] 3 6 9
1962
+ ## [,1] [,2] [,3] [,4] [,5] [,6]
1963
+ ## [1,] 1 2 3 1 4 7
1964
+ ## [2,] 4 5 6 2 5 8
1965
+ ## [3,] 7 8 9 3 6 9</code></pre>
1966
+ </div>
1967
+ </div>
1968
+ <div id="list" class="section level1">
1969
+ <h1>List</h1>
1970
+ <p>A list is a data structure that can contain sublists of different types, while vector and matrix can only hold one type of element.</p>
1971
+ <pre class="ruby"><code>nums = R.c(1.0, 2.0, 3.0)
1972
+ strs = R.c(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;)
1973
+ bool = R.c(true, true, false)
1974
+ @lst = R.list(nums: nums, strs: strs, bool: bool)
1975
+ puts @lst</code></pre>
1976
+ <pre><code>## $nums
1977
+ ## [1] 1 2 3
1978
+ ##
1979
+ ## $strs
1980
+ ## [1] &quot;a&quot; &quot;b&quot; &quot;c&quot; &quot;d&quot;
1981
+ ##
1982
+ ## $bool
1983
+ ## [1] TRUE TRUE FALSE</code></pre>
1984
+ <p>Note that ‘<span class="citation">@lst</span>’ elements are named elements.</p>
1985
+ <div id="list-indexing" class="section level2">
1986
+ <h2>List Indexing</h2>
1987
+ <p>List indexing, also called slicing, is done using the ‘[]’ operator and the ‘[[]]’ operator. Let’s first start with the ‘[]’ operator. The list above has three sublist indexing with ‘[]’ will return one of the sublists.</p>
1988
+ <pre class="ruby"><code>puts @lst[1]</code></pre>
1989
+ <pre><code>## $nums
1990
+ ## [1] 1 2 3</code></pre>
1991
+ <p>Note that when using ‘[]’ a new list is returned. When using the double square bracket operator the value returned is the actual element of the list in the given position and not a slice of the original list</p>
1992
+ <pre class="ruby"><code>puts @lst[[1]]</code></pre>
1993
+ <pre><code>## [1] 1 2 3</code></pre>
1994
+ <p>When elements are named, as dones with <span class="citation">@lst</span>, indexing can be done by name:</p>
1995
+ <pre class="ruby"><code>puts @lst[['bool']][[1]] &gt;&gt; 0</code></pre>
1996
+ <pre><code>## true</code></pre>
1997
+ <p>In this example, first the ‘bool’ element of the list was extracted, not as a list, but as a vector, then the first element of the vector was extracted (note that vectors also accept the ‘[[]]’ operator) and then the vector was indexed by its first element, extracting the native Ruby type.</p>
1998
+ </div>
1999
+ </div>
2000
+ <div id="data-frame" class="section level1">
2001
+ <h1>Data Frame</h1>
2002
+ <p>A data frame is a table like structure in which each column has the same number of rows. Data frames are the basic structure for storing data for data analysis. We have already seen a data frame previously when we accessed variable ‘~:mtcars’. In order to create a data frame, function ’data__frame’ is used:</p>
2003
+ <pre class="ruby"><code>df = R.data__frame(
2004
+ year: R.c(2010, 2011, 2012),
2005
+ income: R.c(1000.0, 1500.0, 2000.0))
2006
+
2007
+ puts df</code></pre>
2008
+ <pre><code>## year income
2009
+ ## 1 2010 1000
2010
+ ## 2 2011 1500
2011
+ ## 3 2012 2000</code></pre>
2012
+ <div id="data-frame-indexing" class="section level2">
2013
+ <h2>Data Frame Indexing</h2>
2014
+ <p>A data frame can be indexed the same way as a matrix, by using ‘[row, column]’, where row and column can either be a numeric or the name of the row or column</p>
2015
+ <pre class="ruby"><code>puts (~:mtcars).head
2016
+ puts (~:mtcars)[1, 2]
2017
+ puts (~:mtcars)['Datsun 710', 'mpg']</code></pre>
2018
+ <pre><code>## mpg cyl disp hp drat wt qsec vs am gear carb
2019
+ ## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
2020
+ ## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
2021
+ ## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
2022
+ ## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
2023
+ ## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
2024
+ ## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
2025
+ ## [1] 6
2026
+ ## [1] 22.8</code></pre>
2027
+ <p>Extracting a column from a data frame as a vector can be done by using the double square bracket operator:</p>
2028
+ <pre class="ruby"><code>puts (~:mtcars)[['mpg']]</code></pre>
2029
+ <pre><code>## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2
2030
+ ## [15] 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4
2031
+ ## [29] 15.8 19.7 15.0 21.4</code></pre>
2032
+ <p>A data frame column can also be accessed as if it were an instance variable of the data frame:</p>
2033
+ <pre class="ruby"><code>puts (~:mtcars).mpg</code></pre>
2034
+ <pre><code>## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2
2035
+ ## [15] 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4
2036
+ ## [29] 15.8 19.7 15.0 21.4</code></pre>
2037
+ <p>Slicing a data frame can be done by indexing it with a vector (we use ‘head’ to reduce the output):</p>
2038
+ <pre class="ruby"><code>puts (~:mtcars)[R.c('mpg', 'hp')].head</code></pre>
2039
+ <pre><code>## mpg hp
2040
+ ## Mazda RX4 21.0 110
2041
+ ## Mazda RX4 Wag 21.0 110
2042
+ ## Datsun 710 22.8 93
2043
+ ## Hornet 4 Drive 21.4 110
2044
+ ## Hornet Sportabout 18.7 175
2045
+ ## Valiant 18.1 105</code></pre>
2046
+ <p>A row slice can be obtained by indexing by row and using the ‘:all’ keyword for the column:</p>
2047
+ <pre class="ruby"><code>puts (~:mtcars)[R.c('Datsun 710', 'Camaro Z28'), :all]</code></pre>
2048
+ <pre><code>## mpg cyl disp hp drat wt qsec vs am gear carb
2049
+ ## Datsun 710 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1
2050
+ ## Camaro Z28 13.3 8 350 245 3.73 3.84 15.41 0 0 3 4</code></pre>
2051
+ <p>Finally, a data frame can also be indexed with a logical vector. In this next example, the ‘am’ column of :mtcars is compared with 0 (with method ‘eq’). When ‘am’ is equal to 0 the car is automatic. So, by doing ‘(~:mtcars).am.eq 0’ a logical vector is created with ‘true’ whenever ‘am’ is 0 and ‘false’ otherwise. Using this logical vector, the data frame is indexed, returning a new data frame in which all cars have automatic transmission.</p>
2052
+ <pre class="ruby"><code># obtain a vector with 'true' for cars with automatic transmission
2053
+ automatic = (~:mtcars).am.eq 0
2054
+ puts automatic
2055
+
2056
+ # slice the data frame by using this vector
2057
+ puts (~:mtcars)[automatic, :all]</code></pre>
2058
+ <pre><code>## [1] FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
2059
+ ## [12] TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE
2060
+ ## [23] TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
2061
+ ## mpg cyl disp hp drat wt qsec vs am gear carb
2062
+ ## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
2063
+ ## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
2064
+ ## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
2065
+ ## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
2066
+ ## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
2067
+ ## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
2068
+ ## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
2069
+ ## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
2070
+ ## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
2071
+ ## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
2072
+ ## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
2073
+ ## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
2074
+ ## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
2075
+ ## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
2076
+ ## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
2077
+ ## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
2078
+ ## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
2079
+ ## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
2080
+ ## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2</code></pre>
2081
+ </div>
1789
2082
  </div>
2083
+ <div id="writing-expressions-in-galaaz" class="section level1">
2084
+ <h1>Writing Expressions in Galaaz</h1>
2085
+ <p>Galaaz extends Ruby to work with complex expressions, similar to R’s expressions build with ‘quote’ (base R) or ‘quo’ (tidyverse). Let’s take a look at some of those expressions.</p>
2086
+ <div id="expressions-from-operators" class="section level2">
2087
+ <h2>Expressions from operators</h2>
2088
+ <p>The code bellow creates an expression summing two symbols</p>
2089
+ <pre class="ruby"><code>exp1 = :a + :b
2090
+ puts exp1</code></pre>
2091
+ <pre><code>## a + b</code></pre>
2092
+ <p>We can build any complex mathematical expression</p>
2093
+ <pre class="ruby"><code>exp2 = (:a + :b) * 2.0 + :c ** 2 / :z
2094
+ puts exp2</code></pre>
2095
+ <pre><code>## (a + b) * 2 + c^2L/z</code></pre>
2096
+ <p>It is also possible to use inequality operators in building expressions</p>
2097
+ <pre class="ruby"><code>exp3 = (:a + :b) &gt;= :z
2098
+ puts exp3</code></pre>
2099
+ <pre><code>## a + b &gt;= z</code></pre>
2100
+ <p>Galaaz provides both symbolic representations for operators, such as (&gt;, &lt;, !=) as functional notation for those operators such as (.gt, .ge, etc.). So the same expression written above can also be written as</p>
2101
+ <pre class="ruby"><code>exp4 = (:a + :b).ge :z
2102
+ puts exp4</code></pre>
2103
+ <pre><code>## a + b &gt;= z</code></pre>
2104
+ <p>Two type of expression can only be created with the functional representation of the operators, those are expressions involving ‘==’, and ‘=’. In order to write an expression involving ‘==’ we need to use the method ‘.eq’ and for ‘=’ we need the function ‘.assign’</p>
2105
+ <pre class="ruby"><code>exp5 = (:a + :b).eq :z
2106
+ puts exp5</code></pre>
2107
+ <pre><code>## a + b == z</code></pre>
2108
+ <pre class="ruby"><code>exp6 = :y.assign :a + :b
2109
+ puts exp6</code></pre>
2110
+ <pre><code>## y &lt;- a + b</code></pre>
2111
+ <p>In general we think that using the functional notation is preferable to using the symbolic notation as otherwise, we end up writing invalid expressions such as</p>
2112
+ <pre class="ruby"><code>exp_wrong = (:a + :b) == :z
2113
+ puts exp_wrong</code></pre>
2114
+ <pre><code>## Message:
2115
+ ## Error in function (x, y, num.eq = TRUE, single.NA = TRUE, attrib.as.set = TRUE, :
2116
+ ## object 'a' not found (RError)
2117
+ ## Translated to internal error</code></pre>
2118
+ <p>and it might be difficult to understand what is going on here. The problem lies with the fact that when using ‘==’ we are comparing expression (:a + :b) to expression :z with ‘==’. When the comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols at this time are not bound to anything and we get a “object ‘a’ not found” message. If we only use functional notation, this type of error will not occur.</p>
2119
+ </div>
2120
+ <div id="expressions-with-r-methods" class="section level2">
2121
+ <h2>Expressions with R methods</h2>
2122
+ <p>It is often necessary to create an expression that uses a method or function. For instance, in mathematics, it’s quite natural to write an expressin such as <span class="math inline">\(y = sin(x)\)</span>. In this case, the ‘sin’ function is part of the expression and should not immediately executed. Now, let’s say that ‘x’ is an angle of 45<span class="math inline">\(^\circ\)</span> and we acttually want our expression to be <span class="math inline">\(y = 0.850...\)</span>. When we want the function to be part of the expression, we call the function preceeding it by the letter E, such as ‘E.sin(x)’</p>
2123
+ <pre class="ruby"><code>exp7 = :y.assign E.sin(:x)
2124
+ puts exp7</code></pre>
2125
+ <pre><code>## y &lt;- sin(x)</code></pre>
2126
+ </div>
2127
+ </div>
2128
+ <div id="manipulating-data" class="section level1">
2129
+ <h1>Manipulating Data</h1>
2130
+ <p>One of the major benefits of Galaaz is to bring strong data manipulation to Ruby. The following examples were extracted from Hardley’s “R for Data Science” (<a href="https://r4ds.had.co.nz/" class="uri">https://r4ds.had.co.nz/</a>). This is a highly recommended book for those not already familiar with the ‘tidyverse’ style of programming in R. In the sections to follow, we will limit ourselves to convert the R code to Galaaz.</p>
2131
+ <p>For these examples, we will investigate the nycflights13 data set available on the package by the same name. We use function ‘R.install_and_loads’ that checks if the library is available locally, and if not, installs it. This data frame contains all 336,776 flights that departed from New York City in 2013. The data comes from the US Bureau of Transportation Statistics.</p>
2132
+ <pre class="ruby"><code>R.install_and_loads('nycflights13')
2133
+ R.library('dplyr')</code></pre>
2134
+ <pre class="ruby"><code>@flights = ~:flights
2135
+ puts @flights.head.as__data__frame</code></pre>
2136
+ <pre><code>## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
2137
+ ## 1 2013 1 1 517 515 2 830 819
2138
+ ## 2 2013 1 1 533 529 4 850 830
2139
+ ## 3 2013 1 1 542 540 2 923 850
2140
+ ## 4 2013 1 1 544 545 -1 1004 1022
2141
+ ## 5 2013 1 1 554 600 -6 812 837
2142
+ ## 6 2013 1 1 554 558 -4 740 728
2143
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
2144
+ ## 1 11 UA 1545 N14228 EWR IAH 227 1400 5
2145
+ ## 2 20 UA 1714 N24211 LGA IAH 227 1416 5
2146
+ ## 3 33 AA 1141 N619AA JFK MIA 160 1089 5
2147
+ ## 4 -18 B6 725 N804JB JFK BQN 183 1576 5
2148
+ ## 5 -25 DL 461 N668DN LGA ATL 116 762 6
2149
+ ## 6 12 UA 1696 N39463 EWR ORD 150 719 5
2150
+ ## minute time_hour
2151
+ ## 1 15 2013-01-01 05:00:00
2152
+ ## 2 29 2013-01-01 05:00:00
2153
+ ## 3 40 2013-01-01 05:00:00
2154
+ ## 4 45 2013-01-01 05:00:00
2155
+ ## 5 0 2013-01-01 06:00:00
2156
+ ## 6 58 2013-01-01 05:00:00</code></pre>
2157
+ <div id="filtering-rows-with-filter" class="section level2">
2158
+ <h2>Filtering rows with Filter</h2>
2159
+ <p>In this example we filter the flights data set by giving to the filter function two expressions: the first :month.eq 1</p>
2160
+ <pre class="ruby"><code>puts @flights.filter((:month.eq 1), (:day.eq 1)).head.as__data__frame</code></pre>
2161
+ <pre><code>## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
2162
+ ## 1 2013 1 1 517 515 2 830 819
2163
+ ## 2 2013 1 1 533 529 4 850 830
2164
+ ## 3 2013 1 1 542 540 2 923 850
2165
+ ## 4 2013 1 1 544 545 -1 1004 1022
2166
+ ## 5 2013 1 1 554 600 -6 812 837
2167
+ ## 6 2013 1 1 554 558 -4 740 728
2168
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
2169
+ ## 1 11 UA 1545 N14228 EWR IAH 227 1400 5
2170
+ ## 2 20 UA 1714 N24211 LGA IAH 227 1416 5
2171
+ ## 3 33 AA 1141 N619AA JFK MIA 160 1089 5
2172
+ ## 4 -18 B6 725 N804JB JFK BQN 183 1576 5
2173
+ ## 5 -25 DL 461 N668DN LGA ATL 116 762 6
2174
+ ## 6 12 UA 1696 N39463 EWR ORD 150 719 5
2175
+ ## minute time_hour
2176
+ ## 1 15 2013-01-01 05:00:00
2177
+ ## 2 29 2013-01-01 05:00:00
2178
+ ## 3 40 2013-01-01 05:00:00
2179
+ ## 4 45 2013-01-01 05:00:00
2180
+ ## 5 0 2013-01-01 06:00:00
2181
+ ## 6 58 2013-01-01 05:00:00</code></pre>
2182
+ </div>
2183
+ <div id="logical-operators" class="section level2">
2184
+ <h2>Logical Operators</h2>
2185
+ <p>All flights that departed in November of December</p>
2186
+ <pre class="ruby"><code>puts @flights.filter((:month.eq 11) | (:month.eq 12)).head.as__data__frame</code></pre>
2187
+ <pre><code>## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
2188
+ ## 1 2013 11 1 5 2359 6 352 345
2189
+ ## 2 2013 11 1 35 2250 105 123 2356
2190
+ ## 3 2013 11 1 455 500 -5 641 651
2191
+ ## 4 2013 11 1 539 545 -6 856 827
2192
+ ## 5 2013 11 1 542 545 -3 831 855
2193
+ ## 6 2013 11 1 549 600 -11 912 923
2194
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
2195
+ ## 1 7 B6 745 N568JB JFK PSE 205 1617 23
2196
+ ## 2 87 B6 1816 N353JB JFK SYR 36 209 22
2197
+ ## 3 -10 US 1895 N192UW EWR CLT 88 529 5
2198
+ ## 4 29 UA 1714 N38727 LGA IAH 229 1416 5
2199
+ ## 5 -24 AA 2243 N5CLAA JFK MIA 147 1089 5
2200
+ ## 6 -11 UA 303 N595UA JFK SFO 359 2586 6
2201
+ ## minute time_hour
2202
+ ## 1 59 2013-11-01 23:00:00
2203
+ ## 2 50 2013-11-01 22:00:00
2204
+ ## 3 0 2013-11-01 05:00:00
2205
+ ## 4 45 2013-11-01 05:00:00
2206
+ ## 5 45 2013-11-01 05:00:00
2207
+ ## 6 0 2013-11-01 06:00:00</code></pre>
2208
+ <p>The same as above, but using the ‘in’ operator. In R, it is possible to define many operators by doing %<op>%. The %in% operator checks if a value is in a vector. In order to use those operators from Galaaz the ‘._’ method is used, where the first argument is the operator’s symbol, in this case ‘:in’ and the second argument is the vector:</p>
2209
+ <pre class="ruby"><code>puts @flights.filter(:month._ :in, R.c(11, 12)).head.as__data__frame</code></pre>
2210
+ <pre><code>## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
2211
+ ## 1 2013 11 1 5 2359 6 352 345
2212
+ ## 2 2013 11 1 35 2250 105 123 2356
2213
+ ## 3 2013 11 1 455 500 -5 641 651
2214
+ ## 4 2013 11 1 539 545 -6 856 827
2215
+ ## 5 2013 11 1 542 545 -3 831 855
2216
+ ## 6 2013 11 1 549 600 -11 912 923
2217
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
2218
+ ## 1 7 B6 745 N568JB JFK PSE 205 1617 23
2219
+ ## 2 87 B6 1816 N353JB JFK SYR 36 209 22
2220
+ ## 3 -10 US 1895 N192UW EWR CLT 88 529 5
2221
+ ## 4 29 UA 1714 N38727 LGA IAH 229 1416 5
2222
+ ## 5 -24 AA 2243 N5CLAA JFK MIA 147 1089 5
2223
+ ## 6 -11 UA 303 N595UA JFK SFO 359 2586 6
2224
+ ## minute time_hour
2225
+ ## 1 59 2013-11-01 23:00:00
2226
+ ## 2 50 2013-11-01 22:00:00
2227
+ ## 3 0 2013-11-01 05:00:00
2228
+ ## 4 45 2013-11-01 05:00:00
2229
+ ## 5 45 2013-11-01 05:00:00
2230
+ ## 6 0 2013-11-01 06:00:00</code></pre>
2231
+ </div>
2232
+ <div id="filtering-with-na-not-available" class="section level2">
2233
+ <h2>Filtering with NA (Not Available)</h2>
2234
+ <p>Let’s first create a ‘tibble’ with a Not Available value (R::NA). Tibbles are a modern version of a data frame and operate very similarly to one. It differs in how it outputs the values and the result of some subsetting operations that are more consistent than what is obtained from data frame.</p>
2235
+ <pre class="ruby"><code>@df = R.tibble(x: R.c(1, R::NA, 3))
2236
+ puts @df.as__data__frame</code></pre>
2237
+ <pre><code>## x
2238
+ ## 1 1
2239
+ ## 2 NA
2240
+ ## 3 3</code></pre>
2241
+ <p>Now filtering by :x &gt; 1 shows all lines that satisfy this condition, where the row with R:NA does not.</p>
2242
+ <pre class="ruby"><code>puts @df.filter(:x &gt; 1).as__data__frame</code></pre>
2243
+ <pre><code>## x
2244
+ ## 1 3</code></pre>
2245
+ <p>To match an NA use method ’is__na’</p>
2246
+ <pre class="ruby"><code>puts @df.filter((:x.is__na) | (:x &gt; 1)).as__data__frame</code></pre>
2247
+ <pre><code>## x
2248
+ ## 1 NA
2249
+ ## 2 3</code></pre>
2250
+ </div>
2251
+ <div id="arrange-rows-with-arrange" class="section level2">
2252
+ <h2>Arrange Rows with arrange</h2>
2253
+ <p>Arrange reorders the rows of a data frame by the given arguments.</p>
2254
+ <pre class="ruby"><code>puts @flights.arrange(:year, :month, :day).head.as__data__frame</code></pre>
2255
+ <pre><code>## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
2256
+ ## 1 2013 1 1 517 515 2 830 819
2257
+ ## 2 2013 1 1 533 529 4 850 830
2258
+ ## 3 2013 1 1 542 540 2 923 850
2259
+ ## 4 2013 1 1 544 545 -1 1004 1022
2260
+ ## 5 2013 1 1 554 600 -6 812 837
2261
+ ## 6 2013 1 1 554 558 -4 740 728
2262
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
2263
+ ## 1 11 UA 1545 N14228 EWR IAH 227 1400 5
2264
+ ## 2 20 UA 1714 N24211 LGA IAH 227 1416 5
2265
+ ## 3 33 AA 1141 N619AA JFK MIA 160 1089 5
2266
+ ## 4 -18 B6 725 N804JB JFK BQN 183 1576 5
2267
+ ## 5 -25 DL 461 N668DN LGA ATL 116 762 6
2268
+ ## 6 12 UA 1696 N39463 EWR ORD 150 719 5
2269
+ ## minute time_hour
2270
+ ## 1 15 2013-01-01 05:00:00
2271
+ ## 2 29 2013-01-01 05:00:00
2272
+ ## 3 40 2013-01-01 05:00:00
2273
+ ## 4 45 2013-01-01 05:00:00
2274
+ ## 5 0 2013-01-01 06:00:00
2275
+ ## 6 58 2013-01-01 05:00:00</code></pre>
2276
+ <p>To arrange in descending order, use function ‘desc’</p>
2277
+ <pre class="ruby"><code>puts @flights.arrange(:dep_delay.desc).head.as__data__frame</code></pre>
2278
+ <pre><code>## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
2279
+ ## 1 2013 1 9 641 900 1301 1242 1530
2280
+ ## 2 2013 6 15 1432 1935 1137 1607 2120
2281
+ ## 3 2013 1 10 1121 1635 1126 1239 1810
2282
+ ## 4 2013 9 20 1139 1845 1014 1457 2210
2283
+ ## 5 2013 7 22 845 1600 1005 1044 1815
2284
+ ## 6 2013 4 10 1100 1900 960 1342 2211
2285
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
2286
+ ## 1 1272 HA 51 N384HA JFK HNL 640 4983 9
2287
+ ## 2 1127 MQ 3535 N504MQ JFK CMH 74 483 19
2288
+ ## 3 1109 MQ 3695 N517MQ EWR ORD 111 719 16
2289
+ ## 4 1007 AA 177 N338AA JFK SFO 354 2586 18
2290
+ ## 5 989 MQ 3075 N665MQ JFK CVG 96 589 16
2291
+ ## 6 931 DL 2391 N959DL JFK TPA 139 1005 19
2292
+ ## minute time_hour
2293
+ ## 1 0 2013-01-09 09:00:00
2294
+ ## 2 35 2013-06-15 19:00:00
2295
+ ## 3 35 2013-01-10 16:00:00
2296
+ ## 4 45 2013-09-20 18:00:00
2297
+ ## 5 0 2013-07-22 16:00:00
2298
+ ## 6 0 2013-04-10 19:00:00</code></pre>
2299
+ </div>
2300
+ <div id="selecting-columns" class="section level2">
2301
+ <h2>Selecting columns</h2>
2302
+ <p>To select specific columns from a dataset we use function ‘select’:</p>
2303
+ <pre class="ruby"><code>puts @flights.select(:year, :month, :day).head.as__data__frame</code></pre>
2304
+ <pre><code>## year month day
2305
+ ## 1 2013 1 1
2306
+ ## 2 2013 1 1
2307
+ ## 3 2013 1 1
2308
+ ## 4 2013 1 1
2309
+ ## 5 2013 1 1
2310
+ ## 6 2013 1 1</code></pre>
2311
+ <p>It is also possible to select column in a given range</p>
2312
+ <pre class="ruby"><code>puts @flights.select(:year.up_to :day).head.as__data__frame</code></pre>
2313
+ <pre><code>## year month day
2314
+ ## 1 2013 1 1
2315
+ ## 2 2013 1 1
2316
+ ## 3 2013 1 1
2317
+ ## 4 2013 1 1
2318
+ ## 5 2013 1 1
2319
+ ## 6 2013 1 1</code></pre>
2320
+ <p>Select all columns that start with a given name sequence</p>
2321
+ <pre class="ruby"><code>puts @flights.select(E.starts_with('arr')).head.as__data__frame</code></pre>
2322
+ <pre><code>## arr_time arr_delay
2323
+ ## 1 830 11
2324
+ ## 2 850 20
2325
+ ## 3 923 33
2326
+ ## 4 1004 -18
2327
+ ## 5 812 -25
2328
+ ## 6 740 12</code></pre>
2329
+ <p>Other functions that can be used:</p>
2330
+ <ul>
2331
+ <li><p>ends_with(“xyz”): matches names that end with “xyz”.</p></li>
2332
+ <li><p>contains(“ijk”): matches names that contain “ijk”.</p></li>
2333
+ <li><p>matches(“(.)\1”): selects variables that match a regular expression. This one matches any variables that contain repeated characters.</p></li>
2334
+ <li><p>num_range(“x”, (1..3)): matches x1, x2 and x3</p></li>
2335
+ </ul>
2336
+ <p>A helper function that comes in handy when we just want to rearrange column order is ‘Everything’:</p>
2337
+ <pre class="ruby"><code>puts @flights.select(:year, :month, :day, E.everything).head.as__data__frame</code></pre>
2338
+ <pre><code>## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
2339
+ ## 1 2013 1 1 517 515 2 830 819
2340
+ ## 2 2013 1 1 533 529 4 850 830
2341
+ ## 3 2013 1 1 542 540 2 923 850
2342
+ ## 4 2013 1 1 544 545 -1 1004 1022
2343
+ ## 5 2013 1 1 554 600 -6 812 837
2344
+ ## 6 2013 1 1 554 558 -4 740 728
2345
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
2346
+ ## 1 11 UA 1545 N14228 EWR IAH 227 1400 5
2347
+ ## 2 20 UA 1714 N24211 LGA IAH 227 1416 5
2348
+ ## 3 33 AA 1141 N619AA JFK MIA 160 1089 5
2349
+ ## 4 -18 B6 725 N804JB JFK BQN 183 1576 5
2350
+ ## 5 -25 DL 461 N668DN LGA ATL 116 762 6
2351
+ ## 6 12 UA 1696 N39463 EWR ORD 150 719 5
2352
+ ## minute time_hour
2353
+ ## 1 15 2013-01-01 05:00:00
2354
+ ## 2 29 2013-01-01 05:00:00
2355
+ ## 3 40 2013-01-01 05:00:00
2356
+ ## 4 45 2013-01-01 05:00:00
2357
+ ## 5 0 2013-01-01 06:00:00
2358
+ ## 6 58 2013-01-01 05:00:00</code></pre>
2359
+ </div>
2360
+ <div id="add-variables-to-a-dataframe-with-mutate" class="section level2">
2361
+ <h2>Add variables to a dataframe with ‘mutate’</h2>
2362
+ <pre class="ruby"><code>@flights_sm = @flights.
2363
+ select((:year.up_to :day),
2364
+ E.ends_with('delay'),
2365
+ :distance,
2366
+ :air_time)
2367
+
2368
+ puts @flights_sm.head.as__data__frame</code></pre>
2369
+ <pre><code>## year month day dep_delay arr_delay distance air_time
2370
+ ## 1 2013 1 1 2 11 1400 227
2371
+ ## 2 2013 1 1 4 20 1416 227
2372
+ ## 3 2013 1 1 2 33 1089 160
2373
+ ## 4 2013 1 1 -1 -18 1576 183
2374
+ ## 5 2013 1 1 -6 -25 762 116
2375
+ ## 6 2013 1 1 -4 12 719 150</code></pre>
2376
+ <pre class="ruby"><code>@flights_sm = @flights_sm.
2377
+ mutate(gain: :dep_delay - :arr_delay,
2378
+ speed: :distance / :air_time * 60)
2379
+ puts @flights_sm.head.as__data__frame</code></pre>
2380
+ <pre><code>## year month day dep_delay arr_delay distance air_time gain speed
2381
+ ## 1 2013 1 1 2 11 1400 227 -9 370.0441
2382
+ ## 2 2013 1 1 4 20 1416 227 -16 374.2731
2383
+ ## 3 2013 1 1 2 33 1089 160 -31 408.3750
2384
+ ## 4 2013 1 1 -1 -18 1576 183 17 516.7213
2385
+ ## 5 2013 1 1 -6 -25 762 116 19 394.1379
2386
+ ## 6 2013 1 1 -4 12 719 150 -16 287.6000</code></pre>
2387
+ </div>
2388
+ </div>
2389
+ <div id="graphics-in-galaaz" class="section level1">
2390
+ <h1>Graphics in Galaaz</h1>
2391
+ <p>Creating graphics in Galaaz is quite easy, as it can use all the power of ggplot2. There are many resources in the web that teaches ggplot, so here we give a quick example of ggplot integration with Ruby. We continue to use the :mtcars dataset and we will plot a diverging bar plot, showing cars that have ‘above’ or ‘below’ gas consuption. Let’s first prepare the data frame with the necessary data:</p>
2392
+ <pre class="ruby"><code># copy the R variable :mtcars to the Ruby mtcars variable
2393
+ @mtcars = ~:mtcars
2394
+
2395
+ # create a new column 'car_name' to store the car names so that it can be
2396
+ # used for plotting. The 'rownames' of the data frame cannot be used as
2397
+ # data for plotting
2398
+ @mtcars.car_name = R.rownames(:mtcars)
2399
+
2400
+ # compute normalized mpg and add it to a new column called mpg_z
2401
+ # Note that the mean value for mpg can be obtained by calling the 'mean'
2402
+ # function on the vector 'mtcars.mpg'. The same with the standard
2403
+ # deviation 'sd'. The vector is then rounded to two digits with 'round 2'
2404
+ @mtcars.mpg_z = ((@mtcars.mpg - @mtcars.mpg.mean)/@mtcars.mpg.sd).round 2
2405
+
2406
+ # create a new column 'mpg_type'. Function 'ifelse' is a vectorized function
2407
+ # that looks at every element of the mpg_z vector and if the value is below
2408
+ # 0, returns 'below', otherwise returns 'above'
2409
+ @mtcars.mpg_type = (@mtcars.mpg_z &lt; 0).ifelse(&quot;below&quot;, &quot;above&quot;)
2410
+
2411
+ # order the mtcar data set by the mpg_z vector from smaler to larger values
2412
+ @mtcars = @mtcars[@mtcars.mpg_z.order, :all]
2413
+
2414
+ # convert the car_name column to a factor to retain sorted order in plot
2415
+ @mtcars.car_name = @mtcars.car_name.factor levels: @mtcars.car_name
2416
+
2417
+ # let's look at the final data frame
2418
+ puts @mtcars</code></pre>
2419
+ <pre><code>## mpg cyl disp hp drat wt qsec vs am gear carb
2420
+ ## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
2421
+ ## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
2422
+ ## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
2423
+ ## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
2424
+ ## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
2425
+ ## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
2426
+ ## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
2427
+ ## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
2428
+ ## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
2429
+ ## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
2430
+ ## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
2431
+ ## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
2432
+ ## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
2433
+ ## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
2434
+ ## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
2435
+ ## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
2436
+ ## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
2437
+ ## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
2438
+ ## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
2439
+ ## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
2440
+ ## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
2441
+ ## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
2442
+ ## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
2443
+ ## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
2444
+ ## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
2445
+ ## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
2446
+ ## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
2447
+ ## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
2448
+ ## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
2449
+ ## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
2450
+ ## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
2451
+ ## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
2452
+ ## car_name mpg_z mpg_type
2453
+ ## Cadillac Fleetwood Cadillac Fleetwood -1.61 below
2454
+ ## Lincoln Continental Lincoln Continental -1.61 below
2455
+ ## Camaro Z28 Camaro Z28 -1.13 below
2456
+ ## Duster 360 Duster 360 -0.96 below
2457
+ ## Chrysler Imperial Chrysler Imperial -0.89 below
2458
+ ## Maserati Bora Maserati Bora -0.84 below
2459
+ ## Merc 450SLC Merc 450SLC -0.81 below
2460
+ ## AMC Javelin AMC Javelin -0.81 below
2461
+ ## Dodge Challenger Dodge Challenger -0.76 below
2462
+ ## Ford Pantera L Ford Pantera L -0.71 below
2463
+ ## Merc 450SE Merc 450SE -0.61 below
2464
+ ## Merc 450SL Merc 450SL -0.46 below
2465
+ ## Merc 280C Merc 280C -0.38 below
2466
+ ## Valiant Valiant -0.33 below
2467
+ ## Hornet Sportabout Hornet Sportabout -0.23 below
2468
+ ## Merc 280 Merc 280 -0.15 below
2469
+ ## Pontiac Firebird Pontiac Firebird -0.15 below
2470
+ ## Ferrari Dino Ferrari Dino -0.06 below
2471
+ ## Mazda RX4 Mazda RX4 0.15 above
2472
+ ## Mazda RX4 Wag Mazda RX4 Wag 0.15 above
2473
+ ## Hornet 4 Drive Hornet 4 Drive 0.22 above
2474
+ ## Volvo 142E Volvo 142E 0.22 above
2475
+ ## Toyota Corona Toyota Corona 0.23 above
2476
+ ## Datsun 710 Datsun 710 0.45 above
2477
+ ## Merc 230 Merc 230 0.45 above
2478
+ ## Merc 240D Merc 240D 0.72 above
2479
+ ## Porsche 914-2 Porsche 914-2 0.98 above
2480
+ ## Fiat X1-9 Fiat X1-9 1.20 above
2481
+ ## Honda Civic Honda Civic 1.71 above
2482
+ ## Lotus Europa Lotus Europa 1.71 above
2483
+ ## Fiat 128 Fiat 128 2.04 above
2484
+ ## Toyota Corolla Toyota Corolla 2.29 above</code></pre>
2485
+ <p>Now, lets plot the diverging bar plot. When using gKnit, there is no need to call ‘R.awt’ to create a plotting device, since gKnit does take care of it:</p>
2486
+ <p>[TO BE CONTINUED…]</p>
1790
2487
  </div>
1791
2488
  <div id="contributing" class="section level1">
1792
2489
  <h1>Contributing</h1>