add 'spec_line' to inline plotting
diff --git a/R/mini_plots.R b/R/mini_plots.R
index f34715f..ebca6fd 100644
--- a/R/mini_plots.R
+++ b/R/mini_plots.R
@@ -2,7 +2,7 @@
#'
#' @description These functions helps you quickly generate sets of sparkline
#' style plots using base R plotting system. Currently, we support histogram
-#' and boxplot. You can use them together with `column_spec` to
+#' boxplot, and line. You can use them together with `column_spec` to
#' generate inline plot in tables. By default, this function will save images
#' in a folder called "kableExtra" and return the address of the file.
#'
@@ -12,12 +12,21 @@
#' @param res The resolution of the plot. Default is 300.
#' @param same_lim T/F. If x is a list of vectors, should all the plots be
#' plotted in the same range? Default is True.
-#' @param lim Manually specify plotting range in the form of `c(0, 10)`.
+#' @param lim,xlim,ylim Manually specify plotting range in the form of
+#' `c(0, 10)`. `lim` is used in `spec_hist` and `spec_boxplot`; `xlim`
+#' and `ylim` are used in `spec_line`.
#' @param xaxt On/Off for xaxis text
#' @param yaxt On/Off for yaxis text
#' @param ann On/Off for annotations (titles and axis titles)
#' @param col Color for the fill of the histogram bar/boxplot box.
#' @param border Color for the border.
+#' @param frame.plot On/Off for surrounding box (`spec_line` only). Default
+#' is False.
+#' @param lwd Line width for `spec_line`; within `spec_line`, the `minmax`
+#' argument defaults to use this value for `cex` for points. Default is 2.
+#' @param minmax,min,max Arguments passed to `points` to highlight minimum
+#' and maximum values in `spec_line`. If `min` or `max` are `NULL`, they
+#' default to the value of `minmax`. Set to an empty `list()` to disable.
#' @param dir Directory of where the images will be saved.
#' @param file File name. If not provided, a random name will be used
#' @param file_type Graphic device. Support `png` or `svg`. SVG is recommended
@@ -187,3 +196,117 @@
return(fig_dir_name)
}
+#' @rdname spec_hist
+#' @export
+spec_line <- function(x, y = NULL, width = 200, height = 50, res = 300,
+ same_lim = TRUE, xlim = NULL, ylim = NULL,
+ xaxt = 'n', yaxt = 'n', ann = FALSE,
+ col = "lightgray", border = NULL,
+ frame.plot = FALSE, lwd = 2,
+ minmax = list(pch = ".", cex = lwd, col = "red"),
+ min = minmax, max = minmax,
+ dir = if (is_latex()) rmd_files_dir() else tempdir(),
+ file = NULL,
+ file_type = if (is_latex()) "png" else "svg", ...) {
+ if (is.list(x)) {
+ if (same_lim) {
+ if (is.null(xlim)) {
+ xlim <- base::range(unlist(x))
+ }
+ if (is.null(ylim) && !is.null(y)) {
+ ylim <- base::range(unlist(y))
+ }
+ }
+ if (is.null(y)) {
+ y <- replicate(length(x), NULL, simplify = FALSE)
+ } else if (!is.list(y) || length(x) != length(y)) {
+ stop("'x' and 'y' are not the same length")
+ }
+ return(Map(function(x_, y_) {
+ spec_line(x = x_, y = y_,
+ width = width, height = height,
+ same_lim = same_lim, xlim = xlim, ylim = ylim,
+ xaxt = xaxt, yaxt = yaxt, ann = ann, col = col, border = border,
+ frame.plot = frame.plot, lwd = lwd,
+ minmax = minmax, min = min, max = max,
+ dir = dir, file = file, file_type = file_type, ...)
+ }, x, y))
+ }
+
+ if (is.null(y) || !length(y)) {
+ y <- x
+ x <- seq(0, 1, length.out = length(y))
+ tmp <- ylim
+ ylim <- xlim
+ xlim <- tmp
+ }
+
+ if (is.null(xlim)) {
+ xlim <- base::range(x)
+ }
+
+ if (is.null(ylim) && !is.null(y)) {
+ ylim <- base::range(y)
+ }
+
+ if (is.null(min)) min <- minmax
+ if (is.null(max)) max <- minmax
+
+ expand <- c(
+ if (!is.null(min) && length(min)) 0.96 else 1,
+ if (!is.null(max) && length(max)) 1.04 else 1)
+ xlim <- xlim * expand
+ ylim <- ylim * expand
+
+ file_type <- match.arg(file_type, c("svg", "png"))
+
+ if (!dir.exists(dir)) {
+ dir.create(dir)
+ }
+
+ if (is.null(file)) {
+ file <- file.path(dir, paste0(
+ "hist_", round(as.numeric(Sys.time()) * 1000), ".", file_type))
+ }
+
+ if (file_type == "svg") {
+ grDevices::svg(filename = file, width = width / res, height = height / res,
+ bg = 'transparent')
+ } else {
+ grDevices::png(filename = file, width = width, height = height, res = res,
+ bg = 'transparent')
+ }
+ curdev <- grDevices::dev.cur()
+ on.exit(grDevices::dev.off(curdev), add = TRUE)
+
+ graphics::par(mar = c(0, 0, 0.2, 0), lwd = lwd)
+ graphics::plot(x, y, type = "l", xlim = xlim, ylim = ylim, border = border,
+ xaxt = xaxt, yaxt = yaxt, ann = ann, col = col,
+ frame.plot = frame.plot, ...)
+
+ if (!is.null(min) && length(min)) {
+ ind <- which.min(y)
+ do.call(graphics::points, c(list(x[ind], y[ind]), min))
+ }
+
+ if (!is.null(max) && length(max)) {
+ ind <- which.max(y)
+ do.call(graphics::points, c(list(x[ind], y[ind]), max))
+ }
+
+ grDevices::dev.off(curdev)
+
+ if (file_type == "svg") {
+ svg_xml <- xml2::read_xml(file)
+ svg_text <- as.character(svg_xml)
+ unlink(file)
+ } else {
+ svg_text <- NULL
+ }
+ out <- list(path = file, dev = file_type, type = "line",
+ width = width, height = height, res = res,
+ svg_text = svg_text)
+
+ class(out) <- "kableExtraInlinePlots"
+ return(out)
+}