---
title: "Controlling Matrix Aesthetics"
author: "Calvin Floyd"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Controlling Matrix Aesthetics}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 4,
  fig.height = 4
)
```

* One of the most aesthetically customizable aspects of grobblR is the cell-by-cell aesthetics of data frames / matrices.
* The `grob_matrix()` function, along with `add_aesthetic()`, `add_structure()` and `alter_at()`, help with just this, attempting to make the process as smooth and intuitive as possible.
* The entire `grob_matrix()` process is intended to be pipe-friendly.

```{r load}
library(grobblR)
```

## Matrix Groups

* There are 3 types of groups the user can alter within a grob matrix:

  * `cells`
  * `column_names`
  * `column_headings`

* All matrices / data frames inputted will have `cells` but they don't have to have `column_names`, and they won't have `column_headings` until the user adds them in after `grob_matrix()`.

## grob_matrix()

* To initialize the aesthetic / structure manipulation process, the user must apply `grob_matrix()` to his/her matrix/data frame.
* Using `view_grob()` the user can view the current state of the grob matrix before inserting it into a grob-layout and producing the final PDF report.

```{r grob_matrix}

df = data.frame(x = c(1, 2), y = c(3, 4), z = c(5, 6))

df %>%
  grob_matrix() %>%
  view_grob()

```


## add_aesthetic()

* Aesthetics will be defined as any aspects of the matrix that affect its visual appearance / looks, like colors or font faces.
* `add_aesthetic()` applies a specific aesthetic to the entire group of the matrix.
* To see a full list of accepted matrix aesthetics, run `?add_aesthetic`.

```{r add_aesthetic_cells}

df %>%
  grob_matrix() %>%
  add_aesthetic(
    aesthetic = "text_color",
    value = "red",
    group = "cells"
    ) %>%
  view_grob()

```

```{r add_aesthetic_cells_column_names}

df %>%
  grob_matrix() %>%
  add_aesthetic(
    aesthetic = "text_color",
    value = "red",
    group = "cells"
    ) %>%
  add_aesthetic(
    aesthetic = "text_color",
    value = "blue",
    group = "column_names"
    ) %>%
  view_grob()

```

## add_structure()

* Structures will be defined as any aspects of the matrix that affect its shape, like padding or column widths.
* `add_structure()` applies a specific structure to the entire matrix, and not just a specific group of the matrix like adding an aesthetic.
* To see a full list of accepted matrix structures, run `?add_structure`.
  * The most applicable structure to matrices is `column_widths_p`, where providing width proportions for each of the columns is the most useful.

```{r add_structure}

df %>%
  grob_matrix() %>%
  add_structure(
    structure = "column_widths_p",
    value = c(3, 1, 1)
    ) %>%
  view_grob()

```

* Giving a width proportion of 3 to the first column and a width proportion of 1 to the other two means `x` will be given 3 times the amount of width as `y` and `z`.
  * Default width proportions are determined by the width of the elements in each column.

## add_column_headings()

* To add column headings to a grob matrix `add_column_headings()` must be utilized after `grob_matrix()`.

```{r add_column_headings}

df %>%
  grob_matrix() %>%
  add_column_headings(
    headings = list("C1", "C2"),
    heading_cols = list(c(1, 2), c(3))
    ) %>%
  view_grob()

```

* Multiple column headings can be added on.

```{r add_2_column_headings}

df %>%
  grob_matrix() %>%
  add_column_headings(
    headings = list("C1", "C2"),
    heading_cols = list(c(1, 2), c(3))
    ) %>%
  add_column_headings(
    headings = list("C3", "C4", "C5"),
    heading_cols = list(1, 2, 3)
    ) %>%
  view_grob()

```

* If a `heading_cols` is omitted, it will be filled with an empty space.

```{r add_column_headings_empty_space}

df %>%
  grob_matrix() %>%
  add_column_headings(
    headings = list("C1"),
    heading_cols = list(c(1, 2))
    ) %>%
  view_grob()

```

* Once column headings have been initialized, the user can manipulate its aesthetics.

```{r add_column_headings_aesthetics}

