---
title: "Frame Tools"
author: "John Mount, Win-Vector LLC"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Frame Tools}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
[`wrapr`](https://winvector.github.io/wrapr/) supplies a few tools for creating example
`data.frame`s. An important use case is: building the control table for `cdata::rowrecs_to_blocks()` and `cdata::blocks_to_rowrecs()` (example [here](https://winvector.github.io/cdata/articles/cdata.html)).
Lets see how to create an example data frame. The idea is similar to that found in [`tibble::tribble()`](https://tibble.tidyverse.org/reference/tribble.html): for small tables a
row oriented constructor can be quite legible, and avoids the cognitive load of taking a transpose.
For example we can create a typical `data.frame` as follows:
```{r}
d <- data.frame(
names = c("a", "b", "c", "d"),
x = c(1, 2, 3, 4 ),
y = c(1, 4, 9, 16 ),
stringsAsFactors = FALSE)
print(d)
```
Notice how the table is specified by columns (which is close to how `data.frame`s
are implemented), but printed by rows. `utils::str()` and `tibble::glimpse()` both
print by columns.
```{r}
str(d)
```
`wrapr` supplies the method [`draw_frame`](https://winvector.github.io/wrapr/articles/FrameTools.html) which at first glance appears to be a mere pretty-printer:
```{r}
library("wrapr")
```
```{r, comment=''}
cat(draw_frame(d))
```
However, the above rendering is actually executable `R` code. If we run it, we re-create
the original `data.frame()`.
```{r}
d2 <- build_frame(
"names", "x", "y" |
"a" , 1 , 1 |
"b" , 2 , 4 |
"c" , 3 , 9 |
"d" , 4 , 16 )
print(d2)
```
The merit is: the above input is how it looks when printed.
The technique is intended for typing small examples (or [`cdata`](https://github.com/WinVector/cdata) control tables) and only builds `data.frame`s with atomic types (characters, numerics, and logicals; no times, factors or list columns). The specification rule is the first appearance of an infix 2-argument function call (in this case the infix "or symbol" "|
") is taken to mean the earlier arguments are part of the header or column names and later arguments are values. The other appearances of "/
" are ignored. This means we could also write the frame as follows:
```{r}
build_frame(
"names", "x", "y" |
"a" , 1 , 1 ,
"b" , 2 , 4 ,
"c" , 3 , 9 ,
"d" , 4 , 16 )
```
This is more limited than `base::dump()`, but also more legible.
```{r, comment=""}
cat(dump("d", ""))
```
One can use the combination of `build_frame()` and `draw_frame()` to neaten up by-hand examples for later use (via copy and paste):
```{r, comment=""}
cat(draw_frame(build_frame(
"names", "x", "y" |
"a", 1, 1,
"b", 2, 4,
"c", 3, 9,
"d", 4, 16)))
```
`build_frame()` allows for simple substitutions of values. In contrast the method `qchar_frame()`
builds `data.frame`s containing only `character` types and doesn't require quoting (though it does allow it).
```{r}
qchar_frame(
col_1, col_2, col_3 |
a , b , c |
d , e , "f g" )
```
`build_frame()` is intended to capture typed-in examples, and is only compatible with very limited in-place calculation and substitution, and that _must_ be in parenthesis:
```{r}
build_frame(
"names", "x" , "y" |
"a" , 1 , 1 |
"b" , cos(2) , 4 |
"c" , (3+2) , 9 |
"d" , 4 , 16 )
```
Expressions not in parenthesis (such as "3 + 2
") will confuse the language transform `build_frame()` uses to detect cell boundaries.