43
43
# ' specifying dimensions in pixels.
44
44
# ' @param bg Background colour. If `NULL`, uses the `plot.background` fill value
45
45
# ' from the plot theme.
46
+ # ' @param create.dir Whether to create new directories if a non-existing
47
+ # ' directory is specified in the `filename` or `path` (`TRUE`) or return an
48
+ # ' error (`FALSE`, default). If `FALSE` and run in an interactive session,
49
+ # ' a prompt will appear asking to create a new directory when necessary.
46
50
# ' @param ... Other arguments passed on to the graphics device function,
47
51
# ' as specified by `device`.
48
52
# ' @export
84
88
ggsave <- function (filename , plot = last_plot(),
85
89
device = NULL , path = NULL , scale = 1 ,
86
90
width = NA , height = NA , units = c(" in" , " cm" , " mm" , " px" ),
87
- dpi = 300 , limitsize = TRUE , bg = NULL , ... ) {
88
- if (length(filename ) != 1 ) {
89
- if (length(filename ) == 0 ) {
90
- cli :: cli_abort(" {.arg filename} cannot be empty." )
91
- }
92
- len <- length(filename )
93
- filename <- filename [1 ]
94
- cli :: cli_warn(c(
95
- " {.arg filename} must have length 1, not length {len}." ,
96
- " !" = " Only the first, {.file {filename}}, will be used."
97
- ))
98
- }
91
+ dpi = 300 , limitsize = TRUE , bg = NULL ,
92
+ create.dir = FALSE ,
93
+ ... ) {
94
+ filename <- check_path(path , filename , create.dir )
99
95
100
96
dpi <- parse_dpi(dpi )
101
97
dev <- plot_dev(device , filename , dpi = dpi )
102
98
dim <- plot_dim(c(width , height ), scale = scale , units = units ,
103
99
limitsize = limitsize , dpi = dpi )
104
100
105
- if (! is.null(path )) {
106
- filename <- file.path(path , filename )
107
- }
108
101
if (is_null(bg )) {
109
102
bg <- calc_element(" plot.background" , plot_theme(plot ))$ fill %|| % " transparent"
110
103
}
@@ -119,6 +112,56 @@ ggsave <- function(filename, plot = last_plot(),
119
112
invisible (filename )
120
113
}
121
114
115
+ check_path <- function (path , filename , create.dir ,
116
+ call = caller_env()) {
117
+
118
+ if (length(filename ) > 1 && is.character(filename )) {
119
+ cli :: cli_warn(c(
120
+ " {.arg filename} must have length 1, not {length(filename)}." ,
121
+ " !" = " Only the first, {.file {filename[1]}}, will be used."
122
+ ), call = call )
123
+ filename <- filename [1 ]
124
+ }
125
+ check_string(filename , allow_empty = FALSE , call = call )
126
+
127
+ check_string(path , allow_empty = FALSE , allow_null = TRUE , call = call )
128
+ if (! is.null(path )) {
129
+ filename <- file.path(path , filename )
130
+ } else {
131
+ path <- dirname(filename )
132
+ }
133
+
134
+ # Happy path: target file is in valid directory
135
+ if (dir.exists(path )) {
136
+ return (filename )
137
+ }
138
+
139
+ check_bool(create.dir , call = call )
140
+
141
+ # Try to ask user to create a new directory
142
+ if (interactive() && ! create.dir ) {
143
+ cli :: cli_bullets(c(
144
+ " Cannot find directory {.path {path}}." ,
145
+ " i" = " Would you like to create a new directory?"
146
+ ))
147
+ create.dir <- utils :: menu(c(" Yes" , " No" )) == 1
148
+ }
149
+
150
+ # Create new directory
151
+ if (create.dir ) {
152
+ dir.create(path , recursive = TRUE )
153
+ if (dir.exists(path )) {
154
+ cli :: cli_alert_success(" Created directory: {.path {path}}." )
155
+ return (filename )
156
+ }
157
+ }
158
+
159
+ cli :: cli_abort(c(
160
+ " Cannot find directory {.path {path}}." ,
161
+ i = " Please supply an existing directory or use {.code create.dir = TRUE}."
162
+ ), call = call )
163
+ }
164
+
122
165
# ' Parse a DPI input from the user
123
166
# '
124
167
# ' Allows handling of special strings when user specifies a DPI like "print".
0 commit comments