-
Notifications
You must be signed in to change notification settings - Fork 0
/
README.Rmd
239 lines (193 loc) · 9.3 KB
/
README.Rmd
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
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# webpea <img src="man/figures/webpea_hex.webp" align="right" width="150"/>
<!-- badges: start -->
[![R-CMD-check](https://github.com/nucleic-acid/webpea/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/nucleic-acid/webpea/actions/workflows/R-CMD-check.yaml)
<!-- badges: end -->
The goal of `{webpea}` is to provide easy functions to save a plot in the [WebP image file format](https://en.wikipedia.org/wiki/WebP). There are other packages with the same purpose, such as `{webp}`. In particular, `{webpea}` aims to be a drop-in replacement for `ggplot2::ggsave()` or to allow easy implementation in Rmarkdown and Quarto documents.
## Installation
You can install the development version of webpea from [GitHub](https://github.com/) with:
``` r
# install.packages("remotes")
remotes::install_github("nucleic-acid/webpea")
```
## Drop-in replacement of ggsave
`webpea::webpea()` can serve as drop-in replacement of `ggplot2::ggsave()`. First, the plot is saved as a temporary PNG file, so all `ggplot2::ggsave()` parameters can be used as usual. Secondly the temporary PNG file is converted to WebP via the {magick} package.
If no plot is specified, `ggplot2::ggsave()` defaults to `ggplot2::last_plot()`.:
```{r example1}
library(webpea)
# draw basic plot
ggplot2::ggplot(mtcars) +
ggplot2::aes(disp, hp, color = as.factor(cyl)) +
ggplot2::geom_point(alpha = 0.7)
# save last plot to temporary file location
webpea(tempfile("plot", fileext = ".webp"))
```
All parameters for `ggplot2::ggsave()` are valid and can be specified in `webpea()`. You can also explicitly specify the plot to be saved. Additionally, you can specify the quality as percentage (defaults to 75, as in the {magick} package, if not specified otherwise):
```{r example2}
library(webpea)
# draw first plot
p1 <- ggplot2::ggplot(mtcars) +
ggplot2::aes(disp, hp, color = cyl) +
ggplot2::geom_point(alpha = 0.7)
# draw another plot
p2 <- ggplot2::ggplot(mtcars) +
ggplot2::aes(disp, hp, color = gear) +
ggplot2::geom_point(alpha = 0.5, size = 3)
# save first plot to temporary file location
webpea(
tempfile("plot1_", fileext = ".webp"),
plot = p1,
width = 16,
height = 9,
quality = 90
)
```
## Using {magick}'s graphics device
In case you want to prevent double file writing (i.e. intermediate PNG and the final WebP), you can draw the plot into {magick}'s graphics device in memory and save that image as WebP. **Note:** Since ggsave is not used in this approach, you cannot use its arguments for output-settings!
All options that can be passed to the graphics device are valid in `webpea()` as well. The options / defaults can be found in [the documentation of `magick::image_graph()`](https://docs.ropensci.org/magick/reference/device.html).
```{r}
library(webpea)
# draw basic plot
p_draw <- ggplot2::ggplot(mtcars) +
ggplot2::aes(disp, hp, color = as.factor(cyl)) +
ggplot2::geom_point(alpha = 0.7)
# save last plot to temporary file location
webpea(
tempfile("plot", fileext = ".webp"),
plot = p_draw,
ggsave = FALSE, # this switches to the {magick} graphics device
width = 1920,
height = 1080,
res = 326,
quality = 42
)
```
## When size matters
The WebP image file format uses rather modern and effective compression algorithmy and allows for significant file size reduction when compared to PNG files. These reductions come with no visually apparent losses in the quality of the produced output in most use cases.
In times of digital communication of R outputs (e.g. HTML-output of Rmarkdown or Quarto) image file size is crucial for quick file transfer or reduced page loading times.
```{r example3}
library(webpea)
# draw a plot
ggplot2::ggplot(mtcars) +
ggplot2::aes(disp, hp, color = as.factor(cyl)) +
ggplot2::geom_point(
alpha = 0.5,
size = 10
) +
ggplot2::labs(
title = "Sample plot of {mtcars}",
subtitle = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa.\n Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."
)
# save plot as PNG
ggplot2::ggsave(
tempfile("plot_", fileext = ".png"),
width = 16,
height = 9,
device = "png",
dpi = "retina"
)
#> file size 233.2 kB
```
This saves a PNG file with 5.120 * 2.880 pixels (14.7 MP) and 233.2 kB file size.
When using WebP as output type, the images below have the same resolution in pixels, but significantly lower file sizes:
```{r example4}
# save plot with same settings for intermediate PNG and DEFAULT webp quality (75)
webpea(
tempfile("plot_", fileext = ".webp"),
width = 16,
height = 9,
device = "png", # this is passed to ggsave. The final output will still be webp.
dpi = "retina"
)
#> file size 81.7 kB
# save plot with same PNG settings but LOWER webp quality
webpea(
tempfile("plot50_", fileext = ".webp"),
width = 16,
height = 9,
device = "png", # this is passed to ggsave. The final output will still be webp.
dpi = "retina",
quality = 50
)
#> file size 72.3 kB
# save plot with same PNG settings but EVEN LOWER webp quality
webpea(
tempfile("plot20_", fileext = ".webp"),
width = 16,
height = 9,
device = "png", # this is passed to ggsave. The final output will still be webp.
dpi = "retina",
quality = 20
)
#> file size 58.2 kB
# save plot with same PNG settings but HIGHER webp quality
webpea(
tempfile("plot90_", fileext = ".webp"),
width = 16,
height = 9,
device = "png", # this is passed to ggsave. The final output will still be webp.
dpi = "retina",
quality = 90
)
#> file size 113.0 kB
# save plot with same PNG settings but HIGHEST webp quality
webpea(
tempfile("plot100_", fileext = ".webp"),
width = 16,
height = 9,
device = "png", # this is passed to ggsave. The final output will still be webp.
dpi = "retina",
quality = 100
)
#> file size 98.6 kB
```
Oddly, the 100% quality version has a smaller file size than the 90% version. I don't have an explanation for this, but the main takeaway is that, all WebP files are smaller than the original PNG. These results are just exemplatory, your milage may vary! Eventually, the 'allowable' loss of quality is to be defined by every user for themselves and for their specific use case.
```{r comparison}
sizes <- data.frame(
type = factor(
c("PNG", "WebP 20%", "WebP 50%", "WebP 75% (default)", "WebP 90%", "WebP 100%"),
levels = c("PNG", "WebP 20%", "WebP 50%", "WebP 75% (default)", "WebP 90%", "WebP 100%")
),
size_kB = c(233.2, 58.2, 72.3, 81.7, 113.0, 98.6),
cat = c("PNG", "WebP", "WebP", "WebP", "WebP", "WebP")
)
ggplot2::ggplot(sizes) +
ggplot2::aes(
x = type,
y = size_kB,
fill = cat
) +
ggplot2::geom_col() +
ggplot2::labs(
title = "WebP output is considerably smaller, than PNG output",
subtitle = "The dimensions / resolution and plot content were kept constant for comparison. \nWebP was used with different compression options, given in %."
) +
ggplot2::coord_flip() +
ggplot2::theme_bw() +
ggplot2::theme(
legend.position = "bottom",
legend.title = ggplot2::element_blank()
)
```
|PNG original | WebP with 20, 50, 75, 90 and 100% quality|
|------|------|
|<img src="man/figures/plot_cropped.png" alt="A zoomed and cropped part of the original PNG " align="right" width="500" style="box-shadow: 4px 4px 3px grey;"/> | <img src="man/figures/plot20_cropped.webp" alt="The same zoom level and cropped part of the plot in a webp file." align="left" width="500" style="box-shadow: 4px 4px 3px grey;"/> |
|<img src="man/figures/plot_cropped.png" alt="A zoomed and cropped part of the original PNG " align="right" width="500" style="box-shadow: 4px 4px 3px grey;"/> | <img src="man/figures/plot50_cropped.webp" alt="The same zoom level and cropped part of the plot in a webp file." align="left" width="500" style="box-shadow: 4px 4px 3px grey;"/> |
|<img src="man/figures/plot_cropped.png" alt="A zoomed and cropped part of the original PNG " align="right" width="500" style="box-shadow: 4px 4px 3px grey;"/> | <img src="man/figures/plot75_cropped.webp" alt="The same zoom level and cropped part of the plot in a webp file." align="left" width="500" style="box-shadow: 4px 4px 3px grey;"/> |
|<img src="man/figures/plot_cropped.png" alt="A zoomed and cropped part of the original PNG " align="right" width="500" style="box-shadow: 4px 4px 3px grey;"/> | <img src="man/figures/plot90_cropped.webp" alt="The same zoom level and cropped part of the plot in a webp file." align="left" width="500" style="box-shadow: 4px 4px 3px grey;"/> |
|<img src="man/figures/plot_cropped.png" alt="A zoomed and cropped part of the original PNG " align="right" width="500" style="box-shadow: 4px 4px 3px grey;"/> | <img src="man/figures/plot100_cropped.webp" alt="The same zoom level and cropped part of the plot in a webp file." align="left" width="500" style="box-shadow: 4px 4px 3px grey;"/> |
## How to contribute
If you have ideas for improvements or new features feel free to fork and make pull requests to the dev branch. I'm always open to contributions!
## Code of Conduct
Please note that the webpea project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.