% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/table_categorical.R
\name{table_categorical}
\alias{table_categorical}
\title{Categorical summary table}
\usage{
table_categorical(
  data,
  select,
  by = NULL,
  labels = NULL,
  levels_keep = NULL,
  include_total = TRUE,
  drop_na = TRUE,
  weights = NULL,
  rescale = FALSE,
  correct = FALSE,
  simulate_p = FALSE,
  simulate_B = 2000,
  percent_digits = 1,
  p_digits = 3,
  v_digits = 2,
  assoc_measure = "auto",
  assoc_ci = FALSE,
  decimal_mark = ".",
  output = c("default", "data.frame", "long", "tinytable", "gt", "flextable", "excel",
    "clipboard", "word"),
  indent_text = "  ",
  indent_text_excel_clipboard = strrep(" ", 6),
  add_multilevel_header = TRUE,
  blank_na_wide = FALSE,
  excel_path = NULL,
  excel_sheet = "Categorical",
  clipboard_delim = "\\t",
  word_path = NULL
)
}
\arguments{
\item{data}{A data frame.}

\item{select}{Columns to include as row variables. Supports tidyselect
syntax and character vectors of column names.}

\item{by}{Optional grouping column used for columns/groups. Accepts an
unquoted column name or a single character column name.}

\item{labels}{An optional character vector of display labels for the
variables named in \code{select} (must be the same length and in the same
order). When \code{NULL} (the default), column names are used as-is.}

\item{levels_keep}{Optional character vector of levels to keep/order for row
modalities. If \code{NULL}, all observed levels are kept.}

\item{include_total}{Logical. If \code{TRUE} (the default), includes a \code{Total} group
when available.}

\item{drop_na}{Logical. If \code{TRUE} (the default), removes rows with \code{NA} in the
row/group variable before each cross-tabulation. If \code{FALSE}, missing values
are displayed as a dedicated \code{"(Missing)"} level.}

\item{weights}{Optional weights. Either \code{NULL} (the default), a numeric vector
of length \code{nrow(data)}, or a single column in \code{data} supplied as an
unquoted name or a character string.}

\item{rescale}{Logical. If \code{FALSE} (the default), weights are used as-is.
If \code{TRUE}, rescales weights so total weighted N matches raw N.
Passed to \code{spicy::cross_tab()}.}

\item{correct}{Logical. If \code{FALSE} (the default), no continuity correction is
applied. If \code{TRUE}, applies Yates correction in 2x2 chi-squared contexts.
Passed to \code{spicy::cross_tab()}.}

\item{simulate_p}{Logical. If \code{FALSE} (the default), uses asymptotic p-values.
If \code{TRUE}, uses Monte Carlo simulation. Passed to \code{spicy::cross_tab()}.}

\item{simulate_B}{Integer. Number of Monte Carlo replicates when
\code{simulate_p = TRUE}. Defaults to \code{2000}.}

\item{percent_digits}{Number of digits for percentages in report outputs.
Defaults to \code{1}.}

\item{p_digits}{Number of digits for p-values (except \verb{< .001}).
Defaults to \code{3}.}

\item{v_digits}{Number of digits for the association measure. Defaults
to \code{2}.}

\item{assoc_measure}{Passed to \code{\link[=cross_tab]{cross_tab()}}. Which association measure
to report (\code{"auto"}, \code{"cramer_v"}, \code{"phi"}, \code{"gamma"}, \code{"tau_b"},
\code{"tau_c"}, \code{"somers_d"}, \code{"lambda"}, \code{"none"}). Defaults to \code{"auto"}.}

\item{assoc_ci}{Passed to \code{\link[=cross_tab]{cross_tab()}}. If \code{TRUE}, includes the
confidence interval of the association measure. In data formats
(\code{"data.frame"}, \code{"long"}, \code{"excel"}, \code{"clipboard"}), two extra
columns \verb{CI lower} and \verb{CI upper} are added.
In rendered formats (\code{"gt"}, \code{"tinytable"}, \code{"flextable"}, \code{"word"}),
the CI is shown inline (e.g., \code{.14 [.08, .19]}).
Defaults to \code{FALSE}.}

\item{decimal_mark}{Decimal separator (\code{"."} or \code{","}). Defaults to \code{"."}.}

\item{output}{Output format. One of:
\itemize{
\item \code{"default"} (a printed ASCII table, returned invisibly)
\item \code{"data.frame"} (a wide numeric \code{data.frame})
\item \code{"long"} (a long numeric \code{data.frame})
\item \code{"tinytable"} (requires \code{tinytable})
\item \code{"gt"} (requires \code{gt})
\item \code{"flextable"} (requires \code{flextable})
\item \code{"excel"} (requires \code{openxlsx2})
\item \code{"clipboard"} (requires \code{clipr})
\item \code{"word"} (requires \code{flextable} and \code{officer})
}}

\item{indent_text}{Prefix used for modality labels in report table building.
Defaults to \code{"  "} (two spaces).}

\item{indent_text_excel_clipboard}{Stronger indentation used in Excel and
clipboard exports. Defaults to six non-breaking spaces.}

\item{add_multilevel_header}{Logical. If \code{TRUE} (the default), merges top
headers in Excel export.}

\item{blank_na_wide}{Logical. If \code{FALSE} (the default), \code{NA} values are kept
as-is in wide raw output. If \code{TRUE}, replaces them with empty strings.}

\item{excel_path}{Path for \code{output = "excel"}. Defaults to \code{NULL}.}

\item{excel_sheet}{Sheet name for Excel export. Defaults to \code{"Categorical"}.}

\item{clipboard_delim}{Delimiter for clipboard text export. Defaults to \code{"\\t"}.}

\item{word_path}{Path for \code{output = "word"} or optional save path when
\code{output = "flextable"}. Defaults to \code{NULL}.}
}
\value{
Depends on \code{output}:
\itemize{
\item \code{"default"}: prints a styled ASCII table and returns the
underlying \code{data.frame} invisibly (S3 class
\code{"spicy_categorical_table"}).
\item \code{"data.frame"}: a wide \code{data.frame} with one row per
variable--level combination.
When \code{by} is used, the columns are \code{Variable}, \code{Level}, and one
pair of \code{n} / \verb{\\\%} columns per group level (plus \code{Total} when
\code{include_total = TRUE}), followed by \code{Chi2}, \code{df}, \code{p}, and the
association measure column.
When \code{by = NULL}, the columns are \code{Variable}, \code{Level}, \code{n}, \verb{\\\%}.
\item \code{"long"}: a long \code{data.frame} with columns \code{variable},
\code{level}, \code{group}, \code{n}, \code{percent} (and \code{chi2}, \code{df}, \code{p},
association measure columns when \code{by} is used).
\item \code{"tinytable"}: a \code{tinytable} object.
\item \code{"gt"}: a \code{gt_tbl} object.
\item \code{"flextable"}: a \code{flextable} object.
\item \code{"excel"} / \code{"word"}: writes to disk and returns the file
path invisibly.
\item \code{"clipboard"}: copies the table and returns the display
\code{data.frame} invisibly.
}
}
\description{
Builds a publication-ready frequency or cross-tabulation table for one
or many categorical variables selected with tidyselect syntax.

With \code{by}, produces grouped cross-tabulation summaries (using
\code{\link[=cross_tab]{cross_tab()}} internally) with Chi-squared \emph{p}-values and optional
association measures.
Without \code{by}, produces one-way frequency-style summaries.

Multiple output formats are available via \code{output}: a printed ASCII
table (\code{"default"}), a wide or long numeric \code{data.frame}
(\code{"data.frame"}, \code{"long"}), or publication-ready tables
(\code{"tinytable"}, \code{"gt"}, \code{"flextable"}, \code{"excel"}, \code{"clipboard"},
\code{"word"}).
}
\details{
When \code{by} is used, each selected variable is cross-tabulated against
the grouping variable with \code{\link[=cross_tab]{cross_tab()}}. Chi-squared statistics,
\emph{p}-values, and the chosen association measure are reported for each
variable.

Optional output engines require suggested packages:
\itemize{
\item \pkg{tinytable} for \code{output = "tinytable"}
\item \pkg{gt} for \code{output = "gt"}
\item \pkg{flextable} for \code{output = "flextable"}
\item \pkg{flextable} + \pkg{officer} for \code{output = "word"}
\item \pkg{openxlsx2} for \code{output = "excel"}
\item \pkg{clipr} for \code{output = "clipboard"}
}
}
\examples{
# Long numeric output
table_categorical(
  data = sochealth,
  select = c(smoking, physical_activity),
  by = education,
  labels = c("Current smoker", "Physical activity"),
  output = "long"
)

# ASCII console output (default)
table_categorical(
  data = sochealth,
  select = c(smoking, physical_activity),
  by = sex
)

# One-way frequency-style table
table_categorical(
  data = sochealth,
  select = c(smoking, physical_activity)
)

# Wide numeric data.frame
table_categorical(
  data = sochealth,
  select = c(smoking, physical_activity),
  by = education,
  labels = c("Current smoker", "Physical activity"),
  output = "data.frame"
)

# Weighted example
table_categorical(
  data = sochealth,
  select = c(smoking, physical_activity),
  by = education,
  labels = c("Current smoker", "Physical activity"),
  weights = "weight",
  rescale = TRUE,
  simulate_p = FALSE,
  output = "long"
)

\donttest{
# Optional output: tinytable
if (requireNamespace("tinytable", quietly = TRUE)) {
  table_categorical(
    data = sochealth,
    select = c(smoking, physical_activity),
    by = sex,
    labels = c("Current smoker", "Physical activity"),
    output = "tinytable"
  )
}

# Optional output: Excel
if (requireNamespace("openxlsx2", quietly = TRUE)) {
  table_categorical(
    data = sochealth,
    select = c(smoking, physical_activity),
    by = education,
    labels = c("Current smoker", "Physical activity"),
    output = "excel",
    excel_path = tempfile(fileext = ".xlsx")
  )
}
}

}
\seealso{
\code{\link[=table_continuous]{table_continuous()}} for continuous variables;
\code{\link[=cross_tab]{cross_tab()}} for two-way cross-tabulations; \code{\link[=freq]{freq()}} for one-way
frequency tables.
}
