% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/paintr-app.R
\name{ptr_app}
\alias{ptr_app}
\title{Build a Shiny App from a \code{ggpaintr} Formula}
\usage{
ptr_app(
  formula,
  envir = parent.frame(),
  ui_text = NULL,
  expr_check = TRUE,
  safe_to_remove = character(),
  css = NULL,
  spec = NULL
)
}
\arguments{
\item{formula}{Either a single character scalar containing a ggplot
expression with \code{ggpaintr} placeholders, or an unquoted ggplot
expression supplied directly. Expression-mode is captured with
\code{\link[rlang:defusing-advanced]{rlang::enexpr()}} at the public boundary, then deparsed to a string
before reaching the shared translate pipeline; both modes produce
equivalent apps. A bare symbol bound to a string in the calling frame
(e.g. \verb{f <- "..."; ptr_app(f)}) is resolved and treated as string
mode. Pre-quoted wrappers (\code{\link[rlang:expr]{rlang::expr()}}, \code{\link[rlang:defusing-advanced]{rlang::quo()}},
\code{\link[base:substitute]{base::quote()}}, \code{\link[base:bquote]{base::bquote()}}) at the captured root are unwrapped
one level. \verb{!!} splicing inside the captured expression is honoured
via \code{\link[rlang:defusing-advanced]{rlang::enexpr()}}. \strong{Native pipe (\verb{|>}) caveat:} in expression
mode, R's parser desugars \verb{|>} before capture, so the rendered code
shows the desugared nested-call form. Stay in string mode (or use
\verb{\%>\%}) if you need \verb{|>} preserved.}

\item{envir}{Environment used to resolve local data objects.}

\item{ui_text}{Optional named list of copy overrides; see \code{\link[=ptr_ui_text]{ptr_ui_text()}}
for the full schema and current defaults.}

\item{expr_check}{Controls formula-level \code{ppExpr} validation. Three modes:
\code{TRUE} (default) applies the built-in denylist + AST walker;
\code{FALSE} disables formula-level validation (for local prototyping with
trusted formulas only); a \code{list} with \code{deny_list} and/or \code{allow_list}
entries (character vectors) customises the formula-level policy without
disabling it. Code typed into a \code{ppExpr} box at runtime is always
screened against the built-in denylist, regardless of this setting. For
the walker model see the safety chapter of the ggpaintr book
(development-version docs):
\url{https://willju-wangqian.github.io/ggpaintr-book/safety.html}.}

\item{safe_to_remove}{Character vector of additional function names whose
zero-argument calls should be dropped after placeholder substitution
leaves them empty. Defaults to \code{character()}. See \strong{Empty-call cleanup}
below. A user-typed \code{ppExpr} always wins — whatever the user enters into
an \code{ppExpr} box is honoured verbatim, even if its top-level name is in
\code{safe_to_remove}.}

\item{css}{Optional character vector of paths to additional CSS files. Each
is served as a static resource and linked after \code{ggpaintr}'s bundled
stylesheet, so its rules override the default \verb{.ptr-*} styling. Relative
\code{url(...)} references inside a file resolve against that file's own
directory. Defaults to \code{NULL} (no extra stylesheet).}

\item{spec}{An optional named list of fully-qualified Shiny input id ->
value, used to override widget defaults at session boot.}
}
\value{
A \code{shiny.appobj}.
}
\description{
Translates \code{formula} into the typed AST, builds the per-layer panel UI,
and wires the server end-to-end. Returns a \code{shiny.appobj} ready to be run.
This page is the canonical reference for the formula grammar and the
empty-call cleanup rule used by every public entry point.
}
\section{Formula grammar}{

A \code{ggpaintr} formula is a single \code{ggplot()} call written as a string. Drop
one of five placeholder keywords anywhere a value would normally go, and
the runtime substitutes the user's input back into the expression at
render time.

\describe{
\item{\code{ppVar}}{Column picker, data-aware. Renders as a \code{selectInput}
populated with the upstream data's column-name vector. Example:
\code{aes(x = ppVar)}.}
\item{\code{ppText}}{Free-text input. Renders as a \code{textInput}. Example:
\code{labs(title = text)}.}
\item{\code{ppNum}}{Numeric input. Renders as a \code{numericInput}. Example:
\code{geom_point(size = ppNum)}.}
\item{\code{ppExpr}}{Code editor, validated by \code{expr_check}. The only keyword
that accepts arbitrary R code; for the safety model see the ggpaintr
book's safety chapter (development-version docs,
\url{https://willju-wangqian.github.io/ggpaintr-book/safety.html}).
Example: \code{facet_wrap(ppExpr)}.}
\item{\code{ppUpload}}{File picker, returns a data frame. Renders as a
\code{fileInput} plus an optional dataset-name textbox. Accepted formats:
\code{.csv}, \code{.tsv}, \code{.rds}, \code{.xlsx}, \code{.xls}, \code{.json}. Uploaded data is
normalized via \code{\link[=ptr_normalize_column_names]{ptr_normalize_column_names()}} automatically. Example:
\code{ggplot(ppUpload, ...)}.}
}

Any keyword occurrence may carry \code{shared = "<id>"} to lift the widget out
of its per-layer panel into a top-level shared section. Used by
\code{\link[=ptr_app_grid]{ptr_app_grid()}} to drive multiple plots from one control. See
\code{vignette("ggpaintr-tutorial")} for worked examples of each keyword.
}

\section{Empty-call cleanup}{

When a placeholder resolves to "missing" (an empty \code{ppVar} pick, a blank
\code{ppText}, a cleared \code{ppNum}, an unchecked layer checkbox), its argument is
dropped from the generated code. If the surrounding call is left empty
and its bare name is in the curated cleanup list, the whole call
disappears too. This rule applies to both placeholder-driven empties and
user-authored literal empty calls like \code{+ labs()}.

Curated \code{ggplot2} names that are dropped when empty:

\preformatted{theme, labs, xlab, ylab, ggtitle,
facet_wrap, facet_grid, facet_null,
xlim, ylim, lims, expand_limits,
guides, annotate, annotation_custom,
annotation_map, annotation_raster,
aes, aes_, aes_q, aes_string,
element_text, element_line, element_rect,
element_point, element_polygon, element_geom}

Empty calls to similar no-op helpers from \code{dplyr}, \code{tidyr}, \code{tibble},
\code{pillar}, \code{purrr}, \code{stringr}, \code{forcats}, \code{lubridate}, and \code{hms} are
covered by the same rule.

\verb{geom_*()} and \verb{stat_*()} layers are \strong{never} dropped, regardless of
whether they end up empty — they inherit their aesthetics from
\code{ggplot()} and remain meaningful with no arguments.

\code{element_blank()} is intentionally \strong{not} in the cleanup list: its
empty form is a meaningful "suppress" directive, not a no-op.

Third-party helpers (e.g. \code{pcp_theme()} from \code{ggpcp}) are not in the
cleanup list — being absent is the "removal safety unknown" signal.
Use \code{safe_to_remove = c("pcp_theme")} to opt a specific name in.
}

\examples{
if (interactive()) {
  # Expression mode (primary): pass the unquoted ggplot expression.
  ptr_app(ggplot(mtcars, aes(x = ppVar, y = ppVar)) + geom_point())
  # `!!` splices a value into the expression.
  col <- rlang::sym("mpg")
  ptr_app(ggplot(mtcars, aes(x = !!col, y = ppVar)) + geom_point())
  # String mode (fallback): the same formula as text.
  ptr_app("ggplot(mtcars, aes(x = ppVar, y = ppVar)) + geom_point()")
}
}
\seealso{
\code{\link[=ptr_app_bslib]{ptr_app_bslib()}} for the same contract with a \code{bslib} theme;
\code{\link[=ptr_app_grid]{ptr_app_grid()}} for multi-plot apps with shared widgets;
\code{\link[=ptr_define_placeholder_value]{ptr_define_placeholder_value()}} et al. for registering custom
keywords; \code{\link[=ptr_ui_text]{ptr_ui_text()}} for copy overrides; \code{\link[=ptr_css]{ptr_css()}} for the
\verb{css =} argument and themable CSS custom properties;
\code{vignette("ggpaintr-tutorial")} for tutorial examples.
}
