forked from yihui/knitr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhooks-extra.R
159 lines (146 loc) · 6.05 KB
/
hooks-extra.R
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
#' Built-in chunk hooks to extend knitr
#'
#' Hook functions are called when the corresponding chunk options are not
#' \code{NULL} to do additional jobs beside the R code in chunks. This package
#' provides a few useful hooks, which can also serve as examples of how to
#' define chunk hooks in \pkg{knitr}.
#'
#' The function \code{hook_pdfcrop()} calls \code{\link{plot_crop}()} to crop
#' the white margins of PDF plots.
#'
#' The function \code{hook_optipng()} calls the program \command{optipng} to
#' optimize PNG images. Note the chunk option \code{optipng} can be used to
#' provide additional parameters to the program \command{optipng}, e.g.
#' \code{optipng = '-o7'}.
#'
#' The function \code{hook_pngquant()} calls the program \command{pngquant} to
#' optimize PNG images. Note the chunk option \code{pngquant} can be used to
#' provide additional parameters to the program \command{pngquant}, e.g.
#' \code{pngquant = '--speed=1 --quality=0-50'}.
#'
#' The function \code{hook_mogrify()} calls the program \command{mogrify}. Note
#' the chunk option \code{mogrify} can be used to provide additional parameters
#' to the program \command{mogrify} (with default \code{-trim} to trim PNG
#' files).
#'
#' When the plots are not recordable via \code{grDevices::\link{recordPlot}()}
#' and we save the plots to files manually via other functions (e.g. \pkg{rgl}
#' plots), we can use the chunk hook \code{hook_plot_custom} to help write code
#' for graphics output into the output document.
#'
#' The hook \code{hook_purl()} can be used to write the code chunks to an R
#' script. It is an alternative approach to \code{\link{purl}}, and can be more
#' reliable when the code chunks depend on the execution of them (e.g.
#' \code{\link{read_chunk}()}, or \code{\link{opts_chunk}$set(eval = FALSE)}).
#' To enable this hook, it is recommended to associate it with the chunk option
#' \code{purl}, i.e. \code{knit_hooks$set(purl = hook_purl)}. When this hook is
#' enabled, an R script will be written while the input document is being
#' \code{\link{knit}}. Currently the code chunks that are not R code or have the
#' chunk option \code{purl=FALSE} are ignored. Please note when the cache is
#' turned on (the chunk option \code{cache = TRUE}), no chunk hooks will be
#' executed, hence \code{hook_purl()} will not work, either. To solve this
#' problem, we need \code{cache = 2} instead of \code{TRUE} (see
#' \url{https://yihui.org/knitr/demo/cache/} for the meaning of \code{cache =
#' 2}).
#' @rdname chunk_hook
#' @param before,options,envir,... See \emph{References} below.
#' @references \url{https://yihui.org/knitr/hooks/#chunk-hooks}
#' @seealso \code{rgl::\link[rgl:snapshot]{rgl.snapshot}},
#' \code{rgl::\link[rgl:postscript]{rgl.postscript}},
#' \code{rgl::\link[rgl]{hook_rgl}},
#' \code{rgl::\link[rgl:hook_rgl]{hook_webgl}}
#' @note The two hook functions \code{hook_rgl()} and \code{hook_webgl()} were
#' moved from \pkg{knitr} to the \pkg{rgl} package (>= v0.95.1247) after
#' \pkg{knitr} v1.10.5, and you can \code{library(rgl)} to get them.
#' @export
#' @examples if (require('rgl') && exists('hook_rgl')) knit_hooks$set(rgl = hook_rgl)
#' # then in code chunks, use the option rgl=TRUE
hook_pdfcrop = function(before, ...) {
# crops plots after a chunk is evaluated and plot files produced
if (before) return()
in_base_dir(for (f in get_plot_files()) plot_crop(f))
}
get_plot_files = function() {
unique(opts_knit$get('plot_files'))
}
#' @export
#' @rdname chunk_hook
hook_optipng = function(...) hook_png(..., cmd = 'optipng')
hook_png = function(
before, options, ..., cmd = c('optipng', 'pngquant', 'mogrify'), post_process = identity
) {
if (before) return()
cmd = match.arg(cmd)
if (!nzchar(Sys.which(cmd))) {
warning('cannot find ', cmd, '; please install and put it in PATH'); return()
}
opts = options[[cmd]]
if (isFALSE(opts)) return()
if (is.null(opts) || isTRUE(opts)) opts = switch(
cmd, pngquant = '--skip-if-larger', mogrify = '-trim'
)
if (cmd == 'pngquant') opts = paste(opts, '--ext -fs8.png')
paths = get_plot_files()
paths = grep('[.]png$', paths, ignore.case = TRUE, value = TRUE)
in_base_dir(
lapply(paths, function(x) {
cmd = paste(cmd, if (is.character(options[[cmd]])) options[[cmd]], shQuote(x))
(if (is_windows()) shell else system)(cmd)
post_process(x)
})
)
return()
}
#' @export
#' @rdname chunk_hook
hook_pngquant = function(...) {
hook_png(..., cmd = 'pngquant', post_process = function(x) {
# pngquant creates an output file with '-fs8.png' as the extension.
x2 = sub("\\.png$", "-fs8.png", x)
if (file.exists(x2)) file.rename(x2, x)
})
}
#' @export
#' @rdname chunk_hook
hook_mogrify = function(...) hook_png(..., cmd = 'mogrify')
#' @export
#' @rdname chunk_hook
hook_plot_custom = function(before, options, envir){
if (before) return() # run hook after the chunk
if (options$fig.show == 'hide') return() # do not show figures
ext = dev2ext(options)
hook = knit_hooks$get('plot')
n = options$fig.num
if (n == 0L) n = options$fig.num = 1L # make sure fig.num is at least 1
res = unlist(lapply(seq_len(n), function(i) {
options$fig.cur = i
hook(fig_path(ext, options, i), reduce_plot_opts(options))
}), use.names = FALSE)
paste(res, collapse = '')
}
#" a hook function to write out code from chunks
#' @export
#' @rdname chunk_hook
hook_purl = function(before, options, ...) {
# at the moment, non-R chunks are ignored; it is unclear what I should do
if (before || !options$purl || options$engine != 'R') return()
output = .knitEnv$tangle.file
if (isFALSE(.knitEnv$tangle.start)) {
.knitEnv$tangle.start = TRUE
unlink(output)
# write out knit_params() data from YAML
params = .knitEnv$tangle.params
if (length(params)) write_utf8(params, output)
.knitEnv$tangle.params = NULL
}
code = options$code
if (isFALSE(options$eval)) code = comment_out(code, '# ', newline = FALSE)
if (is.character(output)) {
code = c(
if (file.exists(output)) read_utf8(output),
label_code(code, options)
)
write_utf8(code, output)
}
invisible()
}