Nothing
Chart <-
function(x=NULL, by=NULL, y=NULL, data=d, filter=NULL,
type=c("bar", "radar", "bubble", "pie", "icicle", "treemap"),
hole=0.65, # pie chart
radius=0.35, power=0.5, # bubble chart
stat=c("mean", "sum", "sd", "deviation", "min", "median", "max"),
stat_x=c("count", "proportion"),
facet=NULL, n_row=NULL, n_col=NULL, aspect="fill",
horiz=FALSE, sort=c("0", "-", "+"),
beside=FALSE, stack100=FALSE,
gap=NULL, scale_y=NULL, one_plot=NULL,
theme=getOption("theme"),
fill=NULL,
color=getOption("bar_color_discrete"),
transparency=getOption("trans_bar_fill"),
fill_split=NULL, fill_scaled=FALSE, fill_chroma=75,
labels=c("%", "input", "prop", "off"),
labels_position=c("in","out"),
labels_color="white",
labels_size=0.75,
labels_decimals=NULL,
labels_cut=NULL,
xlab=NULL, ylab=NULL, main=NULL, sub=NULL,
lab_adjust=c(0,0), margin_adjust=c(0,0,0,0),
pad_y_min=0, pad_y_max=0,
rotate_x=getOption("rotate_x"), rotate_y=getOption("rotate_y"),
break_x=NULL, offset=getOption("offset"),
axis_fmt=c("K", ",", ".", ""), axis_x_pre="", axis_y_pre="",
label_max=100,
legend_title=NULL, legend_position="right_margin",
legend_labels=NULL, legend_horiz=FALSE,
legend_size=NULL, legend_abbrev=10, legend_adjust=0,
add=NULL, x1=NULL, y1=NULL, x2=NULL, y2=NULL,
quiet=getOption("quiet"), do_plot=TRUE,
use_plotly=getOption("lessR.use_plotly"),
pdf_file=NULL, width=6.5, height=6,
digits_d=NULL, out_size=80,
n_cat=getOption("n_cat"), value_labels=NULL,
rows=NULL, facet1=NULL,
eval_df=NULL, fun_call=NULL, ...) {
if (is.null(fun_call)) fun_call <- match.call()
mc <- match.call()
y.is.named <- "y" %in% names(mc)
labels <- match.arg(labels)
labels_position <- match.arg(labels_position)
# Note: if fill contains getColors() call, fill already evaluated
fill.name <- deparse(substitute(fill))
if (length(type) == 1 && type == "sunburst")
type <- "pie"
else
type <- match.arg(type)
stat.miss <- ifelse (missing(stat), TRUE, FALSE)
if (stat.miss) stat <- NULL
if (!is.null(stat[1])) stat <- match.arg(stat) # if condition for shiny
stat_x <- match.arg(stat_x)
options(xname = NULL)
options(yname = NULL)
options(byname = NULL)
# get parameter names passed in function call, does not evaluate the arg
nms <- names(as.list(match.call()))
if (!is.null(nms)) {
if ("facet2" %in% nms) {
cat("\n"); stop(call.=FALSE, "\n------\n",
"parameter facet2 not applicable to BarChart\n\n")
}
}
if (!is.null(pdf_file) && type != "bar") {
cat("\n"); stop(call.=FALSE, "\n------\n",
"Saving PDF files only works for bar charts.\n\n")
}
if (type == "bubble" && !is.null(facet)) {
cat("\n"); stop(call.=FALSE, "\n------\n",
"The facet option is not available for bubble plots.\n\n")
}
facet.miss <- ifelse (missing(facet), TRUE, FALSE)
if (use_plotly && !(type == "bar" && !facet.miss)) {
txt <- "[Interactive chart from the Plotly R package (Sievert, 2020)]"
cat(txt, "\n\n")
}
# old stuff ---------------------------------------------------------------
if (!missing(rows))
message(">>> Parameter rows renamed to: filter.\n",
" Change to filter, rows will stop working in the future.\n")
if (!missing(n_cat) || !missing(value_labels)) {
message(">>> Parameters n_cat and value_labels will no longer ",
"work in the future.\n",
" Better to convert a categorical integer variable to ",
"a factor.\n")
}
if (deparse(substitute(fill)) == "(count)") {
message(">>> Now set to TRUE the more general parameter: fill_scale.\n\n")
fill <- NULL
}
dots <- list(...)
n.values <- 0
if (length(dots) > 0) {
for (i in seq_along(dots)) {
if (grepl("values", names(dots)[i], fixed=TRUE)) {
n.values <- n.values + 1
if (n.values == 1)
message(">>> Parameters values, values_color, etc. now ",
"renamed to: labels, labels_color, etc.\n",
" Old parameter names will stop working in the future.\n")
if (names(dots)[i] == "values") labels <- dots[[i]]
if (names(dots)[i] == "values_color") labels_color <- dots[[i]]
if (names(dots)[i] == "values_size") labels_size <- dots[[i]]
if (names(dots)[i] == "values_digits") labels_decimals <- dots[[i]]
if (names(dots)[i] == "values_position") labels_position <- dots[[i]]
if (names(dots)[i] == "values_cut") labels_cut <- dots[[i]]
}
if (names(dots)[i] == "addtop") pad_y_max <- dots[[i]]
if (names(dots)[i] == "add_top") pad_y_max <- dots[[i]]
if (names(dots)[i] == "stat_yx") stat <- dots[[i]]
if (grepl(".", names(dots)[i], fixed=TRUE)) {
nm <- gsub(".", "_", names(dots)[i], fixed=TRUE) # dot to _
assign(nm, dots[[i]])
get(nm)
}
}
}
if (!is.null(stat)) if (stat[1] == "proportion") {
cat("\n"); stop(call.=FALSE, "\n------\n",
"now use parameter stat_x for \"proportion\" \n",
" \"proportion\" only applies when there is no y numeric variable\n\n")
}
Trellis <- ifelse(!facet.miss && type == "bar", TRUE, FALSE)
# set variables -----------------------------------------------------------
trans <- transparency
if (fill_scaled && is.null(fill_split)) fill_split <- 0
if (nzchar(axis_fmt[1])) axis_fmt <- match.arg(axis_fmt)
fill.miss <- ifelse (missing(fill), TRUE, FALSE)
color.miss <- ifelse (missing(color), TRUE, FALSE)
transparency.miss <- ifelse (missing(transparency), TRUE, FALSE)
horiz.miss <- ifelse (missing(horiz), TRUE, FALSE)
y.miss <- ifelse (missing(y), TRUE, FALSE)
by.miss <- ifelse (missing(by), TRUE, FALSE)
main.miss <- ifelse (missing(main), TRUE, FALSE)
for (i in 1:length(color)) if (color[i] == "off") color[i] <- "transparent"
sort.miss <- ifelse (missing(sort), TRUE, FALSE)
sort <- match.arg(sort)
labels.miss <- ifelse (missing(labels), TRUE, FALSE)
labels <- match.arg(labels)
# set some parameter values -----------------------------------------------
proportion <- ifelse (stat_x[1] == "proportion", TRUE, FALSE) # make stat_x
if (horiz) {
if (sort == "+") sort <- "x"
if (sort == "-") sort <- "+"
if (sort == "x") sort <- "-"
}
if (missing(break_x))
break_x <- ifelse (!horiz && rotate_x==0, TRUE, FALSE)
xlab.adj <- lab_adjust[1]; ylab.adj <- lab_adjust[2]
tm.adj <- margin_adjust[1]; rm.adj <- margin_adjust[2]
bm.adj <- margin_adjust[3]; lm.adj <- margin_adjust[4]
lm.adj <- lm.adj + .1 # pull these margins back a bit for bc
bm.adj <- bm.adj + .1
if (missing(labels_color)) {
labels_color <- "white"
if (labels_position == "out") labels_color <- getOption("axis.text.color")
}
# ensure valid parameter values
.bcParamValid(y.miss, by.miss, facet.miss, Trellis, sort,
fill_split, fill_scaled, fill_chroma, theme,
fill.miss, labels_position, stat.miss)
# data frame stuff --------------------------------------------------------
data.miss <- ifelse (missing(data), TRUE, FALSE)
# let deprecated mydata work as default
dfs <- .getdfs()
mydata.ok <- FALSE
if (!is.null(dfs)) {
if ("mydata" %in% dfs && !("d" %in% dfs)) {
d <- mydata
rm(mydata)
df.name <- "mydata"
mydata.ok <- TRUE
options(dname = df.name)
}
}
# get name of data table
# df.name is NULL if from shiny interact(), not from user-written shiny code
if (!mydata.ok) {
df.name <- deparse(substitute(data))
options(dname = df.name)
}
shiny <- FALSE
if (!is.null(sys.call(-1))) # is NULL when called directly from R console
if (sys.call(-1) == "renderPlot()") { # from shiny, user or interact()
shiny <- TRUE
data <- eval(substitute(data), envir=parent.frame())
}
# if a tibble, convert to data frame
if (!shiny) {
if (exists(df.name, envir=.GlobalEnv)) {
if (any(grepl("tbl", class(data), fixed=TRUE)))
data <- data.frame(data)
}
}
else # no check for existence of df.name
if (any(grepl("tbl", class(data), fixed=TRUE)))
data <- data.frame(data)
x.name <- deparse(substitute(x), width.cutoff = 120L)
options(xname = x.name)
if (!is.null(x.name))
x.in.global <- .in.global(x.name, quiet) # in global?, includes vars list
else
x.in.global <- FALSE
if (!x.in.global) {
if (df.name != "NULL") { # if NULL, force global (shiny, from interact() )
# force evaluation (not lazy) if data not specified, relies on default d
if (data.miss) {
if (!mydata.ok) .nodf(df.name) # check to see if df exists
# the 1.201 comes from Shiny, need to reset
# l.cex and l.axc are set in interact() before shiny run
if (getOption("lab_cex") == 1.201) {
if (getOption("l.cex") != 1.201) {
style(lab_cex=getOption("l.cex"))
style(axis_cex=getOption("l.axc"))
}
else
style()
}
}
}
else # df.name is NULL
x.in.global <- TRUE
}
eval_df <- !x.in.global
# subset filter (with deprecated rows parameter) --------------------------
if (!missing(filter) || !missing(rows)) {
if (x.in.global) {
cat("\n"); stop(call.=FALSE, "\n------\n",
"Parameter filter not applicable if no data frame\n\n")
}
txt <- .filter(deparse(substitute(filter)))
# get r, label each row as TRUE or FALSE
intYN <- try(eval(parse(text = txt)), silent = TRUE)
if (is.numeric(intYN)) {
r <- rep(FALSE, nrow(data))
r[intYN] <- TRUE
}
else {
if (!missing(filter)) # subset filter
r <- eval(str2expression(txt), envir=data, enclos=parent.frame())
if (!missing(rows)) # tag each row as TRUE or FALSE
R <- eval(substitute(rows), envir=data, enclos=parent.frame())
r <- r & !is.na(r) # set missing for a row to FALSE
}
nr.before <- nrow(data)
if (any(r))
data <- data[r,,drop=FALSE]
if (!quiet) {
if (!missing(filter)) # filter parameter present
cat("\nfilter: ", txt, "\n-----\n")
cat("Rows of data before filtering: ", nr.before, "\n")
cat("Rows of data after filtering: ", nrow(data), "\n\n")
}
} # end filter
# establish if a data frame, otherwise identify variable(s)----------------
# x can be missing entirely, with a data frame passed instead
# if x a vector, then x.name not in data, but also not in global
x.call <- NULL
if (is.null(x.name)) x.name <- ""
if (x.name %in% c("row_names", "row.names")) {
# retain order of row names, otherwise will be alphabetical
x.call <- factor(row.names(data), levels=row.names(data))
if (is.null(xlab)) xlab <- "" # unless specified, drop the axis label
}
else if (!missing(x)) {
if (!x.in.global) {
if (eval_df) {
if (!mydata.ok) if (!shiny) .nodf(df.name) # check to see if df exists
.xcheck(x.name, df.name, names(data)) # x-vars in df?
}
data.vars <- as.list(seq_along(data))
names(data.vars) <- names(data)
ind <- eval(substitute(x), envir=data.vars) # col num of each var
if (length(ind) > 1) data <- data[, ind] # x a vars list, no by vars
if (length(ind) == 1) x.call <- eval(substitute(data$x)) # x is 1 var
}
else { # x is in the global environment (vector, matrix or data frame)
if (is.data.frame(x)) # x a data frame
data <- x
else { # x a vector or matrix in global
if (exists(x.name, where=.GlobalEnv)) if (is.matrix(x)) {
x.name <- xlab
xlab <- NULL
by.name <- legend_title
options(xname = x.name)
options(byname = by.name)
}
x.call <- x
if (is.function(x.call)) x.call <- eval(substitute(data$x))
}
}
# if read from console with text parameter can insert extra space at front
if (is.factor(x.call))
if (nchar(levels(x.call)[1]) > 5)
levels(x.call) <- trimws(levels(x.call), which="left")
else if (is.character(x.call))
if (nchar(x.call[1]) > 5) x.call <- trimws(x.call, which="left")
} # !missing x
# -------------------------------------------------
# -------------------------------------------------
# x is a single var, not a data frame or a var list
if (!is.null(x.call)) {
# --- resolve `by`, which can be a vector ---------------------------------
by.miss <- ifelse(missing(by), TRUE, FALSE)
if (!by.miss) {
by_expr <- substitute(by)
by_vars <- all.vars(by_expr)
get_col <- function(nm) {
# prefer data= if present; else fall back to global
in_global <- if (df.name != "NULL") .in.global(nm, quiet) else TRUE
if (!in_global) {
.xcheck(nm, df.name, names(data))
return(data[[nm]])
} else {
return(get(nm, envir = parent.frame()))
}
}
if (length(by_vars) == 0L) {
# already-evaluated object (rare); coerce to factor
by.call <- try(eval(by_expr, envir = parent.frame()), silent = TRUE)
if (inherits(by.call, "try-error")) by.call <- NULL
if (!is.null(by.call) && !is.data.frame(by.call)) {
if (!is.factor(by.call)) by.call <- factor(by.call)
by.name <- deparse(by_expr)
} else if (is.data.frame(by.call)) {
for (nm in names(by.call))
if (!is.factor(by.call[[nm]])) by.call[[nm]] <- factor(by.call[[nm]])
by.name <- paste(names(by.call), collapse = " - ")
}
}
else if (length(by_vars) == 1L) {
by.call <- get_col(by_vars[1])
if (!is.factor(by.call)) by.call <- factor(by.call)
by.name <- by_vars[1]
}
else {
# vector of by's -> data.frame of factors
by_df <- lapply(by_vars, get_col)
by_df <- lapply(by_df, function(v)
if (is.factor(v)) droplevels(v) else factor(v))
by.call <- as.data.frame(by_df, check.names = FALSE)
names(by.call) <- by_vars
by.name <- paste(by_vars, collapse = " - ")
}
options(byname = by.name)
# by should be categorical or integer variable with <= 10 unique values
v <- by.call[[1]] # always a vector
if (!is.character(v) && !is.factor(v) && !.is.num.cat(v, n_cat = 10)) {
warning("\n\nThe 2nd argument is by= , which should be categorical. \n",
by.name, " likely is not categorical. Maybe set this\n",
"variable to y= , which should be a numerical variable.\n\n")
}
if (labels_position == "out" && !beside) {
warning("\n"); stop(call.=FALSE, "\n------\n",
"labels_position=\"out\" not meaningful for a by variable\n",
" without beside=TRUE\n\n")
}
} # end not by.miss
else {
by.call <- NULL
by.name <- NULL
}
# --- resolve y ------------------------------------------------------
y.name <- deparse(substitute(y), width.cutoff = 120L) # can be NULL
options(yname = y.name)
if (!is.null(y.name))
y.in.global <- .in.global(y.name, quiet) # in global?, also vars list
else
y.in.global <- FALSE
if (!y.in.global) {
if (df.name == "NULL") { # from shiny
y.in.global <- TRUE
}
}
eval_df <- !y.in.global
# if not missing, then must be aggregated data
if (!missing(y)) { # assign y.call from data or from global
y.name <- deparse(substitute(y))
# see if var exists in data frame, if y not in global Env or fun call
if (eval_df)
if (!y.in.global) .xcheck(y.name, df.name, names(data))
if (!y.in.global)
y.call <- eval(substitute(data$y))
else { # vars that are function names get assigned to global
y.call <- y
if (is.function(y.call)) y.call <- eval(substitute(data$y))
}
if (is.null(digits_d)) digits_d <- .max.dd(y.call)
} # end !missing(y)
else {
y.name <- "Count"
y.call <- NULL
if (is.null(digits_d)) digits_d <- 0 # y will be counts
}
# --- resolve facet --------------------------------------------------
facet.call <- NULL
facet.name <- NULL
if (!missing(facet)) {
facet_expr <- substitute(facet)
facet_var <- deparse(facet_expr)
get_col <- function(nm) {
in_global <- if (df.name != "NULL") .in.global(nm, quiet) else TRUE
if (!in_global) { .xcheck(nm, df.name, names(data)); data[[nm]] }
else { get(nm, envir = parent.frame()) }
}
v <- get_col(facet_var)
# Ensure factor with dropped unused levels (matches old behavior)
facet.call <- if (is.factor(v)) droplevels(v) else factor(v)
facet.name <- facet_var
## IMPORTANT: use the legacy option name expected by .bar.lattice()
options(facet1name = facet.name)
}
# ------------------------------------------------------------
# ----------- x, y, by, and facet variables established -----
# ------------------------------------------------------------
# suggestions -------------------------------------------------------------
txsug <- ""
if (getOption("suggest")) {
# function call, with last ) removed for suggestions
fncl <- .fun_call.deparse(fun_call) # class call to class character
fncl <- gsub(")$", "", fncl) # get function call less closing )
fncl <- gsub(" = ", "=", fncl)
txsug <- ">>> Suggestions or enter: style(suggest=FALSE)"
if (!is.null(by.call))
fc <- paste("Chart(", x.name, ", by=", by.name, ",", sep="")
else
fc <- paste("Chart(", x.name, sep="")
if (!grepl("radar", fncl)) {
txt <- " type=\"radar\"" # many options"
cmt <- " # Plotly radar chart"
txsug <- paste(txsug, "\n", fc, txt, ")", cmt, "\n", sep="")
}
if (!grepl("treemap", fncl)) {
txt <- " type=\"treemap\"" # many options"
cmt <- " # Plotly treemap chart"
txsug <- paste(txsug, fc, txt, ")", cmt, "\n", sep="")
}
if (!grepl("pie", fncl)) {
txt <- " type=\"pie\"" # many options"
cmt <- " # Plotly pie/sunburst chart"
txsug <- paste(txsug, fc, txt, ")", cmt, "\n", sep="")
}
if (!grepl("icicle", fncl)) {
txt <- " type=\"icicle\"" # many options"
cmt <- " # Plotly icicle chart"
txsug <- paste(txsug, fc, txt, ")", cmt, "\n", sep="")
}
if (!grepl("bubble", fncl)) {
txt <- " type=\"bubble\"" # many options"
cmt <- " # Plotly bubble chart"
txsug <- paste(txsug, fc, txt, ")", cmt, "\n", sep="")
}
txsug <- paste(txsug, "\n")
class(txsug) <- "out"
print(txsug)
} # end suggest
# is a numerical, continuous variable in the second or by position?
# assumes there is only one by, and n.by is the number of levels
n.by <- ifelse (!is.null(by.call), length(unique(by.call)), 0)
if (is.null(by.call)) by.name <- NULL
if (!is.null(by.call) && is.numeric(by.call) && !y.is.named) {
if (!stat.miss && y.miss) {
cat("\n"); stop(call.=FALSE, "\n","------\n",
"Parameter stat requires a numerical y-variable to transform.\n\n",
"Perhaps you have a numerical variable that you wish to transform.\n",
"If so, then you now need to provide the label: y = ", by.name, "\n\n",
"Or, if the variable is the 2nd categorical variable in the analysis\n",
" then label as: by = ", by.name, "\n")
}
}
# not pre-aggregated data -------------------------------------------------
lx.u <- length(unique(x.call))
lx <- ifelse (is.data.frame(x.call), nrow(x.call), length(x.call))
if (is.null(by.call))
is.agg <- ifelse (lx.u < lx, FALSE, TRUE)
else {
lby.u <- length(unique(by.call))
lby <- ifelse (is.data.frame(by.call), nrow(by.call), length(by.call))
is.agg <- ifelse (lx.u*lby.u < lby, FALSE, TRUE)
}
# set labels default for aggregated data
if (labels.miss && (!stat.miss || is.agg)) labels <- "input"
## ---- Missing data removal: x, y, by (possibly multi-column), facet ----
cc <- .drop_casewise_missing( # build data frame with relevant vars
x.call = x.call,
y.call = y.call,
by.call = by.call,
facet.call= facet.call
)
if (!is.null(cc) && !all(cc)) {
# x.call: vector OR matrix/data.frame
if (!is.null(x.call)) {
if (is.matrix(x.call) || is.data.frame(x.call)) {
x.call <- x.call[cc, , drop = FALSE]
} else {
x.call <- x.call[cc]
}
}
# y.call: vector
if (!is.null(y.call)) {
y.call <- y.call[cc]
}
# by.call: vector OR matrix/data.frame
if (!is.null(by.call)) {
if (is.matrix(by.call) || is.data.frame(by.call)) {
by.call <- by.call[cc, , drop = FALSE]
} else {
by.call <- by.call[cc]
}
}
# facet.call: vector OR matrix/data.frame
if (!is.null(facet.call)) {
if (is.matrix(facet.call) || is.data.frame(facet.call)) {
facet.call <- facet.call[cc, , drop = FALSE]
} else {
facet.call <- facet.call[cc]
}
}
}
# check conditions when a y variable is present ---------------------------
if (!is.null(y.call)) { # a y variable present
if (is.agg) { # a summary table
if (!stat.miss && is.agg) { # y and a summary table, no stat
cat("\n"); stop(call.=FALSE, "\n------\n",
"The data are a summary table, so do not specify a value of\n",
" stat as the data aggregation has already been done\n\n")
}
if (sum(is.na(x.call)) > 0 ||
sum(is.na(by.call)) > 0 ||
sum(is.na(y.call)) > 0) {
# ok <- is.finite(x.call) & is.finite(by.call) & is.finite(y.call)
cat("\n"); stop(call.=FALSE, "\n------\n",
"When reading a summary table, missing data not allowed.\n\n")
}
} # is a summary table
else {
if (!is.agg && stat.miss) {
cat("\n"); stop(call.=FALSE, "\n------\n",
"The data are not a summary (pivot) table, and you have a ",
"numerical variable,\n",
" y = ", y.name, "\n",
"so need to specify a value of stat to define the aggregation of\n",
y.name, ", such as stat=\"mean\".\n\n")
}
} # end is not a summary table
} # a y variable
# evaluate specified fill (NULL, numeric constant, or a variable) ---------
if (!is.null(fill)) {
fill.name <- deparse(substitute(fill))
if (length(fill.name) == 1) {
if (exists(df.name, where=.GlobalEnv))
in.df <- ifelse (exists(fill.name, where=data), TRUE, FALSE)
else
in.df <- FALSE
}
else in.df <- FALSE
# only works for y given, not tabulated
if (in.df) { # fill is a variable
# need to aggregate cat var x and set fill.val to those limited values
# currently, fill.val consists of all data values of variable fill
fill.val <- eval(substitute(data$fill)) # fill is a variable in data
fill <- .getColC(fill.val, fill_name=fill.name)
if (sort != "0") {
srt.dwn <- ifelse (sort == "-", TRUE, FALSE)
fill <- fill[order(fill.val, decreasing=srt.dwn)]
}
}
# evaluate getColors at the time of the function call
# re-evaluate here by setting fill with the specified value of n
if (substr(fill.name[1], 1, 9) == "getColors")
fill <- .do_getColors(fill.name, lx.u)
} # end fill is present
n.x <- length(unique(data[[x.name]]))
if (is.null(fill))
fill <- .color_range(.get_fill(theme), max(n.x, n.by))
else
fill <- .color_range(fill, max(n.x, n.by))
# Trellis plots for bar plots ---------------------------------------------
if (Trellis && do_plot) {
# facet2 not currently available
.bar.lattice(x.call, facet.call, facet2=NULL, n_row, n_col, aspect,
proportion, fill, color, trans, size.pt=NULL,
xlab, ylab, main, rotate_x, offset,
axis_fmt, axis_x_pre, axis_y_pre,
width, height, pdf_file,
segments_x=NULL, breaks=NULL, T.type="bar", quiet)
return(invisible(NULL))
}
# set up pdf_file if needed -----------------------------------------------
plotly_types <- c("pie", "radar", "bubble", "sunburst", "treemap", "icicle")
is_plotly_type <- type %in% plotly_types
if (!is.null(pdf_file) && is_plotly_type) {
warning(
"pdf_file is currently not supported for Plotly-based Chart() types (",
paste(sort(unique(type)), collapse = ", "),
"). The pdf_file argument will be ignored for this call."
)
pdf_file <- NULL
}
if (!is.null(pdf_file)) {
if (!grepl(".pdf", pdf_file))
pdf_file <- paste(pdf_file, ".pdf", sep="")
pdf(file=pdf_file, width=width, height=height, onefile=FALSE)
}
else {
if (df.name != "NULL") # not dev.new for shiny
.opendev(pdf_file, width, height)
}
# stat aggregation: y is present with raw data and stat not NULL ----------
if (!is.agg) {
if (!is.null(stat) && !is.null(y.call)) { # y with stat
n_cat <- 0
## ----- console stats BEFORE reducing data -------------------------
if (!quiet) {
txout <- ""
## only show the one-way numeric summary when there is
## truly only one variable (no by, no facet)
if (is.null(by.call) && is.null(facet.call)) { # <- allow for facets
options(yname = x.name) # reverse x and y names, .ss.numeric
options(xname = y.name)
stats <- .ss.numeric(y.call, by = x.call, digits_d = digits_d,
brief = TRUE, y.name = x.name)
txout <- stats$tx
options(xname = x.name) # reverse back
options(yname = y.name)
}
class(txout) <- "out"
output <- list(out_txt = txout)
class(output) <- "out_all"
print(output)
} # end !quiet
## ----- aggregate --------------------------------------------------
is.agg <- TRUE
stat_out <- .stats(x.call, y.call, by.call, facet.call, stat, y.name)
out <- stat_out$out
if (is.null(ylab)) {
ylab <- stat_out$ylab
y.name <- ylab
}
# table already printed above
if (is.null(by.call) && is.null(facet.call)) { # 'out' is a named vector
x.call <- factor(names(out))
y.call <- as.vector(out)
}
else { # by.call or facet.call is present, 'out' is a data.frame
# build: y ~ group_cols + x
## all grouping columns (by + facet) are everything except x,y
grp_cols <- setdiff(names(out), c("x", "y"))
cat("Summary Table for", ylab, "\n\n")
if (!length(grp_cols)) {
x.tbl <- xtabs(y ~ x, data = out)
} else {
form <- reformulate(c(grp_cols, "x"), response = "y")
x.tbl <- xtabs(form, data = out)
}
.print_table(
x.tbl = x.tbl,
x.name = x.name,
x.lbl = x.lbl,
by.name = by.name, # label string, not the columns
y.name = y.name,
stat = stat,
digits_d = digits_d
)
## ----- Update x.call / by.call / facet.call / y.call ----------------
## After aggregation, downstream plotting should see the *reduced* data.
x.call <- out[["x"]]
y.call <- out[["y"]]
## how many by / facet variables did we start with?
n_by <- if (is.null(by.call))
0L
else if (is.data.frame(by.call))
ncol(by.call)
else
1L
n_facet <- if (is.null(facet.call))
0L
else if (is.data.frame(facet.call))
ncol(facet.call)
else
1L
by_cols <- if (n_by > 0L)
grp_cols[seq_len(n_by)]
else
character(0L)
facet_cols <- if (n_facet > 0L)
grp_cols[seq(from = n_by + 1L, length.out = n_facet)]
else
character(0L)
## by.call: NULL, vector, or data.frame depending on how many by vars
if (!length(by_cols))
by.call <- NULL
else if (length(by_cols) == 1L)
by.call <- out[[by_cols[1L]]]
else
by.call <- out[by_cols]
## facet.call: NULL, vector, or data.frame depending on how many facets
if (!length(facet_cols))
facet.call <- NULL
else if (length(facet_cols) == 1L)
facet.call <- out[[facet_cols[1L]]]
else
facet.call <- out[facet_cols]
}
} # y is present for original data and stats not NULL
# else do table stats of counts -------------------------------------------
else if (type != "bar") { # do table of counts, done in bc.main for bar
gl <- .getlabels(main=main, lab_cex=getOption("lab_cex"))
x.name <- gl$xn; x.lbl <- gl$xl
# build the 1-D / 2-D table strictly for console output & hover
x.tbl <- .build_xtab(
x = x.call,
y = if (exists("y.call")) y.call else NULL,
by = by.call,
facet = facet.call,
stat = stat,
is.agg = is.agg,
digits_d = digits_d
)
if (length(dim(x.tbl)) < 3) { # by not a vector
.print_table( # print 1-D or 2-D, in zzz_plotly
x.tbl = x.tbl,
x.name = x.name,
x.lbl = x.lbl,
by.name = if (is.null(by.call)) NULL else by.name,
y.name = if (!is.null(stat) && !is.null(y.call)) y.name else "Count",
stat = stat,
digits_d = digits_d
)
}
}
} # end need to aggregate
# begin processing designated chart type ----------------------------------
if (type == "bar") {
bc <- .bc.main(x.call, y.call, by.call, stack100,
fill, color, trans,
fill_split, fill_scaled, fill_chroma, theme,
horiz, gap, proportion, scale_y,
xlab, ylab, main,
value_labels, label_max, beside,
rotate_x, offset,
axis_fmt, axis_x_pre, axis_y_pre,
break_x, sort,
labels, labels_color, labels_size, labels_decimals,
labels_position, labels_cut,
xlab.adj, ylab.adj, bm.adj, lm.adj, tm.adj, rm.adj,
pad_y_min, pad_y_max,
legend_title, legend_position, legend_labels,
legend_horiz, legend_size, legend_abbrev, legend_adjust,
add, x1, x2, y1, y2, out_size, do_plot, use_plotly, quiet,
shiny, digits_d, ...)
if (!is.null(pdf_file)) {
dev.off()
if (!quiet) .showfile(pdf_file, "BarChart")
}
return(invisible(bc))
}
# Hierarchical chart -----------------------------------------------------
else if (type %in% c("sunburst", "treemap", "icicle") ||
(type == "pie" && !is.null(by.call))) {
plt <- .hier.plotly(
x.call = x.call,
by.call = by.call,
facet.call = facet.call,
y.call = if (exists("y.call")) y.call else NULL,
x.name = x.name, by.name = by.name, facet.name = facet.name, y.name = y.name,
type = type,
stat = stat,
fill=fill,
border=color,
digits_d = digits_d,
facet_gap_x = 0.04,
facet_gap_y = 0.11,
facet_size = 1.00,
facet_title_y_base = -0.018, # down a bit into panel
facet_title_row_shift = -0.003, # additional downshift per lower row
main = if (!missing(main)) main else NULL
)
if (.allow.interactive()) print(plt)
return(invisible(plt))
}
else if (type == "pie") { # plain pie, no by, maybe facet
if (is.null(by.call) && !facet.miss) { # by already shown to not exist
by.name <- facet.name
by.call <- facet.call # use the facet as the by for aggregation
facet.name <- NULL
facet.call <- NULL
}
plt <- .do.plotly(x.call, x.name, y.call, y.name, ylab, by.call, by.name,
type, stat, fill, color, opacity=1-trans,
hole, power, radius, ncols=NULL,
labels, labels_position, labels_color, labels_size,
labels_decimals, main_cex=1, main, main.miss, digits_d,
is.agg, quiet)
return(invisible(plt))
}
# Bubble chart -----------------------------------------------------------
else if (type == "bubble") {
plt <- .do.plotly(x.call, x.name, y.call, y.name, ylab, by.call, by.name,
type, stat, fill, color, opacity=1-trans,
hole, power, radius, ncols=NULL,
labels, labels_position, labels_color, labels_size,
labels_decimals, main_cex=1, main, main.miss, digits_d,
is.agg, quiet)
return(invisible(plt))
}
# Radar chart -------------------------------------------------------------
else if (type == "radar") {
if (transparency.miss && !is.null(by.call))
trans <- 0.4
plt <- .radar.plotly(
x.call = x.call,
by.call = by.call,
facet.call = facet.call,
y.call = y.call,
x.name = x.name,
by.name = by.name,
facet.name = facet.name,
y.name = y.name,
stat = stat,
fill = fill,
border = color,
opacity = 1 - trans,
digits_d = digits_d,
# facet layout controls (same names as hierarchical for consistency)
facet_size = 1.00,
facet_gap_x = 0.04,
facet_gap_y = 0.11,
facet_title_y_base = -0.018, # down a bit into panel
facet_title_row_shift = -0.003 # additional downshift per lower row
)
if (.allow.interactive()) print(plt)
return(invisible(plt))
}
} # end x is a single var
# ------------------------
# ------------------------
# x is a data frame or var list of multiple variables ---------------------
# -------------------------------------------------------------------------
else {
if (!is.null(by) || !is.null(facet)) {
cat("\n"); stop(call.=FALSE, "\n------\n",
"by and facet variables not available for multiple x variables\n\n")
}
# if labels not assigned, do default
if (is.null(labels)) {
labels <- getOption("labels")
if (labels != "off") if (missing(y)) labels <- "input"
}
if (type == "bubble") { # vector bubble, BPFM
# get labels just for subset data matrix
l <- attr(data, which="variable.labels")
nm <- names(x.call)
mylabs <- character(length=length(nm))
for (i in seq_along(nm)) {
if (!(nm[i] %in% names(l)))
mylabs[i] <- "not available"
else
mylabs[i] <- l[which(names(l) == nm[i])]
}
if (all(mylabs == "not available")) mylabs <- NULL
l.name <- "l"
if (l.name %in% ls(name=.GlobalEnv))
mylabs <- get(l.name, pos=.GlobalEnv)
if (is.null(xlab)) xlab <- "" # suppress x-axis label if not specified
if (is.null(fill)) fill <- getOption("bar_fill_cont")
if (transparency.miss) trans <- 0.4
.dpmat.main(
x=data[, , drop = FALSE], l=mylabs,
sort_type=sort,
fill=fill, color=getOption("pt_color"), col.bg=getOption("panel_fill"),
trans=trans, shape_pts="bubble", col.box=getOption("panel_color"),
col.low=NULL, col.hi=NULL,
xy_ticks=TRUE,
xlab=xlab, ylab=ylab, main=main, sub=sub, cex=1,
radius=radius, power=power,
size_cut=1,
txt_color=getOption("bubble_text_color"),
bm.adj=0, lm.adj=0, tm.adj=0, rm.adj=0,
value_labels=value_labels,
rotate_x=rotate_x, rotate_y=rotate_y, offset=offset, quiet=quiet,
do_plot=do_plot, fun_call=fun_call,
...)
} # end vector bubble
else if (type == "bar") { # vector bar
if (is.null(one_plot) || one_plot) { # see if one_plot was specified
one_plot <- TRUE
mx.ln <- 0 # get variable with the most unique responses
for (i in 1:ncol(data)) {
ln <- length(na.omit(unique(data[,i])))
if (ln > mx.ln) {
ind <- i
mx.ln <- ln
}
}
uq <- na.omit(unique(data[,ind])) # first largest set of responses
uq.ln <- length(uq) # length of largest set
# all elements of smaller response set should be in full response set
for (i in 1:ncol(data)) {
if (length(setdiff(na.omit(unique(data[,i])), uq)) > 0) {
one_plot <- FALSE
break;
}
}
} # end determine one_plot
# one_plot all x's stacked on a single plot, like a BPFM for bars
if (one_plot) {
y.call <- NULL
by.call <- NULL
if (is.null(legend_title)) legend_title <- "Responses"
options(byname = "Responses")
if (is.null(xlab)) xlab <- ""
if (is.null(ylab)) ylab <- ""
if (missing(labels_size)) labels_size <- 0.8 - (0.008 * ncol(data))
if (sort.miss) sort <- "+"
if (horiz.miss) horiz <- TRUE
if (color.miss) color <- "transparent"
# if fill not specified, define divergent palette and get colors
if (fill.miss) {
fill <- .get_fill(theme, diverge=TRUE) # get divergent color names
fill <-.color_range(fill, uq.ln) # translate color names to colors
} # end fill.miss
# evaluate getColors at the time of the function call
# re-evaluate here by setting fill with the specified value of n
else if (substr(fill.name, 1, 9) == "getColors")
fill <- .do_getColors(fill.name, uq.ln)
else # not fill=getColors(...) but color names were specified
fill <-.color_range(fill, uq.ln) # translate color names to colors
if (!is.null(pdf_file)) {
if (!grepl(".pdf", pdf_file))
pdf_file <- paste(pdf_file, ".pdf", sep="")
pdf(file=pdf_file, width=width, height=height, onefile=FALSE)
}
else {
if (df.name != "NULL") # not dev.new for shiny
.opendev(pdf_file, width, height)
}
bc <- .bc.main(data, y.call, by.call, stack100,
fill, color, trans,
fill_split, fill_scaled, fill_chroma, theme,
horiz, gap, proportion, scale_y,
xlab, ylab, main,
value_labels, label_max, beside,
rotate_x, offset,
axis_fmt, axis_x_pre, axis_y_pre,
break_x, sort,
labels, labels_color, labels_size, labels_decimals,
labels_position, labels_cut,
xlab.adj, ylab.adj, bm.adj, lm.adj, tm.adj, rm.adj,
pad_y_min, pad_y_max,
legend_title, legend_position, legend_labels,
legend_horiz, legend_size, legend_abbrev, legend_adjust,
add, x1, x2, y1, y2, out_size, do_plot, use_plotly=FALSE,
quiet, shiny, digits_d, ...)
if (!is.null(pdf_file)) {
dev.off()
if (!quiet) .showfile(pdf_file, "BarChart")
}
} # end one_plot
# --------------------------------
# analyze each x column separately
else {
bc.data.frame(data, stack100,
fill, color, trans, fill_split,
fill_scaled, fill_chroma, theme,
horiz, gap, proportion, scale_y,
xlab, ylab, main,
value_labels, label_max, beside,
rotate_x, offset,
axis_fmt, axis_x_pre, axis_y_pre,
break_x, sort,
labels, labels_color, labels_size, labels_decimals,
labels_position, labels_cut,
xlab.adj, ylab.adj, bm.adj, lm.adj, tm.adj, rm.adj,
pad_y_min, pad_y_max,
legend_title, legend_position, legend_labels,
legend_horiz, legend_size, legend_abbrev, legend_adjust,
out_size, do_plot, use_plotly=FALSE, quiet,
digits_d, shiny, pdf_file, width, height, ...)
}
}
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.