-
Notifications
You must be signed in to change notification settings - Fork 222
Expand file tree
/
Copy pathimage.R
More file actions
471 lines (443 loc) · 13.2 KB
/
Copy pathimage.R
File metadata and controls
471 lines (443 loc) · 13.2 KB
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
#------------------------------------------------------------------------------#
#
# /$$
# | $$
# /$$$$$$ /$$$$$$
# /$$__ $$|_ $$_/
# | $$ \ $$ | $$
# | $$ | $$ | $$ /$$
# | $$$$$$$ | $$$$/
# \____ $$ \___/
# /$$ \ $$
# | $$$$$$/
# \______/
#
# This file is part of the 'rstudio/gt' project.
#
# Copyright (c) 2018-2024 gt authors
#
# For full copyright and license information, please look at
# https://gt.rstudio.com/LICENSE.html
#
#------------------------------------------------------------------------------#
#' Helper function for adding an image from the web
#'
#' @description
#'
#' We can flexibly add a web image inside of a table with `web_image()`.
#' The function provides a convenient way to generate an HTML fragment with an
#' image URL. Because this function is currently HTML-based, it is only useful
#' for HTML table output. To use this function inside of data cells, it is
#' recommended to use [text_transform()]. With that function, we can specify
#' which data cells to target and then include a `web_image()` call within the
#' required user-defined function (for the `fn` argument). If we want to include
#' an image in other places (e.g., in the header, within footnote text, etc.)
#' we need to wrap `web_image()` inside [html()].
#'
#' By itself, the function creates an HTML image tag, so, the call
#' `web_image("http://example.com/image.png")` evaluates to:
#'
#' `<img src=\"http://example.com/image.png\" style=\"height:30px;\">`
#'
#' where a height of `30px` is a default height chosen to work well within the
#' heights of most table rows.
#'
#' @param url *An image URL*
#'
#' `scalar<character>` // **required**
#'
#' A url that resolves to an image file.
#'
#' @param height *Height of image*
#'
#' `scalar<numeric|integer>` // *default:* `30`
#'
#' The absolute height of the image in the table cell (in `"px"` units). By
#' default, this is set to `"30px"`.
#'
#' @return A character object with an HTML fragment that can be placed inside of
#' a cell.
#'
#' @section Examples:
#'
#' Get the PNG-based logo for the R Project from an image URL.
#'
#' ```r
#' r_png_url <- "https://www.r-project.org/logo/Rlogo.png"
#' ```
#'
#' Create a tibble that contains heights of an image in pixels (one column as a
#' string, the other as numerical values), then, create a **gt** table. Use
#' [text_transform()] to insert the R logo PNG image with the various
#' sizes.
#'
#' ```r
#' dplyr::tibble(
#' pixels = px(seq(10, 35, 5)),
#' image = seq(10, 35, 5)
#' ) |>
#' gt() |>
#' text_transform(
#' locations = cells_body(columns = image),
#' fn = function(x) {
#' web_image(
#' url = r_png_url,
#' height = as.numeric(x)
#' )
#' }
#' )
#' ```
#'
#' \if{html}{\out{
#' `r man_get_image_tag(file = "man_web_image_1.png")`
#' }}
#'
#' Get the SVG-based logo for the R Project from an image URL.
#'
#' ```r
#' r_svg_url <- "https://www.r-project.org/logo/Rlogo.svg"
#' ```
#'
#' Create a tibble that contains heights of an image in pixels (one column as a
#' string, the other as numerical values), then, create a **gt** table. Use
#' [tab_header()] to insert the **R** logo SVG image once in the title and five
#' times in the subtitle.
#'
#' ```r
#' dplyr::tibble(
#' pixels = px(seq(10, 35, 5)),
#' image = seq(10, 35, 5)
#' ) |>
#' gt() |>
#' tab_header(
#' title = html(
#' "<strong>R Logo</strong>",
#' web_image(
#' url = r_svg_url,
#' height = px(50)
#' )
#' ),
#' subtitle = html(
#' web_image(
#' url = r_svg_url,
#' height = px(12)
#' ) |>
#' rep(5)
#' )
#' )
#' ```
#'
#' \if{html}{\out{
#' `r man_get_image_tag(file = "man_web_image_2.png")`
#' }}
#'
#' @family image addition functions
#' @section Function ID:
#' 9-1
#'
#' @section Function Introduced:
#' `v0.2.0.5` (March 31, 2020)
#'
#' @export
web_image <- function(
url,
height = 30
) {
if (is.numeric(height)) {
height <- paste0(height, "px")
}
paste0("<img src=\"", url, "\" style=\"height:", height, ";\">")
}
#' Helper function for adding a local image
#'
#' @description
#'
#' We can flexibly add a local image (i.e., an image residing on disk) inside of
#' a table with `local_image()` function. The function provides a convenient way
#' to generate an HTML fragment using an on-disk PNG or SVG. Because this
#' function is currently HTML-based, it is only useful for HTML table output. To
#' use this function inside of data cells, it is recommended to use
#' [text_transform()] first. With that function, we can specify which data cells
#' to target and then include a `local_image()` call within the required
#' user-defined function (for the `fn` argument). If we want to include an image
#' in other places (e.g., in the header, within footnote text, etc.) we need to
#' use `local_image()` within the [html()] helper function.
#'
#' By itself, the function creates an HTML image tag with an image URI embedded
#' within. We can easily experiment with a local PNG or SVG image that's
#' available in the **gt** package using the [test_image()] function. Using
#' that, the call `local_image(file = test_image(type = "png"))` evaluates to:
#'
#' `<img src=<data URI> style=\"height:30px;\">`
#'
#' where a height of `30px` is a default height chosen to work well within the
#' heights of most table rows.
#'
#' @param filename *Path to image file*
#'
#' `scalar<character>` // **required**
#'
#' A local path to an image file on disk.
#'
#' @inheritParams web_image
#'
#' @return A character object with an HTML fragment that can be placed inside of
#' a cell.
#'
#' @section Examples:
#'
#' Create a tibble that contains heights of an image in pixels (one column as a
#' string, the other as numerical values), then, create a **gt** table. Use
#' [text_transform()] to insert a local test image (PNG) image with the various
#' sizes.
#'
#' ```r
#' dplyr::tibble(
#' pixels = px(seq(10, 35, 5)),
#' image = seq(10, 35, 5)
#' ) |>
#' gt() |>
#' text_transform(
#' locations = cells_body(columns = image),
#' fn = function(x) {
#' local_image(
#' filename = test_image(type = "png"),
#' height = as.numeric(x)
#' )
#' }
#' )
#' ```
#'
#' \if{html}{\out{
#' `r man_get_image_tag(file = "man_local_image_1.png")`
#' }}
#'
#' @family image addition functions
#' @section Function ID:
#' 9-2
#'
#' @section Function Introduced:
#' `v0.2.0.5` (March 31, 2020)
#'
#' @export
local_image <- function(
filename,
height = 30
) {
# Normalize file path
filename <- path_expand(filename)
if (is.numeric(height)) {
height <- paste0(height, "px")
}
# Create the image URI
uri <- get_image_uri(filename)
# Generate the Base64-encoded image and place it within <img> tags
paste0("<img src=\"", uri, "\" style=\"height:", height, ";\">")
}
#' Helper function for adding a ggplot
#'
#' @description
#'
#' We can add a **ggplot2** plot inside of a table with the help of the
#' `ggplot_image()` function. The function provides a convenient way to generate
#' an HTML fragment with a `ggplot` object. Because this function is currently
#' HTML-based, it is only useful for HTML table output. To use this function
#' inside of data cells, it is recommended that [text_transform()] is used.
#' With that function, we can specify which data cells to target and then
#' include a call to `ggplot_image()` within the required user-defined function
#' (for the `fn` argument). If we want to include a plot in other places (e.g.,
#' in the header, within footnote text, etc.) we need to use `ggplot_image()`
#' within the [html()] helper function.
#'
#' By itself, the function creates an HTML image tag with an image URI embedded
#' within (a 100 dpi PNG). We can easily experiment with any `ggplot2` plot
#' object, and using it within `ggplot_image(plot_object = <plot object>`
#' evaluates to:
#'
#' `<img src=<data URI> style=\"height:100px;\">`
#'
#' where a height of `100px` is a default height chosen to work well within the
#' heights of most table rows. There is the option to modify the aspect ratio of
#' the plot (the default `aspect_ratio` is `1.0`) and this is useful for
#' elongating any given plot to fit better within the table construct.
#'
#' @param plot_object *A ggplot plot object*
#'
#' `obj:<ggplot>` // **required**
#'
#' A `ggplot` plot object.
#'
#' @param height *Height of image*
#'
#' `scalar<numeric|integer>` // *default:* `100`
#'
#' The absolute height of the output image in the table cell (in `"px"`
#' units). By default, this is set to `"100px"`.
#'
#' @param aspect_ratio *The final aspect ratio of plot*
#'
#' `scalar<numeric|integer>` // *default:* `1.0`
#'
#' This is the plot's final aspect ratio. Where the height of the plot is
#' fixed using the `height` argument, the `aspect_ratio` will either compress
#' (`aspect_ratio` < `1.0`) or expand (`aspect_ratio` > `1.0`) the plot
#' horizontally. The default value of `1.0` will neither compress nor expand
#' the plot.
#'
#' @param absolute_height this will be the absolute height of the image file to be saved on the disk, by default is 5. Changing this will affect the final filesize, so if there are many plots it is recommended to set this lower.
#' Note that changing this parameter works the same way as when using ggsave(), i.e. font size and such will be affected.
#'
#' @param dpi this modifies the resolution / quality of the saved image. In case we want to change only the resolution but keep the (absolute) image size.
#'
#' @return A character object with an HTML fragment that can be placed inside of
#' a cell.
#'
#' @section Examples:
#'
#' Create a **ggplot** plot.
#'
#' ```r
#' library(ggplot2)
#'
#' plot_object <-
#' ggplot(
#' data = gtcars,
#' aes(x = hp, y = trq, size = msrp)
#' ) +
#' geom_point(color = "blue") +
#' theme(legend.position = "none")
#' ```
#'
#' Create a tibble that contains two cells (where one is a placeholder for an
#' image), then, create a **gt** table. Use the `text_transform()` function to
#' insert the plot using by calling `ggplot_object()` within the user- defined
#' function.
#'
#' ```r
#' dplyr::tibble(
#' text = "Here is a ggplot:",
#' ggplot = NA
#' ) |>
#' gt() |>
#' text_transform(
#' locations = cells_body(columns = ggplot),
#' fn = function(x) {
#' plot_object |>
#' ggplot_image(height = px(200))
#' }
#' )
#' ```
#'
#' \if{html}{\out{
#' `r man_get_image_tag(file = "man_ggplot_image_1.png")`
#' }}
#'
#' @family image addition functions
#' @section Function ID:
#' 9-3
#'
#' @section Function Introduced:
#' `v0.2.0.5` (March 31, 2020)
#'
#' @export
ggplot_image <- function(
plot_object,
height = 100,
aspect_ratio = 1.0 ,
absolute_height = 5 ,
dpi = 100
) {
rlang::check_installed("ggplot2", "to use `ggplot_image()`.")
if (is.numeric(height)) {
height <- paste0(height, "px")
}
# Upgrade `plot_object` to a list if only a single ggplot object is provided
if (inherits(plot_object, "gg")) {
plot_object <- list(plot_object)
}
vapply(
seq_along(plot_object),
FUN.VALUE = character(1L),
USE.NAMES = FALSE,
FUN = function(x) {
filename <-
paste0("temp_ggplot_", formatC(x, width = 4, flag = "0"), ".png")
# Save PNG file to disk
ggplot2::ggsave(
filename = filename,
plot = plot_object[[x]],
device = "png",
dpi = dpi,
width = absolute_height * aspect_ratio,
height = absolute_height
)
on.exit(file.remove(filename))
local_image(filename = filename, height = height)
}
)
}
#' Generate a path to a test image
#'
#' @description
#'
#' Two test images are available within the **gt** package. Both contain the
#' same imagery (sized at 200px by 200px) but one is a PNG file while the other
#' is an SVG file. This function is most useful when paired with [local_image()]
#' since we test various sizes of the test image within that function.
#'
#' @param type *The image type*
#'
#' `singl-kw:[png|svg]` // *default:* `"png"`
#'
#' The type of image to produce here can either be `"png"` (the default) or
#' `"svg"`.
#'
#' @return A character vector with a single path to an image file.
#'
#' @family image addition functions
#' @section Function ID:
#' 9-4
#'
#' @section Function Introduced:
#' `v0.2.0.5` (March 31, 2020)
#'
#' @export
test_image <- function(type = c("png", "svg")) {
type <- rlang::arg_match(type)
system_file(file = paste0("graphics/test_image.", type))
}
# Function for setting the MIME type
get_mime_type <- function(file) {
extension <- tolower(get_file_ext(file))
switch(
extension,
svg = "image/svg+xml",
jpg = "image/jpeg",
paste("image", extension, sep = "/")
)
}
# Get image URIs from on-disk graphics files
# as a vector Base64-encoded image strings
get_image_uri <- function(file) {
# Create a list of `raw` objects
image_raw <-
lapply(
file, FUN = function(x) {
readBin(
con = x,
what = "raw",
n = file.info(x)$size
)
}
)
vapply(
seq_along(image_raw),
FUN.VALUE = character(1L),
USE.NAMES = FALSE, FUN = function(x) {
paste0(
"data:", get_mime_type(file[x]),
";base64,", base64enc::base64encode(image_raw[[x]])
)
}
)
}