---
title: "Filtering Data with the dataFilter Module"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Filtering Data with the dataFilter Module}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
    collapse = TRUE,
    comment = "#>",
    eval = FALSE
)
```

## Introduction

The `dataFilter` module renders an interactive table with a filter box on every
column and returns **only the rows the user has left visible**. Because it hands
that filtered data back as a reactive, you can plug it in front of any plotting
module so the plot always reflects the current table filters.

Like every module in **VizModules**, it comes in two halves that share an `id`:

- `dataFilterUI(id)` -- places the table in your UI.
- `dataFilterServer(id, data, ...)` -- runs the table and returns the filtered
  data.

## What the module does

The server is small, and its job is easy to describe:

1. **Prepare the data.** By default (`factor.char.cols = TRUE`) every character
   column is converted to a factor. This is purely cosmetic: it makes DT show a
   drop-down select filter for those columns instead of a free-text search box.
2. **Render the table.** A [DT](https://rstudio.github.io/DT/) table is drawn
   with a filter row at the top of each column (`filter = "top"`).
3. **Return the visible rows.** DT continuously reports which rows survive the
   current filters via `input$table_rows_all`. The module subsets the data to
   those rows, calls `droplevels()` so filtered-out categories don't linger in
   plot legends or axes, and returns the result as a reactive.

Conceptually:

```
data (reactive) --> character cols to factors --> DT table (user filters)
                                                        |
                                     input$table_rows_all (visible rows)
                                                        v
                                              filtered data (reactive)
```

### Arguments

| Argument | Default | Purpose |
|----------|---------|---------|
| `id` | -- | Module id; must match the `id` given to `dataFilterUI()`. |
| `data` | -- | A **reactive** containing the data frame to display and filter. |
| `factor.char.cols` | `TRUE` | Convert character columns to factors so they get drop-down filters. |
| `page.length` | `10` | Rows shown per page. |
| `col.visibility` | `FALSE` | Add a "Columns" button so users can show/hide individual columns. |
| `hide.columns` | `NULL` | Column names (or positions) to hide when the table is first drawn. |

### Return value

A **reactive** that evaluates to the filtered subset of `data`. This is the key
to the module's flexibility: a reactive can be read by as many consumers as you
like, so the same filtered data can drive one plot or several.

## Showing fewer columns

Wide data frames make for a busy table and a wall of filter boxes. Pass the
columns you don't want on screen to `hide.columns` and the table is drawn
without them -- no column, no filter box:

```{r hide-columns}
filtered <- dataFilterServer("filter", reactive(example_bar),
    hide.columns = c("internal_id", "batch")
)
```

Two things to keep in mind:

- **Hiding is display-only.** The returned reactive still contains every
  column, so a plotting module can map a hidden column to an aesthetic even
  though users never see it in the table.
- **Hidden stays hidden unless you say otherwise.** Add `col.visibility = TRUE`
  to get DT's "Columns" button, which lets users switch any column -- including
  the ones you hid -- back on.

```{r hide-columns-toggle}
filtered <- dataFilterServer("filter", reactive(example_bar),
    hide.columns = c("internal_id", "batch"),
    col.visibility = TRUE
)
```

The name-to-position lookup behind `hide.columns` is exported as
`resolve_column_targets()`, so you can reach for it in your own tables too.
DataTables addresses columns in `columnDefs` by zero-based position; this turns
column names into those positions (pass `rownames = TRUE` if your table shows a
row-names column, which shifts everything over by one). Hiding is just one use
- the same targets drive `width`, `orderable`, `className`, and friends:

```{r resolve-helper}
DT::datatable(
    example_bar,
    rownames = FALSE,
    options = list(
        columnDefs = list(list(
            visible = FALSE,
            targets = resolve_column_targets(example_bar, c("internal_id", "batch"))
        ))
    )
)
```

## A minimal example

Pass the returned reactive straight into a plotting module's `data` argument.
When the user filters the table, the plot redraws automatically.

```{r minimal}
library(shiny)
library(VizModules)

ui <- fluidPage(
    plotthis_BarPlotOutputUI("bar"),
    dataFilterUI("filter"),
    plotthis_BarPlotInputsUI("bar", example_bar)
)

server <- function(input, output, session) {
    # Returns a reactive of only the currently-visible rows.
    filtered <- dataFilterServer("filter", reactive(example_bar))

    # The plot tracks the filter automatically.
    plotthis_BarPlotServer("bar", data = filtered)
}

if (interactive()) shinyApp(ui, server)
```

Note the shared `id`: `"bar"` is used for the module's `OutputUI`, `InputsUI`,
and `Server`, while `"filter"` ties `dataFilterUI()` to `dataFilterServer()`.

## Linking several modules to one table

Because the filtered data is just a reactive, you don't need any special
machinery to connect it to more than one plot -- **feed the same `filtered`
reactive into each module's server**. Every module reading it re-renders
whenever the filter changes, so a single table keeps all of the plots in sync.

```{r multi}
library(shiny)
library(shinyjs)
library(VizModules)

ui <- fluidPage(
    useShinyjs(),
    fluidRow(
        column(6, plotthis_BarPlotOutputUI("bar")),
        column(6, plotthis_BoxPlotOutputUI("box"))
    ),
    dataFilterUI("filter"),
    fluidRow(
        column(6, plotthis_BarPlotInputsUI("bar", example_bar)),
        column(6, plotthis_BoxPlotInputsUI("box", example_bar))
    )
)

server <- function(input, output, session) {
    # One filtered reactive, shared by both modules.
    filtered <- dataFilterServer("filter", reactive(example_bar))

    plotthis_BarPlotServer("bar", data = filtered)
    plotthis_BoxPlotServer("box", data = filtered)
}

if (interactive()) shinyApp(ui, server)
```

The only rule to remember is namespacing: **each plotting module's `InputsUI`,
`OutputUI`, and `Server` must share the same top-level `id`** (`"bar"` and
`"box"` above). Nothing wraps the module servers, so their ids resolve to the
top-level namespace where their UI lives, and everything connects.

A ready-to-run version of this app ships with the package:

```{r run-example}
shiny::runApp(
    system.file("examples", "linked-filter", package = "VizModules")
)
```

## How it compares to `createModuleApp()`

The `*App()` helpers and `createModuleApp()` already wire a `dataFilter` table
to a single plot for you (see the *Quick Start* vignette). Reach for
`dataFilterUI()` / `dataFilterServer()` directly when you want to control the
layout yourself -- for example, to share one table across multiple plots as
shown above, or to embed the table inside a larger custom module.

## Summary

- `dataFilterServer()` returns a **reactive of the currently-visible rows**.
- Plug that reactive into any plotting module's `data` argument.
- Feed the *same* reactive into several servers to link multiple plots to one
  table -- no extra wiring required.
- Keep each module's `InputsUI`, `OutputUI`, and `Server` on a shared, top-level
  `id` so namespaces line up.