df %>%
  grob_matrix() %>%
  add_column_headings(
    headings = list("C1"),
    heading_cols = list(c(1, 2))
    ) %>%
  add_aesthetic(
    aesthetic = "background_color",
    value = "blue",
    group = "column_headings"
    ) %>%
  add_aesthetic(
    aesthetic = "text_color",
    value = "white",
    group = "column_headings"
    ) %>%
  view_grob()

```

## alter_column_names()

* If the user wants to change the displayed column names to something other than the initial column names  passed through `grob_matrix()`, the user should utilize `alter_column_names()`.

```{r initial_alter_column_names}

df %>%
  grob_matrix() %>%
  alter_column_names(
    column_names = list("C1", "C2", "C3"),
    column_name_cols = list(1, 2, 3)
    ) %>%
  view_grob()

```

* Very useful for creating column names that span across multiple columns.

```{r alter_column_names_group_names}

df %>%
  grob_matrix() %>%
  alter_column_names(
    column_names = list("GROUP"),
    column_name_cols = list(1:2)
    ) %>%
  view_grob()

```

## alter_at()

* `alter_at()` is the function that is truly empowers the user to implement cell-by-cell aesthetic / structure customization.
* Inherits the aesthetic / structure and group from the most previous `add_aesthetic()` / `add_structure()` / `alter_at()`.
  * Otherwise, the user must specify the specific aesthetic and group he/she wants to alter.
* The user can select specific columns and/or rows to apply a value/function to.
  * Selected rows must be numeric row indices.
  * Selected columns can either be column names or column indices.
* If no columns/rows are specified then all columns/rows will be altered.
* The value, or the `.f` argument of `alter_at()` must be a quosure style lambda `~ fun(.)`.

```{r initial_alter_at}

df %>%
  grob_matrix() %>%
  add_aesthetic(
    aesthetic = "text_color",
    value = "blue",
    group = "cells"
    ) %>%
  alter_at(
    ~ "red",
    columns = c("x", "y"),
    rows = 1
    ) %>%
  view_grob()

```

* Matrix structures can also be altered (like the column width proportions).

```{r alter_at_structure}

df %>%
  grob_matrix() %>%
  add_structure("column_widths_p", 1) %>%
  alter_at(~ 3, columns = 1) %>%
  view_grob()

```

* The user can also utilize conditional row selection to determine which rows out of the selected rows and columns to alter.

```{r alter_at_with_conditional_evaluation}

df %>%
  grob_matrix() %>%
  add_aesthetic(
    aesthetic = "text_color",
    value = "blue",
    group = "cells"
    ) %>%
  alter_at(
    ~ "red",
    x > 1
    ) %>%
  alter_at(
    ~ "steelblue",
    y < 4,
    aesthetic = "background_color"
    ) %>%
  view_grob()

```

* The `.f`  argument is meant to be very flexible, as the user can supply a function to apply to the selected cells to output various aesthetics based on their values.

```{r alter_at_with_flexible_function}

test_function = function(x) ifelse(x > 3, "purple", "blue")

grob_matrix_with_function = df %>%
  grob_matrix() %>%
  add_aesthetic(
    aesthetic = "text_color",
    value = "white",
    group = "cells"
    ) %>%
  alter_at(
    ~ test_function(.),
    aesthetic = "background_color"
    )

grob_matrix_with_function %>% view_grob()

```

* In instances where the user might already have a nicely formatted matrix (where numeric columns might be converted to character columns), the user can supply a separate, underlying matrix/data frame to apply a function to or apply the conditional row selection to.

```{r alter_at_with_new_data}

formatted_df = apply(df, 2, function(x) paste0("F", x))

grob_matrix_with_new_data = formatted_df %>%
  grob_matrix() %>%
  alter_at(
    ~ test_function(.),
    x > 1,
    data = df,
    aesthetic = "text_color",
    group = "cells"
    )

grob_matrix_with_new_data %>% view_grob()

```


## Inserting into Grob Layout

* Once the user has the grob matrices in the place he/she wants them, he/she can simply insert them into `grob_layout()` inside a `grob_col()`.

```{r grob_layout}

gl = grob_layout(
  grob_row(grob_col(grob_matrix_with_function)),
  grob_row(grob_col(grob_matrix_with_new_data))
  )

gl %>% view_grob(height = 100, width = 100)

```




