1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
#' Set or query animation options
#'
#' There are various parameters that control the behaviour of the animation,
#' such as time interval, maximum number of animation frames, height and width,
#' etc.
#'
#' @section Animation options: The supported animation parameters: \describe{
#'
#' \item{interval}{ a positive number to set the time interval of the
#' animation (unit in seconds); default to be 1. }
#'
#' \item{nmax}{ maximum number of steps in a loop (e.g. iterations) to create
#' animation frames. Note: the actual number of frames can be less than this
#' number, depending on specific animations. Default to be 50.}
#'
#' \item{ani.width, ani.height}{ width and height of image frames (unit in
#' px); see graphics devices like \code{\link{png}}, \code{\link{jpeg}}, ...;
#' default to be 480. NB: for different graphics devices, the units of these
#' values might be different, e.g. PDF devices usually use inches, whereas
#' bitmap devices often use pixels.}
#'
#' \item{ani.res}{ The nominal resolution in ppi which will be recorded in the bitmap file,
#' if a positive integer. Also used for units other than the default,
#' and to convert points to pixels.;
#' see graphics devices like \code{\link{png}}, \code{\link{jpeg}}.}
#'
#' \item{imgnfmt}{ Customizing image number format in \code{\link{saveHTML}},
#' \code{\link{saveGIF}}, \code{\link{saveLatex}} and \code{\link{saveVideo}},
#' \code{\link{saveSWF}} is not included,
#' it allows user to define the C-style string format for output image.
#' }
#'
#' \item{imgdir}{character: the name of the directory (a relative path) for
#' images when creating HTML animation pages; default to be \code{'images'}.}
#'
#' \item{htmlfile}{character: name of the target HTML main file (without path
#' name; basename only; default to be \code{'index.html'})}
#'
#' \item{ani.dev}{a function or a function name: the graphics device; e.g.
#' (\code{\link{png}}, \code{\link{pdf}}, ...); default to be \code{'png'}}
#'
#' \item{ani.type}{character: image format for animation frames, e.g.
#' \code{png}, \code{jpeg}, ...; default to be \code{'png'}; this will be used
#' as the file extension of images, so don't forget to change this option as
#' well when you changed the option \code{ani.dev}}
#'
#' \item{title, description}{character: the title and description of the
#' animation in the HTML page created by \code{\link{saveHTML}}}
#'
#' \item{verbose}{logical: if \code{TRUE}, write a footer part
#' in the HTML page containing detailed technical information else
#' the footer of the page will be blank.}
#'
#' \item{loop}{logical or numeric: Number of times the GIF animation is to
#' cycle through the image sequence before stopping. By default, this is
#' set to zero or boolean value TRUE (infinite loop).}
#'
#' \item{autobrowse}{logical: whether auto-browse the animation page
#' immediately after it is created? (default to be \code{interactive()})}
#'
#' \item{autoplay}{logical: whether to autoplay the animation when the HTML
#' page is loaded (default to be \code{TRUE}); only applicable to
#' \code{\link{saveHTML}}}
#'
#' \item{use.dev}{ whether to use the graphics device specified in
#' \code{ani.options('ani.dev')} (default to be \code{TRUE}); if \code{FALSE},
#' we need to generate image files by our own approaches in the expression
#' \code{expr} (see functions \code{\link{saveHTML}}, \code{\link{saveGIF}},
#' \code{\link{saveLatex}} and \code{\link{saveSWF}}); this can be useful when
#' the output cannot be captured by standard R graphics devices -- a typical
#' example is the \pkg{rgl} graphics (we can use \code{rgl.snapshot} to
#' capture \pkg{rgl} graphics to png files, or \code{rgl.postscript} to save
#' plots as postscript/pdf; see \code{demo('rgl_animation')} or
#' \code{demo('use_Cairo')} for examples or the last example below). Note,
#' however, we do not really have to create the images using R graphics
#' devices -- see \code{demo('flowers')} on how to download images from the
#' Internet and create an HTML animation page!}
#'
#' }
#'
#' @section Hidden options: There are a couple of ``hidden'' options which are
#' designed to facilitate the usage of some functions but are not initialized
#' like the above options when the package is loaded, including:
#'
#' \describe{
#'
#' \item{convert}{this option will be checked first when calling
#' \code{\link{im.convert}} (or \code{\link{saveGIF}}) to see if it contains
#' the path to \file{convert.exe}; we can specify it beforehand to save the
#' efforts in searching for \file{convert.exe} in ImageMagick under Windows.
#' For example, \code{ani.options(convert = 'c:/program
#' files/imagemagick/convert.exe')}; note this option also works for Mac and
#' Linux (see \code{help(im.convert)})}
#'
#' \item{swftools}{this can help \code{\link{saveSWF}} save the efforts of
#' searching for the software package ``SWF Tools'' under Windows; e.g. we can
#' specify \code{ani.options(swftools = 'c:/program files/swftools')} in
#' advance}
#'
#' \item{img.fmt}{the value of this option can be used to determine the image
#' filename format when we want to use custom graphics devices to record
#' images, e.g. in \code{\link{saveLatex}}, if \code{ani.options('use.dev') ==
#' FALSE}, then \code{ani.options('img.fmt')} will be a string like
#' \code{'path/to/output/img.name\%d.png'}, so we can use it to generate file
#' names in the argument \code{expr}; see \code{demo('rgl_animation')} for
#' example or the last example below}
#'
#' \item{qpdf}{the path of the program \command{qpdf}, e.g.
#' \code{ani.options(qpdf = 'C:/Software/qpdf/bin/qpdf.exe')}; \command{qpdf}
#' is mainly used to compress PDF files in this package, and it is a smaller
#' tool than \command{pdftk}. It is recommended over \command{pdftk}
#' especially under Linux, because tests show that \command{pdftk} does not
#' work well under Linux in compressing PDF files, while \command{qpdf} is
#' much better.}
#'
#' \item{pdftk}{the path of the program \command{Pdftk}, e.g.
#' \code{ani.options(pdftk = 'C:/Software/pdftk.exe')} or
#' \code{ani.options(pdftk = '/home/john/bin/pdftk')}; \command{pdftk} will be
#' used to compress the PDF graphics output in the function
#' \code{\link{pdftk}}; compression will not be tried if this options is
#' \code{NULL}. This option will only affect \code{\link{saveGIF}},
#' \code{\link{saveLatex}} and \code{\link{saveSWF}} when
#' \code{ani.options('ani.type')} is \code{'pdf'}.}
#'
#' \item{ffmpeg}{the path of the progam \command{ffmpeg}, e.g.
#' \code{ani.options(ffmpeg = 'C:/Software/ffmpeg/bin/ffmpeg.exe')}; FFmpeg is
#' used to convert a sequence of images to a video. See
#' \code{\link{saveVideo}}.}
#'
#' }
#' @param ... arguments in \code{tag = value} form, or a list of tagged values.
#' The tags usually come from the animation parameters described below, but
#' they are not restricted to these tags (any tag can be used; this is similar
#' to \code{\link{options}}).
#' @return \code{ani.options()} returns a list containing the options: when
#' parameters are set, their former values are returned in an invisible named
#' list. Such a list can be passed as an argument to
#' \code{\link{ani.options}} to restore the parameter values.
#'
#' \code{ani.options('tag')} returns the value of the option \code{'tag'}.
#'
#' \code{ani.options(c('tag1', 'tag2'))} or \code{ani.options('tag1', 'tag2')}
#' returns a list containing the corresponding options.
#' @note Please note that \code{nmax} is not always equal to the number of
#' animation frames. Sometimes there is more than one frame recorded in a
#' single step of a loop, for instance, there are 2 frames generated in each
#' step of \code{\link{kmeans.ani}}, and 4 frames in \code{\link{knn.ani}},
#' etc; whereas for \code{\link{newton.method}}, the number of animation
#' frames is not definite, because there are other criteria to break the loop.
#'
#' This function can be used for almost all the animation functions such as
#' \code{\link{brownian.motion}}, \code{\link{boot.iid}},
#' \code{\link{buffon.needle}}, \code{\link{cv.ani}}, \code{\link{flip.coin}},
#' \code{\link{kmeans.ani}}, \code{\link{knn.ani}}, etc. Most of the options
#' here will affect the behaviour of animations of the formats HTML, GIF, SWF
#' and PDF; on-screen animations are only affected by \code{interval} and
#' \code{nmax}.
#'
#' @author Yihui Xie
#' @references Examples at \url{https://yihui.org/animation/example/ani-options/}
#' @seealso \code{\link{options}}, \code{\link{dev.interactive}},
#' \code{\link{saveHTML}}, \code{\link{saveGIF}}, \code{\link{saveLatex}},
#' \code{\link{saveSWF}}, \code{\link{pdftk}}
#'
#' \url{http://qpdf.sourceforge.net/}
#'
#' \url{http://www.pdflabs.com/docs/pdftk-man-page/}
#' @export
ani.options = function(...) {
lst = list(...)
.ani.opts = .ani.env$.ani.opts
if (length(lst)) {
if (is.null(names(lst)) && !is.list(lst[[1]])) {
lst = unlist(lst)
if (length(lst) == 1) .ani.opts[[lst]] else .ani.opts[lst]
} else {
omf = .ani.opts
if (is.list(lst[[1]]))
lst = lst[[1]]
if (length(lst) > 0) {
.ani.opts[names(lst)] = lst
.ani.env$.ani.opts = .ani.opts
if (!identical(omf$nmax, .ani.opts$nmax) && interactive()) {
message("animation option 'nmax' changed: ", omf$nmax, ' --> ', .ani.opts$nmax)
}
.check.opts(.ani.opts)
}
invisible(omf)
}
} else {
.ani.opts
}
}
## create an environment to store animation options
.ani.env = new.env()
## check validity of options
.check.opts = function(opts) {
dev = opts$ani.dev
type = opts$ani.type
if (opts$use.dev && is.character(dev)) {
switch(dev, png = {
if (type != 'png')
warning("the graphics device is png() but the file extension is not 'png'!")
}, jpeg = {
if (!(type %in% c('jpg', 'jpeg')))
warning("the graphics device is jpeg() but the file extension is not 'jpeg' or 'jpg'!")
}, pdf = {
if (type != 'pdf')
warning("the graphics device is pdf() but the file extension is not 'pdf'!")
})
}
if (type == 'pdf' && (opts$ani.width >= 100 || opts$ani.height >= 100)) {
warning('you are using a pdf device but the width and height are greater than 100 inches; are you sure this is correct?')
}
}
|