-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimage.plot.nxm.r
More file actions
2400 lines (2220 loc) · 129 KB
/
image.plot.nxm.r
File metadata and controls
2400 lines (2220 loc) · 129 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
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
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
image.plot.nxm <- function(x, y, z, n=NULL, m=NULL, dry=F,
add_grid=F, proj=NULL, zoomfac=NULL,
individual_zlim=F,
horizontal=F, top_bottom=F, add_title=T,
xlab="xaxis", ylab="yaxis", zlab="Variable [unit]",
cex.axis=1.25,
bgcol="white", NAcol="gray",
useRaster=NULL,
poly_border_col=NA,
contour_only=F, add_contour=T, contour_include_zero=T,
contour_posneg_soliddashed=T, contour_posneg_redblue=F,
contour_cols=NULL, contour_unique=F,
contour_smooth=F, contour_smooth_n_segment_thr=5, contour_smooth_spar=0.5,
contour_labcex=0.75, contour_drawlabels=T, contour_vfont=NULL, #c("sans serif", "bold"),
quiver_thr=NULL, quiver_const=F, quiver_nxfac=1, quiver_nyfac=1,
quiver_scale=0.05, quiver_angle=20, quiver_length=0.05,
quiver_col="black", quiver_lty=1, quiver_lwd=0.5,
quiver_legend=NULL,
plot_type="active", plotname="testplot",
cm_bottom=2, cm_left=2.5, cm_top=1,
cm_right=4, colorbar_width_cm=0.45, colorbar_dist_cm=0.2,
width_png=2000, height_png=1666, res=300,
width_pdf=7, height_pdf=7,
axis.args=NULL,
znames_method="text", znames_pos="topleft", znames_cex=1.25,
legend.args=NULL, legend.line=5, legend.cex=0.85,
colorbar.cex=1.25,
family="sans", lwd=0.5, lwd.ticks=0.5,
verbose=F, ...) {
if (verbose) message("\n*********** start image.plot.nxm() with `verbose`=T and `dry`=",
substr(dry, 1, 1), " **************")
if (F) options(warn=2) # for debug
# demo values
if (missing(x) && missing(y) && missing(z)) {
message("x,y,z not provided --> run demo ...")
if (is.null(n)) n <- 3
if (is.null(m)) m <- 2
x <- y <- z <- vector("list", length=n*m)
for (i in 1:(n*m)) {
x[[i]] <- 1:20
y[[i]] <- 1:20
z[[i]] <- array(rnorm(length(x[[i]])*length(y[[i]])),
c(length(x[[i]]), length(y[[i]])))
z[[i]][8:13,8:13] <- NA
}
}
# necessary input; in contrast to the demo case above
if (!missing(x)) {
if (missing(y)) stop("y is missing")
if (missing(z)) stop("z is missing")
if (length(x) == 0) stop("x is of length 0")
}
if (!missing(y)) {
if (missing(x)) stop("x is missing")
if (missing(z)) stop("z is missing")
if (length(y) == 0) stop("y is of length 0")
}
if (!missing(z)) {
if (missing(x)) stop("x is missing")
if (missing(y)) stop("y is missing")
if (length(z) == 0) stop("z is of length 0")
}
if (!is.list(z)) z <- list(z)
if (!is.list(x)) {
xl <- vector("list", length=length(z))
for (i in seq_along(z)) xl[[i]] <- x
x <- xl; rm(xl)
}
if (!is.list(y)) {
yl <- vector("list", length=length(z))
for (i in seq_along(z)) yl[[i]] <- y
y <- yl; rm(yl)
}
if (length(x) != length(z)) stop("x and z must have same length")
if (length(y) != length(z)) stop("y and z must have same length")
# capture additional arguments (aka ellipsis, dots, ...)
dot_list <- list(...) # todo: use base::chkDots(...)?
ndots <- length(dot_list)
dot_names <- names(dot_list)
if (verbose && ndots > 0) {
message("dots:")
for (i in 1:length(dot_list)) {
message("*******************\ndots[[", i, "]]: ", dot_names[i])
cat(capture.output(str(dot_list[[i]])), sep="\n")
}
}
# get nrow and ncol: `grDevices::n2mfrow(nplots)`
nz <- length(z)
if (is.null(n) || is.null(m)) { # default
if (is.null(n) && is.null(m)) {
nm <- grDevices::n2mfrow(nz)
# nz: nrow ncol
# 1: 1 1
# 2: 2 1
# 3: 3 1
# 4: 2 2
# 5: 3 2
# 6: 3 2
# 7: 3 3
# 8: 3 3
if (nz == 8) nm <- c(4, 2)
# 9: 3 3
# 10: 4 3
if (nz == 10) nm <- c(5, 2)
n <- nm[1]; m <- nm[2]
if (F && nz == 2) { # special case: should nrow,ncol = 2,1 (default) or 1,2?
n <- 1; m <- 2
}
} else {
if (is.null(n)) {
n <- ceiling(nz/m)
if (verbose) {
message("provided m = ", m, " cols x automatic n = ", n,
" rows = ", n*m)
}
} else if (is.null(m)) {
m <- ceiling(nz/n)
if (verbose) {
message("provided n = ", n, " rows x automatic m = ", m,
" cols = ", n*m)
}
}
} # if n or m or both are missing
} # if n or m are missing
nplots <- n*m
if (verbose) message("--> n x m = ", n, " rows x ", m, " cols = ", nplots, " plots (nz = ", nz, ")")
if (nplots < nz) {
stop("n*m = ", nplots, " < nz = ", nz, ". re-run with proper n (nrow) or/and m (ncol)")
}
## construct layout mat based on n x m; nrow x ncol
if (top_bottom) { # plot figures from top to bottom and left to right
layout_mat <- matrix(1:(n*m), nrow=n, ncol=m, byrow=F)
} else { # plot figures from left to right and top to bottom
layout_mat <- matrix(1:(n*m), nrow=n, ncol=m, byrow=T)
}
if (!contour_only) { # need colorbar
if (!horizontal) { # vertical colorbar on the right
# left region for axes in cm; columns for plots in relative units; right region for colorbar in cm
layout_mat2 <- cbind(rep(0, times=n), # left axis row
layout_mat,
rep(n*m + 1, times=n)) # right legend column
layout_widths <- c(lcm(cm_left), rep(1/m, times=m), lcm(cm_right))
# upper region for title in cm; rows for plots in relative units; lower region for axes in cm
layout_mat2 <- rbind(rep(0, times=m + 2), # title row
layout_mat2,
rep(0, times=m + 2)) # bottom axis row
layout_heights <- c(lcm(cm_top), rep(1/n, times=n), lcm(cm_bottom))
} else { # horizontal colorbar at the bottom
stop("not yet")
}
} else if (contour_only) { # no colorbar needed
# same as for !contour_only case but with thinner cm_right
layout_mat2 <- cbind(rep(0, times=n), # left axis row
layout_mat,
rep(n*m + 1, times=n)) # right legend column
layout_widths <- c(lcm(cm_left), rep(1/m, times=m), lcm(1)) # 1 cm instead of cm_right
# upper region for title in cm; rows for plots in relative units; lower region for axes in cm
layout_mat2 <- rbind(rep(0, times=m + 2), # title row
layout_mat2,
rep(0, times=m + 2)) # bottom axis row
layout_heights <- c(lcm(cm_top), rep(1/n, times=n), lcm(cm_bottom))
} # if contour_only or not
if (verbose) {
cat("layout_widths=")
dput(layout_widths)
cat("layout_heights=")
dput(layout_heights)
cat("layout_mat2=")
print(layout_mat2)
}
# decide which axes are drawn to which subplot
# n=nrow, m=ncol
left_axis_inds <- bottom_axis_inds <- title_inds <- rep(F, times=nplots)
for (i in seq_len(nplots)) {
# order plots from top to bottom and then from left to right (default: False)
if (top_bottom) {
# titles in top row
if (i == n*(m-1)+1) title_inds[i] <- T
# left axes
if (i <= n) {
if (verbose) message("left axis top_bottom i=", i, " <= n (=", n, ")")
left_axis_inds[i] <- T
}
# bottom axes
if (i %% n == 0 # bottom row
) { # todo: or last column of (nrow-1)th row if n*m > nplots
if (verbose) message("bottom axis top_bottom i=", i, " %% n (=", n, ") = ", i %% n, " == 0")
bottom_axis_inds[i] <- T
}
# else order plots from left to right and then from top to bottom (default: True)
} else if (!top_bottom) {
# titles in top row
if (i == m) title_inds[i] <- T
# left axes
if (verbose) message("i %% m = ", i, " %% ", m, " = ", i %% m)
if (nplots == 1 || m == 1 ||
(nplots > 1 && i %% m == 1)) {
if (verbose) message("left axis !top_bottom i=", i, " %% m (=", m, ") = ", i %% m, " == 1")
left_axis_inds[i] <- T
}
# bottom axes
if (i >= (nplots - m + 1) || # last row
#(nplots > nz && (i >= nplots - m))) { # or last column of (nrow-1)th row if nplots > nz
(nplots > nz && (i >= nplots - (nplots - nz + m - 1)))) { # or (nrow-1)th row if nplots > nz
if (verbose) message("bottom axis !top_bottom i=", i, " >= (n*m - m + 1) = (",
n, "*", m, " - ", m, " + 1) = ", (nplots - m + 1))
bottom_axis_inds[i] <- T
}
} # if top_bottom
} # for i nplots
# just return number of rows and columns
return_list <- list()
return_list$nrow <- n
return_list$ncol <- m
return_list$nplots <- nplots
return_list$nz <- nz
return_list$layout_mat <- layout_mat
return_list$layout_mat2 <- layout_mat2
return_list$layout_widths <- layout_widths
return_list$layout_heights <- layout_heights
return_list$top_bottom <- top_bottom
return_list$left_axis_inds <- left_axis_inds
return_list$bottom_axis_inds <- bottom_axis_inds
return_list$title_inds <- title_inds
if (dry) {
return(return_list)
} else {
if (verbose) message("`dry`=F --> run function with `dry`=T do stop here and return nrow and ncol")
}
# further checks
if (is.null(colorbar.cex)) colorbar.cex <- 1.25
if (is.null(znames_method)) znames_method <- "text"
if (is.null(znames_pos)) znames_pos <- "topleft"
if (is.null(znames_cex)) znames_cex <- 1.25
if (!is.null(znames_method)) {
if (!any(znames_method == c("text", "legend"))) {
stop("`znames_method` must be either \"text\" or \"legend\"")
}
}
if (!is.null(zoomfac)) {
if (!is.numeric(zoomfac)) stop("`zoomfac` must be numeric")
}
if (!is.null(proj)) {
if (!is.character(proj)) stop("`proj` must be character")
if (proj != "") if (!any(search() == "package:oce")) library(oce)
} else {
proj <- "" # default: rectangular plot without projection
}
if (is.null(legend.line)) legend.line <- 5
# check additional objects if provided
if (any(dot_names == "image_list")) {
image_list <- dot_list$image_list
if (!is.null(image_list)) {
for (vi in seq_along(image_list)) {
if (!is.na(image_list[vi])) {
for (i in seq_along(image_list[[vi]])) {
if (is.null(image_list[[vi]][[i]]$x)) stop("provided `image_list` but `image_list[[", vi, "]][[", i, "]]$x` is missing")
if (is.null(image_list[[vi]][[i]]$y)) stop("provided `image_list` but `image_list[[", vi, "]][[", i, "]]$y` is missing")
if (is.null(image_list[[vi]][[i]]$z)) stop("provided `image_list` but `image_list[[", vi, "]][[", i, "]]$z` is missing")
}
}
}
}
} else {
image_list <- NULL
}
polygon_list <- NULL # default
if (any(dot_names == "polygon_list")) {
polygon_list <- dot_list$polygon_list
if (!is.null(polygon_list)) {
for (vi in seq_along(polygon_list)) {
if (!is.na(polygon_list[vi])) {
for (i in seq_along(polygon_list[[vi]])) {
if (!is.na(polygon_list[[vi]][i])) {
if (is.null(polygon_list[[vi]][[i]]$x)) stop("provided `polygon_list` but `polygon_list[[", vi, "]][[", i, "]]$x` is missing")
if (is.null(polygon_list[[vi]][[i]]$y)) stop("provided `polygon_list` but `polygon_list[[", vi, "]][[", i, "]]$y` is missing")
if (is.null(polygon_list[[vi]][[i]]$z)) {
# case 1: show only outline of polygon --> no z needed
if (!is.null(polygon_list[[vi]][[i]]$col)) {
polygon_list[[vi]][[i]]$border <- polygon_list[[vi]][[i]]$col
polygon_list[[vi]][[i]]$col <- NULL
}
if (is.null(polygon_list[[vi]][[i]]$border)) polygon_list[[vi]][[i]]$border <- "black"
if (is.null(polygon_list[[vi]][[i]]$lty)) polygon_list[[vi]][[i]]$lty <- 1
if (is.null(polygon_list[[vi]][[i]]$lwd)) polygon_list[[vi]][[i]]$lwd <- 1
} else if (!is.null(polygon_list[[vi]][[i]]$z)) {
# case 2: color polygon --> z needed
if (is.null(polygon_list$levels)) stop("provided `polygon_list[[", vi, "]][[", i, "]]$z` but ",
"`polygon_list[[", vi, "]][[", i, "]]$levels` is missing")
}
}
}
}
}
}
}
contour_list <- NULL # default
if (any(dot_names == "contour_list")) {
contour_list <- dot_list$contour_list
if (!is.null(contour_list)) {
for (vi in seq_along(contour_list)) {
if (!is.na(contour_list[vi])) {
for (i in seq_along(contour_list[[vi]])) {
if (is.null(contour_list[[vi]][[i]]$x)) stop("provided `contour_list` but `contour_list[[", vi, "]][[", i, "]]$x` is missing")
if (is.null(contour_list[[vi]][[i]]$y)) stop("provided `contour_list` but `contour_list[[", vi, "]][[", i, "]]$y` is missing")
if (is.null(contour_list[[vi]][[i]]$z)) stop("provided `contour_list` but `contour_list[[", vi, "]][[", i, "]]$z` is missing")
if (is.null(contour_list[[vi]][[i]]$levels)) stop("provided `contour_list` but `contour_list[[", vi, "]][[", i, "]]levels` is missing")
if (is.null(contour_list[[vi]][[i]]$col)) contour_list[[vi]][[i]]$col <- "black"
if (is.null(contour_list[[vi]][[i]]$lty)) contour_list[[vi]][[i]]$lty <- 1
if (is.null(contour_list[[vi]][[i]]$lwd)) contour_list[[vi]][[i]]$lwd <- 1
if (is.null(contour_list[[vi]][[i]]$contour_posneg_soliddashed)) contour_list[[vi]][[i]]$contour_posneg_soliddashed <- contour_posneg_soliddashed
if (is.null(contour_list[[vi]][[i]]$contour_posneg_redblue)) contour_list[[vi]][[i]]$contour_posneg_redblue <- contour_posneg_redblue
if (is.null(contour_list[[vi]][[i]]$contour_unique)) contour_list[[vi]][[i]]$contour_unique <- contour_unique
if (is.null(contour_list[[vi]][[i]]$contour_drawlabels)) contour_list[[vi]][[i]]$contour_drawlabels <- contour_drawlabels
if (is.null(contour_list[[vi]][[i]]$contour_smooth)) contour_list[[vi]][[i]]$contour_smooth <- contour_smooth
if (is.null(contour_list[[vi]][[i]]$contour_smooth_n_segment_thr)) contour_list[[vi]][[i]]$contour_smooth_n_segment_thr <- contour_smooth_n_segment_thr
if (is.null(contour_list[[vi]][[i]]$contour_smooth_spar)) contour_list[[vi]][[i]]$contour_smooth_spar <- contour_smooth_spar
if (is.null(contour_list[[vi]][[i]]$contour_smooth)) {
if (is.na(contour_list[[vi]][[i]]$contour_smooth_n_segment_thr) &&
is.na(contour_list[[vi]][[i]]$contour_smooth_spar)) {
stop("`is.null(contour_list[[", vi, "]][[", i, "]]$contour_smooth` = T but both ",
"`contour_list[[", vi, "]][[", i, "]]$contour_smooth_n_segment_thr` and ",
"`contour_list[[", vi, "]][[", i, "]]$contour_smooth_spar` are NA.")
}
}
}
}
}
}
}
quiver_list <- NULL # default
if (any(dot_names == "quiver_list")) {
quiver_list <- dot_list$quiver_list
if (!is.null(quiver_list)) {
for (vi in seq_along(quiver_list)) {
if (!is.na(quiver_list[vi])) {
for (i in seq_along(quiver_list[[vi]])) {
if (!is.na(quiver_list[[vi]][i])) {
if (is.null(quiver_list[[vi]][[i]]$u)) stop("provided `quiver_list` but `quiver_list[[", vi, "]][[", i, "]]$u` is missing")
if (is.null(quiver_list[[vi]][[i]]$v)) stop("provided `quiver_list` but `quiver_list[[", vi, "]][[", i, "]]$v` is missing")
if (is.null(quiver_list[[vi]][[i]]$quiver_const)) quiver_list[[vi]][[i]]$quiver_const <- quiver_const
if (is.null(quiver_list[[vi]][[i]]$quiver_thr)) quiver_list[[vi]][[i]]$quiver_thr <- quiver_thr
if (is.null(quiver_list[[vi]][[i]]$quiver_nxfac)) quiver_list[[vi]][[i]]$quiver_nxfac <- quiver_nxfac
if (is.null(quiver_list[[vi]][[i]]$quiver_nyfac)) quiver_list[[vi]][[i]]$quiver_nyfac <- quiver_nyfac
if (is.null(quiver_list[[vi]][[i]]$quiver_scale)) quiver_list[[vi]][[i]]$quiver_scale <- quiver_scale
if (is.null(quiver_list[[vi]][[i]]$quiver_angle)) quiver_list[[vi]][[i]]$quiver_angle <- quiver_angle
if (is.null(quiver_list[[vi]][[i]]$quiver_length)) quiver_list[[vi]][[i]]$quiver_length <- quiver_length
if (is.null(quiver_list[[vi]][[i]]$quiver_col)) quiver_list[[vi]][[i]]$quiver_col <- quiver_col
if (is.null(quiver_list[[vi]][[i]]$quiver_lty)) quiver_list[[vi]][[i]]$quiver_lty <- quiver_lty
if (is.null(quiver_list[[vi]][[i]]$quiver_lwd)) quiver_list[[vi]][[i]]$quiver_lwd <- quiver_lwd
if (is.null(quiver_list[[vi]][[i]]$quiver_legend)) quiver_list[[vi]][[i]]$quiver_legend <- quiver_legend
if (!is.null(quiver_list[[vi]][[i]]$quiver_legend)) {
if (!is.list(quiver_list[[vi]][[i]]$quiver_legend)) {
stop("quiver_list[[", vi, "]][[", i, "]]$quiver_legend must be either NULL or list")
}
if (is.null(quiver_list[[vi]][[i]]$quiver_legend$x)) quiver_list[[vi]][[i]]$quiver_legend$x <- "x_at[1]"
if (is.null(quiver_list[[vi]][[i]]$quiver_legend$x)) quiver_list[[vi]][[i]]$quiver_legend$x <- "y_at[1]"
if (is.null(quiver_list[[vi]][[i]]$quiver_legend$xvalue)) {
stop("provide numeric `quiver_list[[", vi, "]][[", i, "]]$quiver_legend$xvalue`")
}
if (is.null(quiver_list[[vi]][[i]]$quiver_legend$yvalue)) {
quiver_list[[vi]][[i]]$quiver_legend$yvalue <- 0 # horizontal legend quiver
}
if (quiver_list[[vi]][[i]]$quiver_legend$xvalue == 0 &&
quiver_list[[vi]][[i]]$quiver_legend$xvalue == 0) {
stop("one of `quiver_list[[", vi, "]][[", i, "]]$quiver_legend$xvalue` and `yvalue` must be 0")
}
if (is.null(quiver_list[[vi]][[i]]$quiver_legend$label)) {
quiver_list[[vi]][[i]]$quiver_legend$label <- "unit"
}
}
}
}
}
}
}
}
if (any(dot_names == "addland_list")) {
addland_list <- dot_list$addland_list
if (!is.null(addland_list)) {
if (length(addland_list) != length(z)) {
stop("provided addland_list is of length ", length(addland_list), " but nz = ", nz)
}
for (i in seq_along(addland_list)) {
if (!is.na(addland_list[i])) {
if (!is.null(addland_list[[i]]$data)) {
if (is.character(addland_list[[i]]$data)) {
if (!any(addland_list[[i]]$data == c("world", "world2", "worldHires", "world2Hires"))) {
stop("provided `addland_list[[", i, "]]$data` must be ",
"\"world\"/\"worldHires\" (for lons -180,...,180) or \"world2\"/\"world2Hires\" (for lons 0,...,360)")
}
if (!any(search() == "package:maps")) library(maps)
if (any(addland_list[[i]]$data == c("worldHires", "world2Hires"))) {
if (!any(search() == "package:mapdata")) library(mapdata)
}
addland_list[[i]]$type <- "map"
} else {
if (length(addland_list[[i]]$data) == 4 &&
all(names(addland_list[[i]]$data) == c("x0", "y0", "x1", "y1"))) {
# add checks
addland_list[[i]]$type <- "segments"
} else {
stop("`addland_list[[", i, "]]$data` -structure not implemented yet")
}
}
} else {
stop("provided `addland_list[[", i, "]]$data` is null")
}
}
}
}
} else {
addland_list <- NULL
}
if (any(dot_names == "point_list")) {
point_list <- dot_list$point_list
if (!is.null(point_list)) {
if (length(point_list) != length(z)) {
stop("provided point_list is of length ", length(point_list), " but nz = ", nz)
}
}
} else {
point_list <- vector("list", length=nz)
}
if (any(dot_names == "line_list")) {
line_list <- dot_list$line_list
if (!is.null(line_list)) {
if (length(line_list) != length(z)) {
stop("provided line_list is of length ", length(line_list), " but nz = ", nz)
}
}
} else {
line_list <- vector("list", length=nz)
}
if (any(dot_names == "segment_list")) {
segment_list <- dot_list$segment_list
if (!is.null(segment_list)) {
if (length(segment_list) != length(z)) {
stop("provided segment_list is of length ", length(segment_list), " but nz = ", nz)
}
for (i in seq_along(segment_list)) {
if (!is.na(segment_list[i])) {
if (is.null(segment_list[[i]]$x0)) stop("provided `segment_list[[", i, "]]$x0` is missing")
if (is.null(segment_list[[i]]$y0)) stop("provided `segment_list[[", i, "]]$y0` is missing")
if (is.null(segment_list[[i]]$x1)) stop("provided `segment_list[[", i, "]]$x1` is missing")
if (is.null(segment_list[[i]]$y1)) stop("provided `segment_list[[", i, "]]$y1` is missing")
}
}
}
} else {
segment_list <- NULL
}
if (any(dot_names == "text_list")) {
text_list <- dot_list$text_list
if (!is.null(text_list)) {
if (length(text_list) != length(z)) {
stop("provided text_list is of length ", length(text_list), " but nz = ", nz)
}
for (i in seq_along(text_list)) {
if (!is.na(text_list[i])) {
if (is.null(text_list[[i]]$x)) stop("provided `text_list[[", i, "]]$x` is missing")
if (is.null(text_list[[i]]$y)) stop("provided `text_list[[", i, "]]$y` is missing")
if (is.null(text_list[[i]]$labels)) stop("provided `text_list[[", i, "]]$labels` is missing")
if (is.null(text_list[[i]]$col)) text_list[[i]]$col <- "black"
}
}
}
} else {
text_list <- vector("list", length=nz)
}
cmd_list <- NULL # default
if (any(dot_names == "cmd_list")) {
cmd_list <- dot_list$cmd_list
if (!is.null(cmd_list)) {
for (vi in seq_along(cmd_list)) {
if (!is.na(cmd_list[vi])) {
for (i in seq_along(cmd_list[[vi]])) {
if (!is.na(cmd_list[[vi]][[i]])) {
if (typeof(cmd_list[[vi]][[i]]) != "character") {
stop("provided `cmd_list[[", vi, "]][[", i, "]]` = ", dput(cmd_list[[vi]][[i]]),
"\nmust be of type character")
}
}
}
}
}
}
}
if (any(dot_names == "subplot_list")) {
subplot_list <- dot_list$subplot_list
if (!is.null(subplot_list)) {
stop("todo")
}
} else {
subplot_list <- NULL
}
# get all function arguments
#all_args <- c(as.list(environment()), list(...)) # all arguments _defined by the function_
provided_args <- as.list(match.call(expand.dots=T)) # all _provided_ args by user with dot args having no name
#provided_args <- as.list(match.call(expand.dots=F)) # all _provided_ args by user with dot args having name "..."[[1]]
# checks
if (any(names(provided_args) == "contour_only")) { # if contour_only was provided by user
if (!is.logical(contour_only)) stop("provided `contour_only` must be T or F")
if (contour_only) { # user wants contour_only
if (any(names(provided_args) == "add_contour")) {
if (!is.logical(add_contour)) stop("privided `add_contour` must be T or F")
if (add_contour) { # user wants add_contour
message("user provided both `contour_only` and `add_contour` as true.",
" set `add_contour` to false and continue ...")
add_contour <- F
}
} else { # user did not provide add_contour
if (add_contour) { # default of function
message("user provided `contour_only` as true but `add_contour` is also true (default).",
" assume that the non-default user choice is more impportant and set ",
"`add_contour` to false and continue ...")
add_contour <- F
}
}
} else { # user does not want contour_only
# nothing to do
}
} else { # user did not provide contour_only
# here, contour_only=F (default)
}
# levels and colors
if (individual_zlim) {
if (!contour_only) {
message("if `individual_zlim`=T, `contour_only` must be T. set `contour_only` from F to T ...")
contour_only <- T
}
} else if (!individual_zlim) { # one zlim and breaks for all data
if (any(dot_names == "ip")) {
ip <- dot_list$ip
} else {
if (!any(dot_names == "zlim")) zlim <- range(z, na.rm=T)
message("`ip` argument not provided. try to run `image.plot.pre(zlim)` ...")
source("~/scripts/r/functions/image.plot.pre.r")
ip <- image.plot.pre(zlim)
}
zlim <- ip$zlim
cols <- ip$cols
breaks <- ip$levels
nlevels <- ip$nlevels
axis.at <- ip$axis.at
axis.at.ind <- ip$axis.at.ind
axis.labels <- ip$axis.labels
return_list$zlim <- zlim
return_list$breaks <- breaks
return_list$cols <- cols
return_list$nlevels <- nlevels
return_list$axis.at <- axis.at
return_list$axis.labels <- axis.labels
}
if (add_contour || contour_only) {
if (is.null(contour_cols)) contour_cols <- "black" # default
}
# set `useRaster`
# if a data matrix shall be plotted using graphics::image, the `useRaster` argument
# decides how the pixels are drawn and what kind of graphic file is returned:
# 1) useRaster=T --> raster graphic
# 2) useRaster=F --> vector graphic
# - if a raster graphic is wanted, it should be saved as png (or other raster formats) and
# useRaster should be true. the latter only works of the x and y coords of the data matrix
# are regular, decided via function `check_irregular()` below
# - if a vector graphic is wanted, it should be saved as pdf (or other vector formats) and
# useRaster should be false. however, objects drawn to a vector graphic with graphics::image
# can be very large, since every pixel is rendered as a single vector-object in the pdf viewer.
# this can yield a very large and unusable pdf file
# --> it can be useful to set useRaster explicitly to false, although a vector graphic is wanted.
# the resulting file is a vector graphic (e.g. axes, font, etc.) but all objects drawn with
# graphics::image are not.
check_irregular <- function(x, y) { # defined inside graphics::image.default
# problem: does not work for POSIX x,y objects
dx <- diff(x)
dy <- diff(y)
# all.equal(target, current, ...) returns
# TRUE if d <= tolereance with
# tolerance <- sqrt(.Machine$double.eps)
# d <- (sum(abs(target - current))/length(target))
# a character otherwise, giving the mean relative difference,
# e.g. "Mean relative difference: 0.2"; or other
# information like "Numeric: lengths (18, 1) differ"
# if the lengths of target and current differ
# isTRUE(x) returns
# TRUE if is.logical(x) && length(x) == 1L && !is.na(x) && x
(length(dx) && !isTRUE(all.equal(dx, rep(dx[1], length(dx))))) ||
(length(dy) && !isTRUE(all.equal(dy, rep(dy[1], length(dy)))))
} # check_irregular
is_pdf <- plot_type == "pdf" || # if pdf is wanted
(plot_type == "active" && (!is.null(dev.list()) && all(names(dev.cur()) == "pdf"))) # or current open device is pdf
if (is.null(useRaster)) {
useRaster <- T # default: faster plotting and better quality of graphics::image()-calls if raster graphic
if (is_pdf) useRaster <- F # graphics::image()-call yields vector graphic
} else {
if (!is.logical(useRaster)) stop("provided `useRaster` muse be logical")
if (is_pdf && useRaster) {
warning("a vector graphic is wanted (pdf) but `useRaster`=T --> graphics::image()-calls will not yield vector graphic.\n",
"do not provide the `useRaster` argument or set it to false if the graphics::image()-call shall return a vector object.")
}
}
# is useRaster=T, the x and y coords of the data matrix must be regular
# --> if provided x and y are not regular, make new regular x and y for the plot
if (useRaster) {
if (!contour_only) {
if (verbose) message("`useRaster`=T --> check if x,y are regular for graphics::image(..., useRaster=T) usage ...")
for (i in seq_along(z)) {
if (check_irregular(x[[i]], y[[i]])) {
if (verbose) message(" -> setting ", i, " is irregular -> make regular grid for setting ", i, " ...")
x[[i]] <- seq(min(x[[i]], na.rm=T), max(x[[i]], na.rm=T), length.out=length(x[[i]])) # overwrite original coord
y[[i]] <- seq(min(y[[i]], na.rm=T), max(y[[i]], na.rm=T), length.out=length(y[[i]]))
}
}
} # if !contour_only
if (!is.null(image_list)) {
if (verbose) message("`useRaster`=T --> check provided `image_list` if x,y are regular for graphics::image(..., useRaster=T) usage ...")
for (vi in seq_along(image_list)) {
if (!is.na(image_list[vi])) {
if (!is.na(image_list[[vi]][i])) {
for (i in seq_along(image_list[[vi]])) {
if (check_irregular(image_list[[vi]][[i]]$x, image_list[[vi]][[i]]$y)) {
image_list[[vi]][[i]]$x <- seq(min(image_list[[vi]][[i]]$x, na.rm=T),
max(image_list[[vi]][[i]]$x, na.rm=T),
l=length(image_list[[vi]][[i]]$x))
image_list[[vi]][[i]]$y <- seq(min(image_list[[vi]][[i]]$y, na.rm=T),
max(image_list[[vi]][[i]]$y, na.rm=T),
l=length(image_list[[vi]][[i]]$y))
}
}
}
}
}
} # if !is.null(image_list)
# todo: other matrix objects to check?
} # if useRaster
if (verbose) {
message("x:")
cat(capture.output(str(x)), sep="\n")
message("y:")
cat(capture.output(str(y)), sep="\n")
}
# unique x and y axes of same length for base::plot()
# (not projected)
xrange <- range(x, na.rm=T)
if (verbose) { cat("xrange = "); dput(xrange) }
yrange <- range(y, na.rm=T)
if (verbose) { cat("yrange = "); dput(yrange) }
l <- max(c(sapply(x, length), sapply(y, length)))
x_plot <- seq(xrange[1], xrange[2], length.out=l)
y_plot <- seq(yrange[1], yrange[2], length.out=l)
# project coords if wanted
if (F) { # test
proj <- "+proj=ortho +lat_0=30 +lon_0=-45" # orthographic
proj <- "+proj=stere +lat_0=90 +lat_ts=90"
message("test proj = \"", proj, "\" ...")
}
if (proj != "") {
# check if provided proj is valid
# oce::mapPlot() -> oce::lonlat2map() -> oce::oceProject() -> sf::sf_project()
xy <- expand.grid(lon=x_plot, lat=y_plot, KEEP.OUT.ATTRS=F)
capture.output({ # error-check from oce::oceProject()
xy_proj <- try(unname(oce::oceProject(xy=xy, proj=proj, debug=0)), silent=T)
})
if (inherits(xy_proj, "try-error")) {
warning("provided `proj` = \"", proj,
"\" not valid for sf::sf_project(). continue with `proj <- \"\"` ...")
proj <- ""
} else { # projection success
colnames(xy_proj) <- c("lon", "lat")
xy_proj <- as.data.frame(xy_proj)
# update xrange yrange to projected coords
xrange_proj <- range(xy_proj$lon, na.rm=T)
yrange_proj <- range(xy_proj$lat, na.rm=T)
if (verbose) {
cat("xrange_proj = "); dput(xrange_proj)
cat("yrange_proj = "); dput(yrange_proj)
}
}
} # if !is.null(proj)
# from here: `proj` is character "" (default rectangular plot) or != "" (some projection)
# apply zoom factor
if (!is.null(zoomfac)) {
if (verbose) message("apply `zoomfac` = ", zoomfac, " ...")
# from https://github.com/cbarbu/R-package-zoom
# find new xrange/yrange wrt zoomfac as in zoom:::multipancPoint()
xrange <- (1 - 1/zoomfac)*mean(xrange) + 1/zoomfac*xrange
yrange <- (1 - 1/zoomfac)*mean(yrange) + 1/zoomfac*yrange
if (verbose) {
message("--> new xrange = ", paste(xrange, collapse=", "), "\n",
"--> new yrange = ", paste(yrange, collapse=", "))
}
if (proj != "") {
xrange_proj <- (1 - 1/zoomfac)*mean(xrange_proj) + 1/zoomfac*xrange_proj
yrange_proj <- (1 - 1/zoomfac)*mean(yrange_proj) + 1/zoomfac*yrange_proj
if (verbose) {
message("--> new xrange_proj = ", paste(xrange_proj, collapse=", "), "\n",
"--> new yrange_proj = ", paste(yrange_proj, collapse=", "))
}
}
} # if zoomfac
# from here, xrange and yrange (and xrange_proj and yrange_proj if proj =! "") are finished
# update unique x and y axes for base::plot wrt zoomfac
# (not projected)
x_plot <- seq(xrange[1], xrange[2], length.out=l)
y_plot <- seq(yrange[1], yrange[2], length.out=l)
if (verbose) {
cat("x_plot = ")
cat(capture.output(str(x_plot)), sep="\n")
cat("y_plot = ")
cat(capture.output(str(y_plot)), sep="\n")
}
# apply user provided xlim ylim
xlim <- xrange # default
if (any(dot_names == "xlim")) {
xlim <- dot_list[["xlim"]]
if (verbose) { cat("provided xlim = "); dput(xlim) }
}
ylim <- yrange # default
if (any(dot_names == "ylim")) {
ylim <- dot_list[["ylim"]]
if (verbose) { cat("provided ylim = "); dput(ylim) }
}
if (F && proj != "") { # not needed for oce::mapPlot(); see below
xy_lim <- expand.grid(lon=xlim, lat=ylim, KEEP.OUT.ATTRS=F)
xy_lim_proj <- oce::oceProject(xy=xy_lim, proj=proj, debug=0)
colnames(xy_lim_proj) <- c("lon", "lat")
xy_lim_proj <- as.data.frame(xy_lim_proj)
xlim_proj <- range(xy_lim_proj$lon, na.rm=T)
ylim_proj <- range(xy_lim_proj$lat, na.rm=T)
if (verbose) {
cat("xlim_proj = "); dput(xlim_proj)
cat("ylim_proj = "); dput(ylim_proj)
}
}
# find tick values of unique x and y axes
# (not projected)
if (!any(dot_names == "x_at")) {
x_at <- pretty(x_plot, n=10)
if (verbose) { cat("automatic x_at step 1 = "); dput(x_at) }
x_at <- x_at[x_at >= min(x_plot) & x_at <= max(x_plot)]
if (verbose) { cat("automatic x_at step 2 = "); dput(x_at) }
} else if (any(dot_names == "x_at")) {
x_at <- dot_list[["x_at"]]
}
if (!any(dot_names == "y_at") ||
(any(dot_names == "y_at") && is.null(dot_list[["y_at"]]))) {
y_at <- pretty(y_plot, n=10)
if (verbose) { cat("automatic y_at step 1 = "); dput(y_at) }
y_at <- y_at[y_at >= min(y_plot) & y_at <= max(y_plot)]
if (verbose) { cat("automatic y_at step 2 = "); dput(y_at) }
} else if (any(dot_names == "y_at")) {
y_at <- dot_list[["y_at"]]
}
if (!any(dot_names == "x_labels")) {
x_labels <- format(x_at, trim=T)
if (verbose) { cat("automatic x_labels = "); dput(x_labels) }
} else if (any(dot_names == "x_labels")) {
x_labels <- dot_list[["x_labels"]]
}
if (!any(dot_names == "y_labels")) {
y_labels <- format(y_at, trim=T)
if (verbose) { cat("automatic y_labels = "); dput(y_labels) }
} else if (any(dot_names == "y_labels")) {
y_labels <- dot_list[["y_labels"]]
}
if (any(dot_names == "znames_labels")) {
znames_labels <- dot_list[["znames_labels"]]
} else { # if not provided: default: a) 1, b) 2, ...
znames_labels <- names(z)
if (is.null(znames_labels)) {
znames_labels <- rep("", times=n*m)
for (i in seq_len(n*m)) {
znames_labels <- paste0(letters[i], ") ", 1:(n*m))
}
}
}
## Open new or use already open plot device
if (verbose) message("plot_type = ", plot_type)
if (plot_type == "active") {
if (is.null(dev.list())) { # open new interactive device if none is open
dev.new(family=family)
} else { # use already open device
# nothing to do
}
} else if (plot_type == "png") {
stop("update")
if (n < m) {
width_png <- 2*width_png
}
png(plotname,
width=width_png, height=height_png, res=res, family=family)
} else if (plot_type == "pdf") {
stop("update")
if (m > n) {
stop("neeeed")
}
pdf(plotname,
width=width_pdf, height=height_pdf, family=family)
}
cur_dev_type <- names(dev.cur())
if (verbose) message("type of active device: ", cur_dev_type)
if (verbose) message("run layout() ...")
layout(layout_mat2, widths=layout_widths, heights=layout_heights)
#layout.show(n=max(layout_mat2))
par(mar=rep(0.5, times=4)) # distance between sub-figures [rows]
if (znames_method == "text" && is.character(znames_pos) && grepl("top", znames_pos)) { # increase vertical distance between sub figures
par(mar=c(0.5, 0.5, 1.66, 0.5))
}
if (verbose) {
cat("fig=")
dput(par("fig"))
cat("fin=")
dput(par("fin"))
cat("oma=")
dput(par("oma"))
cat("omi=")
dput(par("omi"))
cat("mar=")
dput(par("mar"))
cat("mai=")
dput(par("mai"))
cat("usr=")
dput(par("usr"))
cat("plt=")
dput(par("plt"))
cat("pty=")
dput(par("pty"))
}
# for every plot
for (i in seq_len(nplots)) {
if (verbose) message("\n**************************************\n",
"subplot ", i, "/", nplots, " (nz = ", nz, ") ...")
# Open i-th subplot device, also if there is nothing to draw
if (proj == "") { # default
# usage of helper-`x_plot` more flexible than just using combination of `xlim` and `x=0`
base::plot(x_plot, y_plot, type="n",
xlim=xlim, ylim=ylim,
axes=F, xlab=NA, ylab=NA,
xaxs="i", yaxs="i")
} else if (proj != "") {
if (F) { # test
proj <- "+proj=ortho +lat_0=30 +lon_0=-45 +R=3000000" # radius in m
proj <- "+proj=ortho +lat_0=30 +lon_0=-45 +a=6371000 +b=6371000 +units=m +no_defs"
proj <- "+proj=ortho +lat_0=30 +lon_0=-45 +a=3371000 +units=m +no_defs"
if (F) xy_proj <- expand.grid(lon=d$lon[[i]], lat=d$lat[[i]], KEEP.OUT.ATTRS=F)
if (F) {
xy_proj <- oce::lonlat2map(xy_proj$lon, xy_proj$lat, projection=proj, debug=1)
oceProj <- oce::oceProject(xy=xy_proj, proj=proj, debug=1)
} else { # check within oce::oceProject() in map.R:
longlatProj <- sf::st_crs("+proj=longlat")$proj4string
capture.output({
XY <- try(unname(sf::sf_project(longlatProj, proj,
xy_proj, keep = TRUE)), silent = TRUE)
})
}
} # test
# how the provided projection is checked:
oce::mapPlot(longitude=xy_proj$lon, latitude=xy_proj$lat,
projection=proj,
grid=F, type="n",
longitudelim=xlim, #c(-95, -5),
latitudelim=ylim, #c(20, 90),
#xlim=xlim_proj, #xrange_proj, # when xlim and/or ylim are provided,
#ylim=ylim_proj, #yrange_proj, # longitudelim and latitudelim will be ignored
axes=F, drawBox=F,
debug=1) # 0 1
} # if proj == "" or not
# it's possible that there are less data to plot than nrow*ncols (e.g. length(x) = 5, ncol=2, nrow=3)
# --> do not plot anything if (length(x) == nplots - 1 && i == nplots)
#if (length(x) == nplots - 1 && i == nplots) {
if (i > nz || (i <= nz && is.null(z[[i]]))) {
# nothing to do
if (verbose) {
#message("length(x) = ", length(x), " == nplots - 1 = ", nplots - 1,
# " && i == nplots = ", nplots, " --> nothing to draw")
if (i <= nz && is.null(z[[i]])) {
message("z[[", i, "]] is null --> nothind to draw")
} else {
message("i = ", i, " > nz = ", nz, " --> nothing to draw")
}
}
} else { # if length(x) != nplots - 1 && i != nplots --> add data to subplot
nx <- length(x[[i]]); ny <- length(y[[i]])
if (!contour_only) {
# add NA values
if (T && any(is.na(z[[i]]))) {
if (proj == "") {
if (F) { # old
if (verbose) message("`z[[", i, "]]` has missing values (NA) --> add missing values ",
"to subplot with color `NAcol`=", NAcol, " using graphics::image() with `useRaster`=",
useRaster, " ...")
graphics::image(x[[i]], y[[i]], array(1, c(nx, ny)),
add=T, col=NAcol,
axes=F, xlab="n", ylab="n",
useRaster=useRaster)
} else { # new
usr <- par("usr")
rect(usr[1], usr[3], usr[2], usr[4], col=NAcol, border=NA)
}
} # else if proj != "" --> NA are handled by `oce::mapImage(missingColor=NAcol, ...)`
} # if any NA
# add actual data
if (individual_zlim) {
stop("combination `contour_only`=F and `individual_zlim`=T not implemented yet")
}
if (proj == "") {
if (verbose) message("`contour_only`=F --> add data to subplot using graphics::image() with `useRaster`=",
useRaster, " ...")
graphics::image(x[[i]], y[[i]], z[[i]],
add=T, col=cols, breaks=breaks,
axes=F, xlab="n", ylab="n",
useRaster=useRaster)
} else if (proj != "") {
if (verbose) message("`contour_only`=F --> add data to subplot using oce::mapImage() ...")
oce::mapImage(x[[i]], y[[i]], z[[i]],
breaks=breaks, col=cols,
#filledContour=T, gridder="interp", # "binMean2D" "interp"
missingColor=NAcol,
debug=1) # 0 1
}
} # if !contour_only
# add contour to subplot
if (contour_only || add_contour) {
if (verbose) {
if (contour_only) message("`contour_only`", appendLF=F)
if (add_contour) message("`add_contour`", appendLF=F)
message("=T --> add data to subplot using graphics::contour() ...")