---
title: "Getting Started"
output:
    rmarkdown::html_vignette:
        toc: true
vignette: >
  %\VignetteIndexEntry{Getting Started}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
    collapse = FALSE,
    comment = NULL
)

options(cli.unicode = FALSE)
options(crayon.enabled = TRUE)

ansi_aware_handler = function(x, options) {
    paste0(
        "<pre class=\"r-output\"><code>",
        fansi::sgr_to_html(x = x, warn = FALSE, term.cap = "256"),
        "</code></pre>"
    )
}

knitr::knit_hooks$set(
    output = ansi_aware_handler, 
    message = ansi_aware_handler, 
    warning = ansi_aware_handler,
    error = ansi_aware_handler
)

knitr::opts_chunk$set(
    collapse = TRUE,
    # comment = "#>",
    comment = NA, 
    # fig.path = "man/figures/README-",
    out.width = "100%"
)

library(tabstats)
```

## Rationale

`{tabstats}` is a lightweight package for displaying data in clean, formatted tables directly in the console. It is mainly designed for developers who wants to display their outputs (preferably in a data frame object), and to make the output readable at a glance, configurable without boilerplate, and friendly to interactive workflows.

The package provides four main functions:

| Function          | Purpose                                    |
|-------------------|--------------------------------------------|
| `table_default()` | General-purpose data frame table           | 
| `table_summary()` | Two-column key-value summary table         |
| `corr_matrix()`   | Correlation matrix display                 |
| `cross_table()`   | Cross tabulation with optional percentages |

All functions share a common design philosophy:

1.  **Styling** is controlled via a `style = list(...)` argument that accepts either predefined style strings (e.g. `"blue_bold"`) or plain lambda functions (e.g. `\(x) cli::col_red(x)`).
2.  **Alignment** is controlled via an `align` argument that accepts a single string, a length-2 vector, or a named list.
3.  **Centering** is controlled via `center_table = TRUE`, which automatically pads the output to the middle of your terminal.

## Installation

Install the following package from CRAN:

```{r, eval = FALSE}
install.packages("tabstats")
```

Or install the development version from GitHub:

```{r eval = FALSE}
# install.packages("pak")
pak::pak("joshuamarie/tabstats")
## devtools::install_github("joshuamarie/tabstats") 
```

## A Quick Tour

The main API of this package displays the data you wanted to display into a specific format

### `table_default()`

Data frames usually looks like this when displayed:

```{r}
head(mtcars[, 1:5], 5)
```

With `table_default()`, the data frame is now displayed in an APA-style format, with configurable formatting.

```{r}
table_default(head(mtcars[, 1:5], 5))
```

### `table_summary()`

Another form of `table_default()`, except it is best suitable for displaying summarized data, where it requires 2 columns data frame. The simplest use case is a named summary of values, like model diagnostics or descriptive statistics, where the 1st column is the name of the parameter (statistic) while the 2nd column is the estimate.

```{r}
df = data.frame(
    Statistic = c("N", "Mean", "SD", "Min", "Max"),
    Value = c("100", "3.45", "1.20", "1.00", "6.00")
)

table_summary(
    df, 
    title = "Descriptive Statistics", 
    header = TRUE
)
```

*The `header` means you still wanted to display the column names from the original `df` data frame, otherwise, no column names are present. *

### `corr_matrix()`

A much complex but niche function to display the matrix, specifically designed for correlation matrices. If the `display` is a correlation matrix, typically the output of `cor()`, you can directly pass it. 

```{r}
corr_matrix(cor(mtcars[, 1:4]), method = "Pearson")
```

But, if the data you wanted to display is not a matrix, but on another form, you're going to have to configure it by building a custom spec with `new_corr_data()` for full control over which values to appear.

A wild example, assuming you want to display the output from `rstatix::cor_test()`: 

```{r}
cor_mat = 
    iris |> 
    rstatix::cor_test(Sepal.Width, Sepal.Length, Petal.Length) |> 
    dplyr::mutate(
        var1,
        var2,
        cor = format(cor, digits = 2),
        statistic = format(statistic, digits = 2),
        conf_int = paste0(
            "[",
            format(conf.low, digits = 2), 
            ", ",
            format(conf.high, digits = 2),
            "]"
        ),
        
        .keep = "unused"
    ) 

cor_mat |> 
    with({
        corr_matrix(
            new_corr_data(
                var1 = var1,
                var2 = var2,
                corr = cor,
                statistic = statistic,
                pval = p,
                conf_int = conf_int
            ),
            title = "Pearson Correlation Matrix"
        )
    })
```

### `cross_table()`

Another nice function to display the matrices — contingency tables, to be exact. It has (almost) everything to display the contingency table, including the observed frequencies, expected values, and percentages side by side.

```{r}
m = matrix(
    c(10, 20, 30, 40), 
    nrow = 2,
    dimnames = list(
        c("A", "B"), 
        c("X", "Y")
    )
)

cross_table(m, percentage = "all")
```

## Styling Primer

All table functions provides an API to style the table. 

1.  `table_default()` has 2 parameters: `style_colnames` to style the column names you wanted to design, and `style_columns` if you want to apply the style to the entire column you choose to style. Use `td_style()` to configure the style of the column you choose to style. 

2.  `table_summary()` has a `style` parameter to configure the style of the specific column you wanted to design. Use `sm_style()` to configure the style of the specific column. 

3.  `cross_table()` has a `style` parameter to configure the style of the data displayed by the function. Use `ct_style()` to configure the style of the displayed values. 

4.  `corr_matrix()` has a `style` parameter to configure the style of the values you entered, typically from the `display` argument using `new_corr_data()`. Use `cm_style()` to configure those values you assigned into `new_corr_data()` into the displayed table.

The quickest way to style output is with a named string:

```{r}
table_summary(
    df, 
    title = "Descriptive Statistics", 
    header = TRUE, 
    style = sm_style(
        left_col = "blue_bold",
        right_col = "green",
        title = "bold", 
        sep = ":  "
    )
)
```

For full control, pass a lambda instead — it receives the text as its argument:

```{r}
table_summary(
    df, 
    title = "Descriptive Statistics", 
    header = TRUE, 
    style = sm_style(
        left_col = \(x) cli::col_red(cli::style_bold(x)),
        right_col = \(x) cli::col_cyan(x), 
        title = "bold", 
        sep = ":  "
    )
)
```

Supported named style strings:

| String                                   | Effect                              |
|------------------------------------------|-------------------------------------|
| `"bold"`                                 | Bold text                           |
| `"italic"`                               | Italic text                         |
| `"blue"`, `"red"`, `"green"`, `"yellow"` | Foreground colour                   |
| `"blue_bold"`                            | Colour + bold (combinable with `_`) |
| `"red_italic"`                           | Colour + italic                     |

More example: Imagine you want to apply for the p-value of the output from `rstatix::cor_test()`, an earlier example. In `corr_matrix()`, you can even conditionally format the specified value from `new_corr_data()`. 

```{r}
cor_mat |> 
    with({
        corr_matrix(
            new_corr_data(
                var1 = var1,
                var2 = var2,
                corr = cor,
                statistic = statistic,
                pval = p,
                conf_int = conf_int
            ),
            title = "Pearson Correlation Matrix",
            style = cm_style(
                pval = function(x) {
                    x_num = as.numeric(x)
                    if (is.na(x_num) || x_num > 0.05) {
                        cli::style_italic(x) 
                    } else if (x_num > 0.01) {
                        cli::col_red(x)
                    } else {
                        cli::style_bold("<0.001")
                    }
                }
            )
        )
    })
```
