forked from Maschette/SOmap
-
Notifications
You must be signed in to change notification settings - Fork 5
/
gg.R
598 lines (555 loc) · 36.7 KB
/
gg.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
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
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
#' Generate a ggplot2 representation of an SOmap object
#'
#' Note: this function is still experimental! Use at your own risk.
#'
#' @param ... : one or more objects as returned by \code{SOmap}, \code{SOmap2}, \code{SOmanagement}, or \code{SOmap_auto}
#'
#' @return An object of class "SOmap_gg", "SOmanagement_gg", or "SOmap_auto_gg". Printing or plotting this object will cause it to generate a ggplot2 object, which will be returned to the user. If this object is printed or plotted (e.g. to the console) then it will be displayed in the current graphics device as is usual for ggplot2 objects.
#'
#' @examples
#' \dontrun{
#' ## generate a SOmap object
#' p <- SOmap2(trim = -45, iwc = TRUE, iwc_labels = TRUE, graticules = TRUE, fronts = TRUE,
#' mpa = TRUE, mpa_labels = TRUE)
#'
#' ## convert this to a ggplot2-based representation
#' pg <- SOgg(p)
#'
#' ## display it
#' pg
#'
#' ## we can see that this object has a bunch of ggplot code embedded inside of it
#' str(pg)
#'
#' ## and that code can be modified if desired
#' ## e.g. change the bathymetry colours
#' pg$scale_fill[[1]]$plotargs$colours <- topo.colors(21)
#' ## plot it
#' pg
#'
#' ## If we want to change the legend breaks we can add breaks to the plotting arguments.
#' pg$scale_fill[[1]]$plotargs$breaks <- c(0,500,1000,4000)
#'
#'
#' ## when the print or plot method is called on pg, it creates an actual ggplot2
#' ## object, which we can capture and modify
#' pg_gg <- plot(pg)
#' class(pg_gg)
#'
#' ## modifying this is done in the same way any other ggplot object is modified
#' ## e.g. add a new scale_fill_gradientn to override the existing one
#' pg_gg + ggplot2::scale_fill_gradientn(colours = heat.colors(21))
#' }
#'
#' @export
SOgg <- function(...) {
x <- list(...)
if (length(x) == 1) {
x <- x[[1]]
if (inherits(x, "SOmap")) {
quietly(SOgg_notauto(x))
} else if (inherits(x, "SOmap_management")) {
quietly(SOgg_management(x))
} else if (inherits(x, "SOmap_auto")) {
quietly(SOgg_auto(x))
} else {
stop("x must be an SOmap/SOmap_auto/SOmanagement object as generated by SOmap, SOmap2, SOmanagement, or SOmap_auto")
}
} else if (length(x) < 1) {
NULL
} else {
## apply SOgg to each item in turn
## but note that if we have passed a SOmap_management object, it won't have projection or trim components
## we should use whatever has been passed in the other object(s)
utrim <- unique(unlist(lapply(x, function(z) z$trim)))
if (!is.null(utrim) && length(utrim) == 1) {
## one unique value of trim
for (xi in seq_along(x)) x[[xi]]$trim <- utrim
}
uprojection <- unique(unlist(lapply(x, function(z) z$projection)))
if (!is.null(uprojection) && length(uprojection) == 1) {
## one unique value of projection
for (xi in seq_along(x)) x[[xi]]$projection <- uprojection
}
## need to do something sensible here if we have conflicting trim or projection entries in different objects
uglymerge(lapply(x, SOgg))
}
}
## TODO: rather than gg-ifying then merging, do the merge via SOmerge then gg-ify
uglymerge <- function(xl) {
out <- xl[[1]]
for (ii in seq_along(xl)[-1]) {
this <- xl[[ii]]
nms <- setdiff(names(this), c("plot_sequence"))
for (nn in nms) out[[nn]] <- this[[nn]]
out$plot_sequence <- c(setdiff(out$plot_sequence, this$plot_sequence), this$plot_sequence)
}
out
}
#' @method plot SOmap_gg
#' @export
plot.SOmap_gg <- function (x, y, ...) {
plot_all_gg(x)
}
#' @method print SOmap_gg
#' @export
print.SOmap_gg <- function(x, ...) {
print(plot(x))
}
## iterate through the object's plot_sequence vector, running the plotfun with plotargs for each
plot_all_gg <- function(x) {
assert_that(inherits(x, c("SOmap_gg", "SOmap_auto_gg")))
## interate through each plottable element in turn
p <- NULL
for (toplot in intersect(x$plot_sequence, names(x))) {
allpf <- x[[toplot]] ## all the stuff to plot for this element
## either a SO_plotter object, or a list thereof
## if it's just one, put it in a list
if (inherits(allpf, "SO_plotter")) allpf <- list(allpf)
if (!all(vapply(allpf, inherits, "SO_plotter", FUN.VALUE = TRUE))) {
warning("plotting behaviour for '", toplot, "' should be specified by an SO_plotter object or list of such objects, ignoring")
next
}
## evaluate each of these plotfuns
for (thispf in allpf[seq_along(allpf)]) {
thisfun <- thispf$plotfun
this_plotargs <- thispf$plotargs
thisp <- if (is.character(thisfun)) do.call(eval(parse(text = thisfun)), this_plotargs) else do.call(thisfun, this_plotargs)
p <- if (is.null(p)) thisp else p + thisp
}
}
p
}
## NOTE, the "parse = TRUE/FALSE" args to geom_text and geom_sf_text seem fragile, need better user control
## gg-ifier for SOmap objects, not SOmap_auto. Any management layers will be passed so SOgg_management for gg-ifying
SOgg_notauto <- function(x) {
if (!inherits(x, "SOmap")) stop("x must be an SOmap object as generated by SOmap or SOmap2")
myext <- extent(x$target)
## plot bathymetry
bdf <- raster::as.data.frame(raster::trim(SOmap::latmask(x$bathy[[1]]$plotargs$x, latitude = x$trim)), xy = TRUE)
names(bdf)[3] <- "Depth"
out <- x[intersect(names(x), c("projection", "target", "straight", "trim"))]
out$init <- SO_plotter(plotfun = "ggplot2::ggplot", plotargs = list(data = bdf, mapping = aes_string(x = "x", y = "y")))
out$bathy <- SO_plotter(plotfun = "ggplot2::geom_raster", plotargs = list(mapping = aes_string(fill = "Depth")))
out$coord <- SO_plotter(plotfun = "ggplot2::coord_sf", plotargs = list(default = TRUE))
out$plot_sequence <- c("init", "bathy", "coord")
out$scale_fill <- SO_plotter(plotfun = "ggplot2::scale_fill_gradientn", plotargs = list(colours = x$bathy[[1]]$plotargs$col, na.value = "#FFFFFF00", guide = if (!x$straight) "none" else "colourbar", limits = c(-9638, 5145)))
out$plot_sequence <- c(out$plot_sequence, "scale_fill")
if (!is.null(x$bathy_legend) && "bathy_legend" %in% x$plot_sequence && !x$straight) {
if (inherits(x$bathy_legend[[1]], "SOmap_legend")) {
out$bathy_legend <- SOgg_legend(x$bathy_legend[[1]])
} else {
## old code, possibly not needed any more
suppressMessages(thecolors <- fortify(x$bathy_legend[[1]]$legend[[2]]$plotargs$x))
## exclude the last two entries here, they are the outer (long) borders
theticks <- x$bathy_legend[[1]]$ticks[[1]]$plotargs$x
theticks <- theticks[seq_len(nrow(theticks)-2), ]
suppressMessages(theticks <- fortify(theticks))
##suppressMessages(themask <- fortify(x$bathy_legend$graticules$plotargs$x))
thecolors$cols <- as.numeric(thecolors$id)
out$bathy_legend <- c(SO_plotter(plotfun = "ggplot2::geom_line", plotargs = list(data = theticks, mapping = aes_string(x = "long", y = "lat", group = "group"), col = x$bathy_legend[[1]]$ticks[[1]]$plotargs$col, size = 1)),
SO_plotter(plotfun = "ggplot2::geom_polygon", plotargs = list(data = thecolors, mapping = aes_string(x = "long", y = "lat", group = "group"), fill = NA, col = x$bathy_legend[[1]]$ticks[[1]]$plotargs$col, size = 1)))
out$bathy_legend <- c(out$bathy_legend, unlist(lapply(seq_along(x$bathy_legend[[1]]$legend[[2]]$plotargs$col), function(ii) SO_plotter(plotfun = "ggplot2::geom_polygon", plotargs = list(data = thecolors[thecolors$cols == ii, ], mapping = aes_string(x = "long", y = "lat", group = "group"), fill = x$bathy_legend[[1]]$legend[[2]]$plotargs$col[ii], col = NA))), recursive = FALSE))
temp <- as.data.frame(x$bathy_legend[[1]]$tick_labels[[1]]$plotargs$x)
out$bathy_legend <- c(out$bathy_legend, SO_plotter(plotfun = "ggplot2::geom_text", plotargs = list(data = temp, mapping = aes_string(x = if ("lon" %in% names(temp)) "lon" else "coords.x1", y = if ("lat" %in% names(temp)) "lat" else "coords.x2", label = "a"), size = SOgg_cex(x$bathy_legend[[1]]$tick_labels[[1]]$plotargs$cex))))
}
out$plot_sequence <- c(out$plot_sequence, "bathy_legend")
}
## extra legends
xlegs <- x$plot_sequence[grepl("^legend_", x$plot_sequence)]
xlegs <- intersect(xlegs, names(x))
for (lnm in xlegs) {
if (inherits(x[[lnm]][[1]], "SOmap_legend")) {
out[[lnm]] <- SOgg_legend(x[[lnm]][[1]])
out$plot_sequence <- c(out$plot_sequence, lnm)
} else {
warning("unexpected legend object with name: ", lnm)
}
}
## buffer to use for cropping things back to our extent of interest
buf <- make_buf(x$trim+2, x$projection)
if (!is.null(x$coastline) && "coastline" %in% x$plot_sequence) {
## the coastline data has to be trimmed to our northernmost latitude
## masking (using e.g. x$outer_mask) is likely to be problematic because of z-ordering
## TODO check that this trimming is robust
this <- suppressWarnings(sf::st_intersection(buf, x$coastline[[1]]$plotargs$x))
out$coastline <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, fill = x$coastline[[1]]$plotargs$col, col = x$coastline[[1]]$plotargs$border, inherit.aes = FALSE))
out$plot_sequence <- c(out$plot_sequence, "coastline")
}
if (!is.null(x$ice) && "ice" %in% x$plot_sequence) {
## TODO check that this trimming is robust
this <- suppressWarnings(sf::st_intersection(buf, x$ice[[1]]$plotargs$x))
out$ice <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, fill = x$ice[[1]]$plotargs$col, col = x$ice[[1]]$plotargs$border, inherit.aes = FALSE))
out$plot_sequence <- c(out$plot_sequence, "ice")
}
## fronts
if (!is.null(x$fronts) && "fronts" %in% x$plot_sequence) {
this <- x$fronts[[1]]$plotargs$x
this <- suppressWarnings(sf::st_intersection(buf, this))
thiscol <- rep(x$fronts[[1]]$plotargs$col, ceiling(nrow(this)/length(x$fronts[[1]]$plotargs$col)))
thiscol <- thiscol[seq_len(nrow(this))]
out$fronts <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = thiscol, inherit.aes = FALSE))
out$plot_sequence <- c(out$plot_sequence, "fronts")
}
## Graticule grid
if (!is.null(x$graticule) && "graticule" %in% x$plot_sequence) {
this <- fortify(x$graticule$main$plotargs$x)
this <- this[this$long >= myext[1] & this$long <= myext[2] & this$lat >= myext[3] & this$lat <= myext[4], ]
out$graticule <- SO_plotter(plotfun = "ggplot2::geom_path", plotargs = list(data = this, mapping = aes_string(x = "long", y = "lat", group = "group"), col = x$graticule$main$plotargs$col, linetype = x$graticule$main$plotargs$lty))
if (!is.null(x$graticule$labels)) {
this <- as.data.frame(x$graticule$labels$plotargs$x)
this <- this[this$x >= myext[1] & this$x <= myext[2] & this$y >= myext[3] & this$y <= myext[4], ]
out$graticule <- c(out$graticule, SO_plotter(plotfun = "ggplot2::geom_text", plotargs = list(data = this, mapping = aes_string(label = "lab"), parse = TRUE, col = x$graticule$labels$plotargs$col, size = SOgg_cex(x$graticule$labels$plotargs$cex))))
}
out$plot_sequence <- c(out$plot_sequence, "graticule")
}
out$axis_labels <- SO_plotter(plotfun = "ggplot2::labs", plotargs = list())
out$plot_sequence <- c(out$plot_sequence, "axis_labels")
out$theme <- SO_plotter(plotfun = "ggplot2::theme", plotargs = list(axis.title = element_blank(),
axis.text.x = element_blank(), axis.ticks.x = element_blank(),
axis.text.y = element_blank(), axis.ticks.y = element_blank(),
panel.border = element_blank(),
panel.background = element_blank()))
out$plot_sequence <- c(out$plot_sequence, "theme")
## process the ccamlr_statistical_areas, ccamlr_ssru etc components (if they exist) using SOgg_management
temp <- SOgg_management(x)
for (nn in setdiff(names(temp), "plot_sequence")) out[[nn]] <- temp[[nn]]
out$plot_sequence <- c(out$plot_sequence, temp$plot_sequence)
if (!is.null(x$border) && "border" %in% x$plot_sequence) {
suppressMessages(this <- fortify(x$border[[1]]$plotargs$x))
this$col <- (as.numeric(this$id) %% length(x$border[[1]]$plotargs$col)) + 1
out$border <- NULL
for (ii in seq_along(x$border[[1]]$plotargs$col)) {
out$border <- c(out$border, SO_plotter(plotfun = "ggplot2::geom_polygon", plotargs = list(data = this[this$col == ii, ], mapping = aes_string(x = "long", y = "lat", group = "group"), fill = x$border[[1]]$plotargs$col[ii], col = "black")))
}
out$plot_sequence <- c(out$plot_sequence, "border")
}
structure(out, class = "SOmap_gg")
}
## gg-ifier for SOmap_legend objects
SOgg_legend <- function(x) {
if (!inherits(x, "SOmap_legend")) stop("x must be an SOmap_legend object as generated by SOleg")
suppressMessages(thecolors <- fortify(x$legend[[2]]$plotargs$x))
theticks <- x$ticks[[1]]$plotargs$x
theticks <- theticks[seq_len(nrow(theticks)), ]
suppressMessages(theticks <- fortify(theticks))
thecolors$cols <- as.numeric(thecolors$id)
legend_as_annotation <- FALSE
if (legend_as_annotation) {
## experimental, not yet used
out <- c()
if ("ticks" %in% x$plot_sequence) {
out <- c(out, SO_plotter(plotfun = "ggplot2::annotate", plotargs = list(geom = "path", x = theticks$long, y = theticks$lat, group = theticks$group, col = x$ticks[[1]]$plotargs$col, size = 1)), SO_plotter(plotfun = "ggplot2::annotate", plotargs = list(geom = "polygon", x = thecolors$long, y = thecolors$lat, group = thecolors$group, fill = NA, col = x$ticks[[1]]$plotargs$col, size = 1)))
}
if ("legend" %in% x$plot_sequence) {
out <- c(out, unlist(lapply(seq_along(x$legend[[2]]$plotargs$col), function(ii) SO_plotter(plotfun = "ggplot2::annotate", plotargs = list(geom = "polygon", x = thecolors$long[thecolors$cols == ii], y = thecolors$lat[thecolors$cols == ii], fill = x$legend[[2]]$plotargs$col[ii], col = NA))), recursive = FALSE))
}
if ("tick_labels" %in% x$plot_sequence) {
temp <- as.data.frame(x$tick_labels[[1]]$plotargs$x)
out <- c(out, SO_plotter(plotfun = "ggplot2::annotate", plotargs = list(geom = "text", x = temp$lon, y = temp$lat, label = temp$a, size = SOgg_cex(x$tick_labels[[1]]$plotargs$cex))))
}
if ("legend_labels" %in% x$plot_sequence) {
temp <- as.data.frame(x$legend_labels[[1]]$plotargs$x)
tang <- if (is.null(x$legend_labels[[1]]$plotargs$srt)) 0 else x$legend_labels[[1]]$plotargs$srt
out <- c(out, SO_plotter(plotfun = "ggplot2::annotate", plotargs = list(geom = "text", x = temp$lon, y = temp$lat, label = temp$a, size = SOgg_cex(x$legend_labels[[1]]$plotargs$cex), angle = tang)))
}
} else {
out <- c()
if ("ticks" %in% x$plot_sequence) {
out <- c(out, SO_plotter(plotfun = "ggplot2::geom_line", plotargs = list(data = theticks, mapping = aes_string(x = "long", y = "lat", group = "group"), col = x$ticks[[1]]$plotargs$col, size = 1)), SO_plotter(plotfun = "ggplot2::geom_polygon", plotargs = list(data = thecolors, mapping = aes_string(x = "long", y = "lat", group = "group"), fill = NA, col = x$ticks[[1]]$plotargs$col, size = 1)))
}
if ("legend" %in% x$plot_sequence) {
out <- c(out, unlist(lapply(seq_along(x$legend[[2]]$plotargs$col), function(ii) SO_plotter(plotfun = "ggplot2::geom_polygon", plotargs = list(data = thecolors[thecolors$cols == ii, ], mapping = aes_string(x = "long", y = "lat", group = "group"), fill = x$legend[[2]]$plotargs$col[ii], col = NA))), recursive = FALSE))
}
if ("tick_labels" %in% x$plot_sequence) {
temp <- as.data.frame(x$tick_labels[[1]]$plotargs$x)
out <- c(out, SO_plotter(plotfun = "ggplot2::geom_text", plotargs = list(data = temp, mapping = aes_string(x = if ("lon" %in% names(temp)) "lon" else "coords.x1", y = if ("lat" %in% names(temp)) "lat" else "coords.x2", label = "a"), size = SOgg_cex(x$tick_labels[[1]]$plotargs$cex))))
}
if ("legend_labels" %in% x$plot_sequence) {
tang <- if (is.null(x$legend_labels[[1]]$plotargs$srt)) 0 else x$legend_labels[[1]]$plotargs$srt
temp <- as.data.frame(x$legend_labels[[1]]$plotargs$x)
out <- c(out, SO_plotter(plotfun = "ggplot2::geom_text", plotargs = list(data = temp, mapping = aes_string(x = if ("lon" %in% names(temp)) "lon" else "coords.x1", y = if ("lat" %in% names(temp)) "lat" else "coords.x2", label = "a"), angle = tang, size = SOgg_cex(x$legend_labels[[1]]$plotargs$cex))))
}
}
out
}
#' Convert cex to ggplot size
#'
#' Text size in base graphics is generally specified via \code{cex} values, which are multipliers applied to the device pointsize. \code{SOgg_cex} is a convenience function that converts a cex value into a \code{size} value as used by ggplot2 geometries.
#'
#' @param cex numeric: character expansion, see \code{\link{par}}
#'
#' @return The corresponding 'size' value to use in ggplot calls
#'
#' @export
SOgg_cex <- function(cex) {
if (missing(cex) || is.null(cex)) cex <- 1
par("ps")*cex*0.35278 ## device pointsize * cex * ggplot_multiplier
}
## gg-ifier for SOmanagement objects
SOgg_management <- function(x, basemap) {
## this can be given an SOmap_management object, or an SOmap object (in which case it only extracts the management components
if (!inherits(x, c("SOmap_management", "SOmap"))) stop("x must be an SOmap_management object as generated by SOmanagement")
out <- list()
have_warned <- FALSE
thisproj <- NULL
if ("projection" %in% names(x)) {
thisproj <- x$projection
} else if (!missing(basemap)) {
thisproj <- basemap$projection
} else {
have_warned <- TRUE
warning("to ensure correct cropping of layers, either need to be an SOmap object, or basemap to be supplied")
}
thistrim <- NULL
if ("trim" %in% names(x)) {
thistrim <- x$trim
} else if (!missing(basemap)) {
thistrim <- basemap$trim
} else {
if (!have_warned) warning("to ensure correct cropping of layers, either need to be an SOmap object, or basemap to be supplied")
}
## buffer to use for cropping things back to our extent of interest
if (is.null(thisproj) || is.null(thistrim)) {
buf <- NULL
} else {
buf <- make_buf(x$trim+2, x$projection)
}
apply_buf <- function(thing) if (is.null(buf)) thing else suppressWarnings(sf::st_intersection(buf, thing))
if (!is.null(x$ccamlr_statistical_areas) && "ccamlr_statistical_areas" %in% x$plot_sequence) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$ccamlr_statistical_areas$main$plotargs$x)))
out$ccamlr_statistical_areas <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$ccamlr_statistical_areas$main$plotargs$border, inherit.aes = FALSE, fill = NA))#fill = x$ccamlr_statistical_areas$main$plotargs$col)
if (!is.null(x$ccamlr_statistical_areas$labels)) {
temp <- x$ccamlr_statistical_areas[names(x$ccamlr_statistical_areas) %in% "labels"]
for (templab in temp) {
this <- templab$plotargs$x
this <- suppressWarnings(apply_buf(sf::st_as_sf(this)))
out$ccamlr_statistical_areas <- c(out$ccamlr_statistical_areas, SO_plotter(plotfun = "ggplot2::geom_sf_text", plotargs = list(data = this, mapping = aes_string(label = "LongLabel"), parse = FALSE, col = templab$plotargs$col, size = SOgg_cex(templab$plotargs$cex), inherit.aes = FALSE)))
}
}
out$plot_sequence <- c(out$plot_sequence, "ccamlr_statistical_areas")
}
if (!is.null(x$ccamlr_ssru) && "ccamlr_ssru" %in% x$plot_sequence) {
if (is.null(x$ccamlr_ssru$main$plotargs$col)) x$ccamlr_ssru$main$plotargs$col <- NA
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$ccamlr_ssru$main$plotargs$x)))
out$ccamlr_ssru <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$ccamlr_ssru$main$plotargs$border, fill = x$ccamlr_ssru$main$plotargs$col, inherit.aes = FALSE))
if (!is.null(x$ccamlr_ssru$labels)) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$ccamlr_ssru$labels$plotargs$x)))
out$ccamlr_ssru <- c(out$ccamlr_ssru, SO_plotter(plotfun = "ggplot2::geom_sf_text", plotargs = list(data = this, mapping = aes_string(label = as.character("Name")), parse = FALSE, col = x$ccamlr_ssru$labels$plotargs$col, size = SOgg_cex(x$ccamlr_ssru$labels$plotargs$cex), inherit.aes = FALSE)))##, pos = x$ccamlr_ssru$labels$pos, offset = x$ccamlr_ssru$labels$offset)
}
out$plot_sequence <- c(out$plot_sequence, "ccamlr_ssru")
}
if (!is.null(x$ccamlr_ssmu) && "ccamlr_ssmu" %in% x$plot_sequence) {
if (is.null(x$ccamlr_ssmu$main$plotargs$col)) x$ccamlr_ssmu$main$plotargs$col <- NA
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$ccamlr_ssmu$main$plotargs$x)))
out$ccamlr_ssmu <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$ccamlr_ssmu$main$plotargs$border, fill = x$ccamlr_ssmu$main$plotargs$col, inherit.aes = FALSE))
if (!is.null(x$ccamlr_ssmu$labels)) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$ccamlr_ssmu$labels$plotargs$x)))
out$ccamlr_ssmu <- c(out$ccamlr_ssmu, SO_plotter(plotfun = "ggplot2::geom_sf_text", plotargs = list(data = this, mapping = aes_string(label = as.character("ShortLabel")), parse = FALSE, col = x$ccamlr_ssmu$labels$plotargs$col, size = SOgg_cex(x$ccamlr_ssmu$labels$plotargs$cex), inherit.aes = FALSE)))##, pos = x$ccamlr_ssmu$labels$pos, offset = x$ccamlr_ssmu$labels$offset)
}
out$plot_sequence <- c(out$plot_sequence, "ccamlr_ssmu")
}
if (!is.null(x$iwc) && "iwc" %in% x$plot_sequence) {
pidx <- seq_along(x$iwc)
if (!is.null(names(x$iwc))) pidx <- pidx[!names(x$iwc) %in% c("labels")] ## not labels here
if (length(pidx) > 0) {
this <- do.call(rbind, lapply(pidx, function(z) { out <- as.data.frame(x$iwc[[z]]$plotargs$x); out$id <- z; out}))
names(this) <- c("x", "y", "id")
out$iwc <- SO_plotter(plotfun = "ggplot2::geom_path", plotargs = list(data = this, mapping = aes_string(x = "x", y = "y", group = "id"), col = x$iwc[[pidx[1]]]$plotargs$col, inherit.aes = FALSE))
}
if (!is.null(x$iwc$labels)) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$iwc$labels$plotargs$x)))
out$iwc <- c(out$iwc, SO_plotter(plotfun = "ggplot2::geom_sf_text", plotargs = list(data = this, mapping = aes_string(label = "a.1"), parse = FALSE, col = x$iwc$labels$plotargs$col, size = SOgg_cex(x$iwc$labels$plotargs$cex), inherit.aes = FALSE)))
}
out$plot_sequence <- c(out$plot_sequence, "iwc")
}
if (!is.null(x$research_blocks) && "research_blocks" %in% x$plot_sequence) {
if (is.null(x$research_blocks$main$plotargs$col)) x$research_blocks$main$plotargs$col <- NA
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$research_blocks$main$plotargs$x)))
out$research_blocks <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$research_blocks$main$plotargs$border, fill = x$research_blocks$main$plotargs$col, inherit.aes = FALSE))
if (!is.null(x$research_blocks$labels)) {
this <- x$research_blocks$labels$plotargs$x
this <- suppressWarnings(apply_buf(sf::st_as_sf(this)))
out$research_blocks <- c(out$research_blocks, SO_plotter(plotfun = "ggplot2::geom_sf_text", plotargs = list(data = this, mapping = aes_string(label = as.character("GAR_Short_")), parse = FALSE, col = x$research_blocks$labels$plotargs$col, size = SOgg_cex(x$research_blocks$labels$plotargs$cex), inherit.aes = FALSE)))
}
out$plot_sequence <- c(out$plot_sequence, "research_blocks")
}
if (!is.null(x$sprfmo_research_blocks) && "sprfmo_research_blocks" %in% x$plot_sequence) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$sprfmo_research_blocks[[1]]$plotargs$x)))
that <- suppressWarnings(apply_buf(sf::st_as_sf(x$sprfmo_research_blocks[[2]]$plotargs$x)))
out$sprfmo_research_blocks <- c(SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$sprfmo_research_blocks[[1]]$plotargs$col, inherit.aes = FALSE)),
SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = that, col = x$sprfmo_research_blocks[[2]]$plotargs$col, inherit.aes = FALSE)))
out$plot_sequence <- c(out$plot_sequence, "sprfmo_research_blocks")
}
if (!is.null(x$eez) && "eez" %in% x$plot_sequence) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$eez$main$plotargs$x)))
out$eez <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$eez$main$plotargs$border, fill = x$eez$main$plotargs$col, inherit.aes = FALSE))
if (!is.null(x$eez$labels)) {
this <- x$eez$labels$plotargs$x
this <- suppressWarnings(apply_buf(sf::st_as_sf(this)))
out$eez <- c(out$eez, SO_plotter(plotfun = "ggplot2::geom_sf_text", plotargs = list(data = this, mapping = aes_string(label = "ShortLabel"), parse = FALSE,size = SOgg_cex(x$eez$labels$plotargs$cex), col = x$eez$labels$plotargs$col, inherit.aes = FALSE)))##, pos = x$eez$labels$pos, offset = x$eez$labels$offset)
}
out$plot_sequence <- c(out$plot_sequence, "eez")
}
if (!is.null(x$mpa) && "mpa" %in% x$plot_sequence) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$mpa$main$plotargs$x)))
out$mpa <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$mpa$main$plotargs$border, fill = x$mpa$main$plotargs$col, inherit.aes = FALSE))
if (!is.null(x$mpa$labels)) {
this <- x$mpa$labels$plotargs$x
this <- suppressWarnings(apply_buf(sf::st_as_sf(this)))
out$mpa <- c(out$mpa, SO_plotter(plotfun = "ggplot2::geom_sf_text", plotargs = list(data = this, mapping = aes_string(label = "ShortLabel"), parse = TRUE, col = x$mpa$labels$plotargs$col, size = SOgg_cex(x$mpa$labels$plotargs$cex), inherit.aes = FALSE)))##, cex = x$mpa$labels$cex, pos = x$mpa$labels$pos, offset = x$mpa$labels$offset)
}
out$plot_sequence <- c(out$plot_sequence, "mpa")
}
if (!is.null(x$ccamlr_planning_domains) && "ccamlr_planning_domains" %in% x$plot_sequence) {
this <- suppressWarnings(apply_buf(sf::st_as_sf(x$ccamlr_planning_domains$main$plotargs$x)))
## TODO fix that intersection, is slow because of complexity of coastline
out$ccamlr_planning_domains <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, col = x$ccamlr_planning_domains$main$plotargs$border, fill = x$ccamlr_planning_domains$main$plotargs$col, inherit.aes = FALSE))
if (!is.null(x$ccamlr_planning_domains$labels)) {
## this is horrible code
temp <- x$ccamlr_planning_domains[names(x$ccamlr_planning_domains) %in% "labels"]
for (lb in temp) {
crds <- lb$plotargs$x
crds <- if (inherits(crds, "Spatial")) as.data.frame(sp::coordinates(crds)) else as.data.frame(sf::st_coordinates(crds))
names(crds) <- c("x", "y")
crds$lab <- lb$plotargs$x$labs
if (is.null(lb$plotargs$pos)) {
hj <- 0.5; vj <- 0.5
} else if (lb$plotargs$pos == 1) {
## text below the specified coords
hj <- 0.5; vj <- 0
} else if (lb$plotargs$pos == 2) {
## to the left
hj <- 1; vj <- 0.5
} else if (lb$plotargs$pos == 3) {
## above
hj <- 0.5; vj <- 1
} else {
## right
hj <- 0; vj = 0.5
}
out$ccamlr_planning_domains <- c(out$ccamlr_planning_domains, SO_plotter(plotfun = "ggplot2::geom_text", plotargs = list(data = crds, mapping = aes_string(x = "x", y = "y", label = "lab"), parse = FALSE, col = lb$plotargs$col, inherit.aes = FALSE, hjust = hj, vjust = vj)))
}
}
out$plot_sequence <- c(out$plot_sequence, "ccamlr_planning_domains")
}
structure(out, class = "SOmanagement_gg")
}
## gg-ifier for SOmap_auto objects
SOgg_auto <- function(x) {
if (!inherits(x, "SOmap_auto")) stop("x must be an SOmap_auto object as generated by SOmap_auto")
myext <- extent(x$target)
## plot bathymetry
bdf <- raster::as.data.frame(x$bathy[[1]]$plotargs$x, xy = TRUE)
names(bdf) <- c("Longitude", "Latitude", "Depth")
out <- x[intersect(names(x), c("projection", "target", "crs"))]
out$init <- SO_plotter(plotfun = "ggplot2::ggplot", plotargs = list(data = bdf, mapping = aes_string(x = "Longitude", y = "Latitude")))
out$bathy <- SO_plotter(plotfun = "ggplot2::geom_raster", plotargs = list(mapping = aes_string(fill = "Depth")))
out$coord <- SO_plotter(plotfun = "ggplot2::coord_sf", plotargs = list(default = TRUE))
out$plot_sequence <- c("init", "bathy", "coord")
clims <- tryCatch(range(x$bathy[[1]]$plotargs$breaks, na.rm = TRUE), error = function(e) c(-9638, 5145)) ## match colour limits, with fallback
## our colour breaks are not evenly spaced, scale these to 0-1 as pass as "values" arg to scale_fill_gradientn
cvals <- tryCatch((x$bathy[[1]]$plotargs$breaks - min(x$bathy[[1]]$plotargs$breaks))/diff(range(x$bathy[[1]]$plotargs$breaks)), error = function(e) NULL)
out$scale_fill <- SO_plotter(plotfun = "ggplot2::scale_fill_gradientn", plotargs = list(colours = x$bathy[[1]]$plotargs$col, values = cvals, na.value = "#FFFFFF00", limits = clims))
out$plot_sequence <- c(out$plot_sequence, "scale_fill")
if (!is.null(x$coastline) && "coastline" %in% x$plot_sequence) {
this <- suppressWarnings(sf::st_as_sf(x$coastline[[1]]$plotargs$x))
out$coastline <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, fill = x$coastline[[1]]$plotargs$col, col = x$coastline[[1]]$plotargs$border, inherit.aes = FALSE))
out$plot_sequence <- c(out$plot_sequence, "coastline")
}
if (!is.null(x$ice) && "ice" %in% x$plot_sequence) {
this <- suppressWarnings(sf::st_as_sf(x$ice[[1]]$plotargs$x))
out$ice <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, fill = x$ice[[1]]$plotargs$col, col = x$ice[[1]]$plotargs$border, inherit.aes = FALSE))
out$plot_sequence <- c(out$plot_sequence, "ice")
}
if (!is.null(x$contours) && "contours" %in% x$plot_sequence) {
out$contours <- SO_plotter(plotfun = "ggplot2::geom_contour", plotargs = list(mapping = aes_string(z = "Depth"), breaks = x$contours[[1]]$plotargs$levels, col = x$contours[[1]]$plotargs$col))
out$plot_sequence <- c(out$plot_sequence, "contours")
}
if (!is.null(x$graticule) && "graticule" %in% x$plot_sequence) {
out$graticule <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = x$graticule[[1]]$plotargs$x, col = "grey", inherit.aes = FALSE))
out$plot_sequence <- c(out$plot_sequence, "graticule")
}
## TODO These should iterate through multiple SO_plotters?
if(!is.null(x$lines) && "lines" %in% x$plot_sequence) {
out$lines <- SO_plotter(plotfun = "ggplot2::geom_path", plotargs = list(data = setNames(as.data.frame(x$lines[[1]]$plotargs$x), c("x", "y")), mapping = aes_string(x = "x", y = "y"), col = x$lines[[1]]$plotargs$col, linetype = x$lines[[1]]$plotargs$lty, size = x$lines[[1]]$plotargs$lwd))
out$plot_sequence <- c(out$plot_sequence, "lines")
}
if(!is.null(x$points) && "points" %in% x$plot_sequence) {
out$points <- SO_plotter(plotfun = "ggplot2::geom_point", plotargs = list(data = setNames(as.data.frame(x$points[[1]]$plotargs$x), c("x", "y")), mapping = aes_string(x = "x", y = "y"), col = x$points[[1]]$plotargs$col, shape = x$points[[1]]$plotargs$pch, size = x$points[[1]]$plotargs$cex))
out$plot_sequence <- c(out$plot_sequence, "points")
}
out$theme <- SO_plotter(plotfun = "ggplot2::theme", plotargs = list(axis.title = element_blank(), panel.border = element_rect(color = "black", fill = NA), panel.background = element_blank(), axis.text.x = element_text(angle = 90, vjust = 0.5)))
out$plot_sequence <- c(out$plot_sequence, "theme")
out$scale_x <- SO_plotter(plotfun = "ggplot2::scale_x_continuous", plotargs = list(expand = c(0, 0)))
out$scale_y <- SO_plotter(plotfun = "ggplot2::scale_y_continuous", plotargs = list(expand = c(0, 0)))
out$plot_sequence <- c(out$plot_sequence, "scale_x", "scale_y")
structure(out, class = "SOmap_auto_gg")
}
## old object structure
##SOgg_auto <- function(x) {
## if (!inherits(x, "SOmap_auto")) stop("x must be an SOmap_auto object as generated by SOmap_auto")
## myext <- extent(x$target)
## ## plot bathymetry
## bdf <- raster::as.data.frame(x$bathy, xy = TRUE)
## names(bdf) <- c("Longitude","Latitude","Depth")
##
## out <- x[intersect(names(x), c("projection", "target", "straight", "trim"))]
## out$init <- SO_plotter(plotfun = "ggplot2::ggplot", plotargs = list(data = bdf, mapping = aes_string(x = "Longitude", y = "Latitude")))
## out$bathy <- SO_plotter(plotfun = "ggplot2::geom_raster", plotargs = list(mapping = aes_string(fill = "Depth")))
## out$coord <- SO_plotter(plotfun = coord_sf, plotargs = list(default = TRUE))
## out$plot_sequence <- c("init", "bathy", "coord")
##
## out$scale_fill <- SO_plotter(plotfun = "ggplot2::scale_fill_gradientn", plotargs = list(colours = x$bathy_palette, na.value = "#FFFFFF00"))
## out$plot_sequence <- c(out$plot_sequence, "scale_fill")
##
## if (!is.null(x$coastline)) {
## this <- suppressWarnings(sf::st_as_sf(x$coastline$data))
## out$coastline <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, fill = x$coastline$fillcol, col = x$coastline$linecol, inherit.aes = FALSE))
## out$plot_sequence <- c(out$plot_sequence, "coastline")
## }
## if (!is.null(x$ice)) {
## this <- suppressWarnings(sf::st_as_sf(x$ice$data))
## out$ice <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, fill = x$ice$fillcol, col = x$ice$linecol, inherit.aes = FALSE))
## out$plot_sequence <- c(out$plot_sequence, "ice")
## }
## if (x$contours) {
## this <- suppressWarnings(sf::st_as_sf(x$coastline$data))
## out$contours <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = this, fill = x$coastline$fillcol, col = x$coastline$linecol, inherit.aes = FALSE))
## out$plot_sequence <- c(out$plot_sequence, "contours")
##
## }
##
## if (!is.null(x$graticule)) {
## out$graticule <- SO_plotter(plotfun = "ggplot2::geom_sf", plotargs = list(data = x$graticule, col = "grey", inherit.aes = FALSE))
## out$plot_sequence <- c(out$plot_sequence, "graticule")
## }
##
## if(!is.null(x$lines_data)) {
## out$lines_data <- SO_plotter(plotfun = "ggplot2::geom_path", plotargs = list(data = setNames(as.data.frame(x$lines_data), c("x", "y")), mapping = aes_string(x = "x", y = "y"), col = x$lcol, linetype = x$llty, size = x$llwd))
## out$plot_sequence <- c(out$plot_sequence, "lines_data")
## }
##
## if(!is.null(x$points_data)) {
## out$points_data <- SO_plotter(plotfun = "ggplot2::geom_point", plotargs = list(data = setNames(as.data.frame(x$points_data), c("x", "y")), mapping = aes_string(x = "x", y = "y"), col = x$pcol, shape = x$ppch, size = x$pcex))
## out$plot_sequence <- c(out$plot_sequence, "points_data")
## }
##
## out$theme <- SO_plotter(plotfun = "ggplot2::theme", plotargs = list(axis.title = element_blank(), panel.border = element_rect(color = "black", fill = NA), panel.background = element_blank(), axis.text.x = element_text(angle = 90, vjust = 0.5)))
## out$plot_sequence <- c(out$plot_sequence, "theme")
## out$scale_x <- SO_plotter(plotfun = "ggplot2::scale_x_continuous", plotargs = list(expand = c(0, 0)))
## out$scale_y <- SO_plotter(plotfun = "ggplot2::scale_y_continuous", plotargs = list(expand = c(0, 0)))
## out$plot_sequence <- c(out$plot_sequence, "scale_x", "scale_y")
##
## structure(out, class = "SOmap_auto_gg")
##}
#' @method plot SOmap_auto_gg
#' @export
plot.SOmap_auto_gg <- function (x, y, ...) {
plot_all_gg(x)
}
#' @method print SOmap_auto_gg
#' @export
print.SOmap_auto_gg <- function(x, ...) {
print(plot(x))
}