-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path04-customizations.Rmd
More file actions
1694 lines (1352 loc) · 60.1 KB
/
Copy path04-customizations.Rmd
File metadata and controls
1694 lines (1352 loc) · 60.1 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
# Deeper Customizations
```{r setup-04, include=FALSE}
knitr::opts_chunk$set(
# fig.retina = 2, out.width = '100%'
cache=TRUE,
fig.align="center",
fig.width=8,
fig.height=7
)
suppressPackageStartupMessages(library(venndir))
suppressPackageStartupMessages(library(patchwork))
```
While a Venn diagram may seem simple on the surface,
real-world datasets rarely cooperate.
At a certain point, those 'minor' details --
directionality, labeling, scaling, overlap type --
start to shape what the figure reveals, and what it obscures.
Every feature in Venndir has a story —
some short, some strangely epic —
that drove its creation.
## Venndir Borders
The underlying geometry of each polygon is represented as a
`JamPolygon` object (Ward 2025), a new S4 object designed for
geometries used in Venndir.
An important distinction from typical polygons in R is that
the objects are capable of describing three borders:
1. **'border'**: Line along the exact edge of the polygon.
2. **'innerborder'**: Line drawn on the inside edge.
3. **'outerborder'**: Line drawn on the outsideedge.
`JamPolygon` objects allow adjacent borders to co-exist without
rendering two borders on top of each other.
(ref:jp-borders) Four standard objects are displayed on the top row. The bottom row shows the effect of adding distinct borders: border, innerborder, outerborder, and all borders.
Figure \@ref(fig:jp-borders) illustrates four examples of borders,
showing the problem being addressed with innerborder. The left object
has two halves labeled A and B, with borders gold and purple, respectively.
When using 'border' the gold border is covered by the purple border down
the center line between A and B.
Instead, the next object with C and D shows the effect of using 'innerborder',
with the respective gold and purple borders both visible. Also notice the
object is not enlarged by adding the border, the line width extends *inside*
the polygon.
The next panel shows E and F, with 'outerborder' wrapping around them both.
The outerborder extends outside the object, and in fact the outerborder
does not extend inside the object at all.
The right panel shows G and H, and includes each type of border, drawn in
order: innerborder, outerborder, border. The 'border' was configured as
a thin line, otherwise it could potentially cover both the innerborder
and outerborder.
```{r jp-borders, echo=FALSE, fig.width=7, fig.height=4, fig.cap="(ref:jp-borders)", fig.alt="(ref:jp-borders)"}
make_semis <- function(
x=1,
y=2,
name="A",
radius=1,
fill=c("gold", "firebrick4"),
...)
{
#
if (length(name) == 1) {
name <- c(name, paste0("non_", name))
}
if (length(fill) == 1) {
fill <- jamba::color2gradient(fill, n=2)
}
fill[3] <- NA;
jp1full <- polygon_circles(x=x,
y=y,
setnames=name[2],
radius=radius,
...)
jpsq <- data.frame(
name=name[1],
x=I(list(
c(x - radius * 2, x, x, x - radius * 2))),
y=I(list(
c(y - radius * 2, y - radius * 2,
y + radius * 2, y + radius * 2)))
)
jpdf <- new("JamPolygon",
polygons=jpsq)
jp1 <- intersect_JamPolygon(rbind2(jpdf, jp1full))
jp2 <- minus_JamPolygon(rbind2(jp1full, jpdf))
jp12 <- rbind2(jp1, jp2)
jp12 <- rbind2(jp1, jp2, jp1full)
jp12@polygons$fill <- fill;
jp12@polygons$name[3] <- " ";
jp12@polygons$label_color <- jamba::setTextContrastColor(jp12@polygons$fill);
jp12;
}
r <- 1.25;
jp12 <- make_semis(x=1, radius=r, name=c("A", "B"), fill="firebrick")
jp34 <- make_semis(x=4, radius=r, name=c("C", "D"), fill="dodgerblue")
jp56 <- make_semis(x=7, radius=r, name=c("E", "F"), fill="aquamarine3")
jp78 <- make_semis(x=10, radius=r, name=c("G", "H"), fill="slateblue2")
jp <- do.call(rbind2, list(jp12, jp34, jp56, jp78));
k <- 7;
jp@polygons$border.lwd <- c(
# k*2, k*2, 1,
3, 3, 3,
# 1, 1, 1,
# 1, 1, 1,
# 1, 1, 1,
0, 0, 0,
0, 0, 0,
1, 1, 1)
jp@polygons$border <- c(
"gold", "purple", NA,
# "black", "black", "black",
"black", "black", "black",
"black", "black", "black",
"black", "black", "black")
jp@polygons$innerborder <- c(
NA, NA, NA,
"gold", "purple", NA,
NA, NA, NA,
"gold", "purple", NA)
jp@polygons$innerborder.lwd <- k
jp@polygons$outerborder=c(
NA, NA, NA,
NA, NA, NA,
NA, NA, "orange",
NA, NA, "orange")
jp@polygons$outerborder.lwd <- k
jp2 <- nudge_JamPolygon(jp, nudge=lapply(jamba::nameVectorN(jp), function(i){c(0, 3)}))
jp2@polygons$label <- jp2@polygons$name;
jp@polygons$label <- jp@polygons$name;
names(jp2) <- paste0(names(jp2), "_jp2")
jp2@polygons$border <- NA;
jp2@polygons$outerborder <- NA;
jp2@polygons$innerborder <- NA;
jb1 <- make_semis(x=1, y=0, radius=0.5)[3]
names(jb1) <- "blank1"
jb1@polygons$label <- "border"
jb1@polygons$label_color <- "black"
jb2 <- make_semis(x=4, y=0, radius=0.5)[3]
names(jb2) <- "blank2"
jb2@polygons$label <- "innerborder"
jb2@polygons$label_color <- "black"
jb3 <- make_semis(x=7, y=0, radius=0.5)[3]
names(jb3) <- "blank3"
jb3@polygons$label <- "outerborder"
jb3@polygons$label_color <- "black"
jb4 <- make_semis(x=10, y=0, radius=0.5)[3]
names(jb4) <- "blank4"
jb4@polygons$label <- "all borders"
jb4@polygons$label_color <- "black"
jp12 <- rbind2(jp, jp2, jb1, jb2, jb3, jb4)
jp12@polygons$fontsize <- 16;
p <- plot.JamPolygon(jp12,
xlim=c(-0.6, 11.6), ylim=c(-0.5, 6.25))
```
### Venndir Rendering Steps
Venndir draws borders in a specific order to provide a layering effect,
followed by other graphics elements such as labels and connecting
line segments.
1. **Venn Sets**
* The `outerborder` is drawn using `set_colors` darkened slightly.
* Other borders are not drawn: `fill` color, `border`, and `innerborder`.
2. **Venn Overlaps**
* Colors from the overlapping sets, from `set_colors`, are blended.
* The `fill` color is drawn after applying `poly_alpha`.
* The filled region does not include the `innerborder.lwd` if the
`innerborder` is defined.
* The `innerborder` is drawn using the `fill` color, darkened slightly,
and with no alpha transparency.
* Other borders are not drawn: `border` and `outerborder`.
3. **Count Labels**
* The font colors are adjusted for contrast, relative to the
background colors behind each label.
4. **Item Labels** (if enabled)
5. **Line Segments** (if enabled)
6. **Venndir Legend** (if enabled)
7. **Main Title** (if enabled)
The order that Venndir polygons are rendered, as described in (1) and (2)
above, is determined by the order of polygons present in the Venndir
`'jps'` S4 slot.
For example, if `v` is a `Venndir` object, the `JamPolygon` entries
are accessed using `v@jps`.
The order in `'jps'` can be modified, but all entries
are required for the `Venndir` object to be valid. For example,
[Highlight Venn Overlaps] re-orders `'jps'` to place the highlighted
overlap region last, thereby preventing `border` and `outerborder`
from being overdrawn by other entries in `'jps'`.
Additional `JamPolygon` entries may be added to `v@jps`, however
the new names must not conflict with existing `names(v@jps)`.
Additional notes:
* When plotting a `Venndir` object, the ellipses `'...'` can be used
to provide custom border settings, and are described in
[Customize Venndir borders].
* By default, `Venndir` objects do not use `border`, they use
`outerborder` for sets, and `innerborder` for overlap regions.
* The overlap regions use colors that are blended based upon `set_colors`
defined for the `Venndir` object.
* Default borders are quite subtle, but the effect is more distinctive
when using larger values for `innerborder.lwd` and `outerborder.lwd`.
* It is usually best to use the same `numeric` value for both
`innerborder.lwd` and `outerborder.lwd`, due to the way the borders
are layered.
### Customize Venndir borders
The border options can be customized directly when plotting
the Venndir object, adding named arguments to any function
that produces a Venndir plot:
* `venndir(...)`
* `render_venndir(Venndir, ...)`
* `plot(Venndir, ...)`
A few common alternatives are shown in Figure \@ref(fig:custom-borders).
(ref:custom-borders) Venndir diagrams demonstrating common border styles.
(ref:custom-borders-1) Venndir shown with no borders.
(ref:custom-borders-2) Venndir shown with thin grey border.
(ref:custom-borders-3) Venndir shown with white border.
(ref:custom-borders-4) Venndir with beveled effect.
```{r custom-borders, out.width="50%", fig.width=6, fig.height=5, fig.align="center", fig.ncol=2, fig.cap="(ref:custom-borders)", fig.alt="(ref:custom-borders)", fig.subcap=c("(ref:custom-borders-1)", "(ref:custom-borders-2)", "(ref:custom-borders-3)", "(ref:custom-borders-4)")}
v1 <- venndir(make_venn_test(),
innerborder=NA, outerborder=NA)
v2 <- venndir(make_venn_test(),
border="grey40", border.lwd=1,
innerborder=NA, outerborder=NA)
v3 <- venndir(make_venn_test(),
innerborder="white", innerborder.lwd=1,
outerborder="white")
v4 <- venndir(make_venn_test(),
label_style="lite box", innerborder.lwd=1,
outerborder="white", outerborder.lwd=2)
```
These options are useful for global changes to borders,
but are not ideal to modify a specific region. For those
customizations, see [Modify Venn Overlaps].
## Modify Venn Overlaps
Each overlap region in the Venndir object can be customized to some extent.
The `Venndir` object itself can be edited, but this process is tedious
and not intended to be user-friendly. Instead `modify_venndir_overlap()`
provides the most common modifications.
For a simple way to highlight a Venndir overlap, see
[Highlight Venn Overlaps]. This alternative offers a simple
variation of `modify_venndir_overlap()`.
As described in [Venndir Rendering Steps], **Sets** are drawn as open
circles, then each **Overlap** is drawn as a color-filled region.
**Labels** are then rendered last. Each overlap may have options
defined related to the region and the label.
For example `fill` is applied to the polygon background color,
however `label.fill` is applied to the corresponding label.
The full set of recognized parameters will be described later.
**Overlap** regions have specific names using the set or sets involved.
* `'set_A'` refers to the region unique to `'set_A'` with no other
overlapping sets.
* `'set_A&set_B'` refers to the region where the two sets `'set_A'` and
`'set_B'` overlap, with no other overlapping sets.
The overlap name is provided with argument `overlap_set`.
See the example \@ref(fig:modify-overlap-1)
(ref:modify-overlap-1) Venndir example showing a default Venn diagram, and a modified diagram (right) affecting the overlap region for `'set_A&set_B'`. Changes were made to the `fill` color, `innerborder`, `innerborder.lwd`, and `fontsize`.
```{r modify-overlap-1, fig.ncol=2, fig.height=6, fig.width=7, out.width="50%", fig.cap="(ref:modify-overlap-1)", fig.alt="(ref:modify-overlap-1)", fig.subcap=c("Default Venndir.", "Modified Venndir.")}
# default Venndir
v <- venndir(make_venn_test(do_signed=TRUE),
do_plot=FALSE)
plot(v,
main="Default Venndir")
# modified Venndir
v_mod <- modify_venndir_overlap(v,
overlap_set="set_A&set_B",
params=list(
fill="orange",
alpha=0.8,
fontsize=c(22, 16, 16),
innerborder="royalblue",
innerborder.lwd=5)
)
plot(v_mod,
main="Modified 'set_A&set_B'")
```
This customization is fairly common, and straightforward:
* `fill` color was changed to `'orange'`.
* `alpha` was defined 0.8, to be applied to `fill`.
* `innerborder` color was changed to `'royalblue'`.
* `innerborder.lwd` line width was set to 5.
* Label `fontsize` values were increased.
Note that `fontsize` is applied to each individual label in the
order it is drawn.
### Overlap Attributes
The recognized Venndir overlap attributes are shown in
Table \@ref(tab:overlap-attr-table).
(fig:overlap-attr-table) List of recognized region attributes, used to customize the Venndir figure.
```{r overlap-attr-table, echo=FALSE}
attr_list <- list(
"fill"=paste("R color used to fill the overlap region, after",
"also applying `alpha`.",
"The default is derived from the set_colors for the sets involved."),
"alpha"=paste("Numeric alpha transparency applied to the `fill` color,",
"where alpha=0 is fully transparent, and alpha=1 is opaque."),
"border"=paste("R color for the on-edge border. The on-edge border",
"is not recommended for most figures.",
"Use border=NA to draw no border, which is default."),
"border.lwd"=paste("The numeric line with for the `border` when defined."),
"innerborder"=paste("R color for the inner-boundary border, recommended",
"in most customizations.",
"When innerborder=NA, or innerborder.lwd=0 the innerborder is not drawn."),
"innerborder.lwd"=paste("The numeric line with for the `innerborder`.",
"When innerborder=NA, or innerborder.lwd=0 the innerborder is not drawn."),
"outerborder"=paste("R color for the outer-boundary border, not recommended",
"in most customizations.",
"When outerborder=NA, or outerborder.lwd=0 the outerborder is not drawn."),
"outerborder.lwd"=paste("The numeric line with for the `outerborder`.",
"When outerborder=NA, or outerborder.lwd=0 the outerborder is not drawn."),
"fontsize"=paste("Numeric font size in points for each overlap",
"label as defined in the Venndir object."),
"label.color"=paste("Text color for each overlap label",
"as defined in the Venndir object."),
"label.fill"=paste("Background label fill color with optional alpha transparency.",
"When label.fill=NA, no fill is applied.",
"The label.fill also affects the label.color,",
"using fill and label.fill together as relevant with",
"`make_color_contrast()` to ensure contrasting text."),
"label.border"=paste("Optional border color around the label group.",
"Use NA for no border."),
"label.count"=paste("Position or visibility for each count label",
"as defined the Venndir object.",
"Values are 'outside', 'inside', or 'none'."),
"label.overlap"=paste("Position and visibility for the set overlap label.",
"Currently only Set labels can be visible.",
"Values are 'outside', 'inside', or 'none'.")
)
attr_df <- data.frame(Attribute=names(attr_list),
Description=unlist(attr_list))
kdf <- knitr::kable(attr_df,
caption="List of recognized region attributes, used to customize the Venndir figure.",
row.names=FALSE)
kdf <- kdf |>
kableExtra::column_spec(2, width="27em") |>
kableExtra::group_rows(index=c(
"Region Attributes"=8,
"Label Attributes"=6))
kdf <- epub_kdf(kdf)
kdf
```
## Customize Any Label
Venndir labels are customized using `modify_venndir_overlap()` as
described in [Modify Venn Overlaps]. Some label adjustments are
best illustrated with specific examples.
The recognized attributes are described in [Overlap Attributes].
The overall font sizes used in a `Venndir` object are defined
with argument `font_cex` when first calling `venndir()`,
as described in [Font Sizes]. The font point sizes are stored
in the `Venndir` object, and may be modified.
The most common adjustments involve the font size, color, and optional
border and label fill.
The figures in Figure \@ref(fig:modify-label-1) show:
* the default Venndir
* customizations to one overlap count label
* moving this overlap label outside the figure.
(ref:modify-label-1) Venndir (left) and modified Venndir with customized label attributes (right), and how to move the label outside (bottom).
```{r modify-label-1, fig.height=6, fig.width=7, fig.ncol=2, out.width="50%", fig.cap="(ref:modify-label-1)", fig.alt="(ref:modify-label-1)", fig.subcap=c("Default Venndir.", "Modified overlap label.", "Overlap label outside.")}
# default Venndir
v <- venndir(make_venn_test(do_signed=TRUE),
main="Default Venndir")
# modified Venndir
v_mod <- modify_venndir_overlap(v,
overlap_set="set_A&set_C",
params=list(fill="royalblue",
alpha=1,
fontsize=c(20, 16, 12, 12, 12),
label.border="navy",
label.fill="royalblue3",
label.color=c("white", "pink", "skyblue"),
innerborder="royalblue4",
innerborder.lwd=5))
plot(v_mod, main="Modified 'set_A&set_C'")
# move the label outside
v_mod1 <- modify_venndir_overlap(v_mod,
overlap_set="set_A&set_C",
params=list(label.count="outside"))
plot(v_mod1,main="Outside 'set_A&set_C'")
```
A short list of techniques follows:
* To move the overlap count labels outside, set `label.count='outside'`.
* To move the overlap count labels inside, set `label.count='inside'`.
* To move an overlap Set label outside, set `label.overlap='outside'`.
* To move an overlap Set label inside, set `label.overlap='inside'`.
* To change label colors, define `label.color` for each label, in order.
## Automatic Text Contrast
In the previous section Figure \@ref(fig:modify-label-1),
the overlap fill defined by `'label.fill'` was set to blue.
Text colors were also manually changed using `label.color`
to improve visual contrast. This step may be automated
by using `make_color_contrast()`.
Given a set of input text colors in argument `x`, and
background colors in `y`, the function returns
a vector of colors to contrast with the background.
The purpose is to retain some color saturation, as opposed
to returning either white or black, while also
prioritizing visual clarity.
An optional argument `bg` can be used to define the canvas
background color, which is useful when the colors in `y`
have partial transparency, and would also partly show
the canvas color.
Two additional arguments to `make_color_contrast()` may be
relevant: `L_lo=40` and `L_hi=95`, which control the output color
darkness and lightness, respectively.
Adjustments may be passed through `venndir()` using `'...'` ellipses
to modify the color saturation, for example: `venndir(setlist, L_hi=85)`.
The argument `do_plot=TRUE` is used to visualize the input and
output colors for review.
```{r contrasting-color-1x, eval=FALSE}
x <- c("red3", "blue", "gold", "pink", "black");
xc1 <- make_color_contrast(x, y="royalblue3", do_plot=TRUE);
xc2 <- make_color_contrast(x, y="#FFF9EE", do_plot=TRUE);
```
(ref:contrasting-color-1) Two examples with blue background (top) and off-white background (bottom). In each plot, the top row labels indicate the input colors, the bottom row labels are the output colors adjusted to improve contrast.
```{r contrasting-color-1, echo=FALSE, fig.height=2.5, fig.width=7, out.width="60%", fig.ncol=1, fig.cap="(ref:contrasting-color-1)", fig.subcap=c("Blue background.", "Off-white background.")}
withr::with_par(list(mar=c(1, 1, 1, 1)), {
#
x <- c("red3", "blue", "gold", "pink", "black");
xc1 <- make_color_contrast(x, bg="royalblue3", do_plot=TRUE);
xc2 <- make_color_contrast(x, bg="#FFF9EE", do_plot=TRUE);
})
```
Putting these techniques together, the example in
Figure \@ref(fig:contrasting-color-2) uses
`modify_venndir_overlap()` together with `make_color_contrast()`
to ensure text labels have visual contrast.
(ref:contrasting-color-2) Venn diagram with modifications to the label for `'set_A&set_B'`.
```{r contrasting-color-2, fig.height=6, fig.width=7, fig.cap="(ref:contrasting-color-2)", fig.alt="(ref:contrasting-color-2)"}
v <- venndir(make_venn_test(do_signed=TRUE), do_plot=FALSE)
new_bg <- "darkgreen";
current_colors <- c("black", "firebrick", "dodgerblue3", "purple4");
v2 <- modify_venndir_overlap(v,
overlap_set="set_A&set_C",
params=list(
label.fill=new_bg,
label.border="black",
label.color=make_color_contrast(current_colors, new_bg),
label.count="outside",
innerborder=new_bg,
innerborder.lwd=3)
)
plot(v2)
```
The modifications made in this figure:
* `new_bg` was defined as `'darkgreen'`.
* `new_bg` was applied to the `label.fill` and the `innerborder`.
* `innerborder.lwd` was increased to `3`.
* `label.border` was changed to black, to contrast with dark green.
* `label.count` was set to `'outside'` to place count labels outside.
* `current_colors` were defined to match the existing label text colors.
* `label.color` was defined using `make_color_contrast()`, with arguments
`current_colors` and `new_bg`.
## Highlight Venn Overlaps
A convenient alternative to the previous section [Modify Venn Overlaps]
is to apply a highlight with `highlight_venndir_overlap()`.
This step applies a few options together.
The default settings:
* gold border
* yellow fill color
* red
* `fill` = 'yellow'
* `innerborder` = 'gold'
* `border` = 'red'
The example in \@ref(fig:highlight-label-1) shows the effect of
highlighting one overlap region, 'set_B&set_C'. The third panel
demonstrates how to move the count labels outside with a background
fill color. The line segment color is defined by `border` with
default 'red', however if 'label.border' is defined, that color
is slightly darkerned and used for the line segment as well.
(ref:highlight-label-1) Example Venn diagrams showing default (left), highlighted (right), and highlighted-labeled alternatives.
```{r highlight-label-1, fig.ncol=2, fig.height=6, fig.width=7, out.width="50%", fig.cap="(ref:highlight-label-1)", fig.alt="(ref:highlight-label-1)", fig.subcap=c("Default Venndir.", "Highlighted label.", "Highlighted label outside.")}
# default Venndir
v <- venndir(make_venn_test(do_signed=TRUE), do_plot=FALSE)
plot(v,
main="Default Venndir")
v_mod <- highlight_venndir_overlap(v,
border="red",
"set_B&set_C")
plot(v_mod,
main="Highlighted set_B&set_C")
v_mod2 <- modify_venndir_overlap(v_mod, "set_B&set_C",
params=list(label.count="outside",
label.fill="gold"))
plot(v_mod2,
main="Highlighted set_B&set_C outside")
```
The overlap region is named using each set involved, separated by
the ampersand '&', for example the overlap of 'set_B' and 'set_C'
is named 'set_B&set_C'. The overlap is provided with argument
`overlap_set`.
Other arguments are intended to provide convenient shortcuts for
commonly used attributes, with sensible default values:
* `'innerborder'` - the border shown on the inside edge of the
overlap region.
* `'innerborder.lwd'` - the width of the innerborder, with default `2`
to make this border much wider than the default.
* `outerborder'`, `'outerborder.lwd'` - the corresponding outerborder
displayed on the outside edge of the overlap region. By default the
outerborder line width is zero.
* `'border'`, `'border.lwd'` - the color and width of the border, placed
on the edge of the polygon itself. The default uses 'red' with line width 1.
The main effect is to apply this color and line width to the line
segment when the overlap label is outside.
* `reorder` - a `logical` value indicating whether to re-order the
`Venndir` polygons. The default is `TRUE`, which causes the highlighted
regions to be drawn last. This subtle change ensures that the
`outerborder` remains visible, and is not over-drawn by other polygon
regions in the `Venndir` object.
The argument `reorder` is a unique enhancement for
`highlight_venndir_overlap()`, and is the only convenient
method for re-ordering `Venndir` polygons.
## Rotate the Venndir
The Venndir figure can be rotated using degrees, on scale of
0 to 360, where 180 will rotate the figure exactly halfway.
Currently the rotation must occur when calling `venndir()`,
so that all polygons are rotated before the `Venndir` object
is created.
The default 3-way Venn diagram has 60-degree symmetry, so rotations
with multiples of 30 degrees tend to work best.
(ref:rotate-venndir) Several examples of rotated Venn and Euler diagrams.
```{r rotate-venndir, out.width="50%", fig.width=6, fig.height=5, fig.ncol=2, fig.cap="(ref:rotate-venndir)", fig.alt="(ref:rotate-venndir)", fig.subcap=c("Venn default.", "Venn rotated 60 degrees.", "Euler default.", "Euler rotated 90 degrees.")}
v1 <- venndir(make_venn_test(),
main="rotated 0{.sup o}",
rotate_degrees=0)
v2 <- venndir(make_venn_test(),
main="rotated 60{.sup o}",
rotate_degrees=60)
v3 <- venndir(make_venn_test(),
proportional=TRUE,
main="rotated 0{.sup o}",
rotate_degrees=0)
v4 <- venndir(make_venn_test(),
proportional=TRUE,
main="rotated 90{.sup o}",
rotate_degrees=90)
```
As indicated in the bottom-left panel (c), sometimes the legend
overlaps the placement of a set label. See [Nudge the Legend]
for alternatives.
## Nudge the Legend
The legend placement is defined by `legend_x` when calling `venndir()`,
`render_venndir()`, or `plot()`; or defined by `x` when calling
`venndir_legender()` separately. This argument takes `character` string
with combinations of `'top'`, `'bottom'`, `'left'`, and `'right'`.
Two words can be used, for example the default `legend_x="bottomright"`
places the legend in the bottom-right corner of the `grid` viewport.
The Venndir viewport is defined to be square, to maintain 1:1 aspect
ratio, and to make sure circles maintain their shape. As a result,
sometimes there is whitespace on the left/right sides, or top/bottom edges.
The legend is 'inset' from the exact outer edge using arguments
`x_inset` and `y_inset`, and these arguments can be passed through `'...'`
ellipses from `venndir()` to modify the legend. The default places
the legend `'2 lines'` inside the viewport border, using 2 character
lines of text as the unit. Any valid `grid::unit` can be provided,
however a good starting point is to adjust by units of `'lines'`.
(ref:nudge-legend) Two Euler diagrams showing default legend (left) and legend nudged 5 character lines (right).
```{r nudge-legend, out.width="50%", fig.ncol=2, fig.width=7, fig.height=5, fig.cap="(ref:nudge-legend)", fig.alt="(ref:nudge-legend)", fig.subcap=c("Default legend.", "Nudged legend.")}
v3a <- venndir(make_venn_test(),
proportional=TRUE)
v3b <- venndir(make_venn_test(),
x_inset=grid::unit(-5, "lines"),
proportional=TRUE)
```
## Hidden Overlaps
Euler diagrams may offer improvements to standard
Venn layout, by giving a visual indication of the relative area
within each set and the corresponding overlaps.
However, Euler diagrams are only *determinant* for two sets, exactly correct.
With more than two sets, a Euler diagram provides the best
*approximation* of the overlap sizes.
Some overlaps in a Euler diagram cannot be represented at all,
due to limitations of 2-dimensional geometry.
> `Venndir` objects retain all set overlaps, including those
which cannot be displayed in a Euler diagram.
Four strategies mitigate the limitations:
1. **Discover** hidden counts using `warnings(Venndir)`.
2. **Recover** hidden overlaps using `overlaplist(Venndir)`.
3. **Adjust** the Euler diagram, for example see [Nudge Venndir Circles].
4. **Optimize** Euler modeling options with `eulerr::eulerr_options()`.
Data from [Bisogno et al](doi:10.1126/sciadv.abc3851) help
demonstrate how to workaround the issue.
[Overlap counts] were imported to create a `setlist`.
```{r warnings-0}
overlaps <- c(A=187, B=146, C=499,
`A&B`=1,
`A&C`=181,
`B&C`=219,
`A&B&C`=20);
setlist <- counts2setlist(overlaps)
```
The resulting `setlist` is shown in Figure \@ref(fig:warnings-1) as a
Venn diagram (left), and Euler diagram (right).
It uses custom `set_colors` to match the published figure.
> An astute observer may notice that `1` is missing in the Euler diagram.
This may be a good time to point out that the Euler diagram can
also be rotated, see [Rotate the Venndir].
(ref:warnings-1) Venn diagram using test data from Bisogno et al, as Venn (left) and Euler (right) diagrams. Notice the footnote in the bottom-right corner of the Euler diagram.
```{r warnings-1, out.width="50%", fig.width=7, fig.height=5, fig.ncol=2, fig.cap="(ref:warnings-1)", fig.alt="(ref:warnings-1)", fig.subcap=c("Venn diagram.", "Euler diagram.")}
bisogno_colors <- c(A="firebrick2", B="dodgerblue", C="#BBBBBB")
v <- venndir(setlist,
set_colors=bisogno_colors)
ve <- venndir(setlist,
proportional=TRUE,
set_colors=bisogno_colors)
```
**Discover** hidden counts with `warnings(ve)`:
```{r warnings-1w}
warnings(ve)
```
The output means there is one overlap `'A&B'` with `1` item which is not
displayed.
**Recover** overlaps using `overlaplist(ve)`. The output `list` provides a
convenient way to summarize size of overlap by using `lengths()`,
shown below.
```{r warnings-1ol}
ol <- overlaplist(ve)
lengths(ol)
```
**Adjust** is shown in the next section [Nudge Venndir Circles],
which allows moving the Euler circles to create the geometry
for overlap labels.
**Optimize** is beyond scope of Venndir, and is discussed
in the R package [eulerr documentation](10.32614/CRAN.package.eulerr)
[@R-eulerr].
### Nudge Venndir Circles
The example in [Hidden Overlaps] Figure \@ref(fig:warnings-1)
illustrates a weakness in using proportional Euler diagrams,
while also showing a straightforward alternative.
The Venn or Euler circles used can be nudged, prior to being
used for visualization.
In the example, the overlap `'A&B'` is not represented in the
Euler diagram returned by `eulerr`, therefore the label `1`
cannot be displayed. Two possible solutions:
1. Move A and B closer to each other so they overlap outside C.
2. Move C higher so that A and B overlap outside C.
The argument `circle_nudge` should be passed to `venndir()` in order
for the geometry to be adjusted before the Venn overlap labels
are assigned to the corresponding overlap regions.
This argument should be a `list`, where each element is named
using the set name. Each element should be a `numeric` vector
with two values, the `x` and `y` coordinate adjustment.
The example in Figure \@ref(fig:nudge-circle-1) moves set `'A'`
to the right, and set `'B'` to the left.
(ref:nudge-circle-1) Venn diagram showing the default Euler (left) with footnote, and nudged circles (right) with no footnote indicated. The overlap for `'A&B'` now shows `1` count.
```{r nudge-circle-1, fig.ncol=2, fig.height=5, fig.width=6, out.width="50%", fig.cap="(ref:nudge-circle-1)", fig.alt="(ref:nudge-circle-1)", fig.subcap=c("Default Euler.", "Nudged A and B circles.")}
ve <- venndir(setlist,
proportional=TRUE,
set_colors=bisogno_colors)
vn <- venndir(setlist,
circle_nudge=list(A=c(1, 0), B=c(-1, 0)),
proportional=TRUE,
set_colors=bisogno_colors)
```
<!-- ### Automatically Move Labels Outside -->
## Nudge specific labels
Venndir automatically places labels which aims to cover the most common
85% scenarios. For all other cases, labels can be re-positioned using
`nudge_venndir_label()`.
* For each overlap, the label can be displayed 'inside' or 'outside'.
* The position defined for 'inside' or 'outside' can be adjusted with
`nudge_venndir_label()`.
As such, a label position is identified by two criteria:
1. **Overlap**: each set name, separated by ampersand `'&'`, for example
`'set_A&set_B'`
2. **Location**: 'inside' or 'outside' the Venn diagram.
The components of each label, and placement 'inside' or 'outside',
are stored in the `Venndir` object as described in [Venndir Labels].
Individual changes can be made by following [Customize Any Label].
Instead, `nudge_venndir_label()` adjusts the coordinate position
used when placing each label 'inside' or 'outside'.
(ref:nudge-labels-1) Venndir example with default label placement (left), and with `'set_A&set_C'` moved to the left (right).
```{r nudge-labels-1, fig.ncol=2, out.width="50%", fig.height=6, fig.width=6, fig.cap="(ref:nudge-labels-1)", fig.alt="(ref:nudge-labels-1)", fig.subcap=c("Default labels.", "One label moved left.")}
setlist <- make_venn_test(100, 3, do_signed=TRUE)
vo <- venndir(setlist,
overlap_type="each",
label_style="lite box",
main="Default venndir")
vo2 <- nudge_venndir_label(vo,
set="set_A&set_C",
label_location="inside",
x_offset=-0.04)
plot(vo2, main="'set_A&set_C' moved left")
```
The changes were defined by these arguments:
* The overlap: `set="set_A&set_C"`
* The location: `label_location="inside"`
* The x position: `x_offset=-0.04`, with default units
relative to the total size of the figure.
An alternative approach may be more convenient, using argument `offset_list`.
The argument is a `list`, named by overlap, containing a two-value
`numeric` vector with the x,y offset values. This style is
more convenient when adjusting multiple labels together.
Note that `label_location` is still required.
Figure \@ref(fig:nudge-labels-3) shows the effects after nudging
labels `'set_A&set_C'` and `'set_C'` in one step.
(ref:nudge-labels-3) Venndir after moving labels `'set_A&set_C'` and `'set_C'` using `offset_list`.
```{r nudge-labels-3, fig.height=7, fig.width=9, fig.cap="(ref:nudge-labels-3)", fig.alt="(ref:nudge-labels-3)"}
vo3 <- nudge_venndir_label(vo,
label_location="inside",
offset_list=list(
"set_A&set_C"=c(-0.04, -0.02),
"set_C"=c(0, 0.05)
))
plot(vo3, main="Two labels moved")
```
## Venndir Markdown Support
By virtue of using **marquee** [@R-marquee], several labels in
Venndir can be customized using [markdown](#g-markdown) syntax,
specifically following [CommonMark](https://commonmark.org/help/).
The main features are:
* support for font styles (**bold**, *italic*, _underline_)
* forced new-lines by ending a line with two spaces, or adding `'\n'`
* inline **marquee** styles
* inline images
* inline R graphics objects
Other styles are recognized by **marquee**, such as `{.super }` and
`{.sub }`.
For example, using `venn_meme()`:
(ref:markdown-1) Venn Meme showing markdown formatted items (left), and inline styles (right).
```{r markdown-1, out.width="50%", fig.ncol=2, fig.height=7, fig.width=8, fig.cap="(ref:markdown-1)", fig.alt="(ref:markdown-1)", fig.subcap=c("Markdown.", "Inline style.")}
venndir::venn_meme(c(
"*italics*",
"_under_-\n_line_",
"in\n**bold**"))
venndir::venn_meme(jitter_color=0, jitter_cex=0,
c(
"This\nis{.sup super}",
"\n`This`\n`is`\n`code`",
"This\nis {.sub sub}"))
```
### Inline styles
The **marquee* R package supports inline styles, using this
syntax `'{.style text}'`, where 'style' is the name of a
pre-defined style from `marquee::style()`, and 'text'
is any valid text or markdown text, or even other inline styles.
Venndir defines `marquee::classic_style()` for use by any labels,
which supports a large number of the most common HTML-like styles,
including:
`r jamba::cPaste(sep=", ", names(marquee::classic_style()[[1]]))`
Argument `'marquee_styles'` for `venndir()` accepts an optional `list`
with additional styles, which are added to the set of recognized styles.
The marquee style specification includes *very many* customizations:
font family, weight, width, size, color, lineheight, background, border,
padding, and many more. Any detailed customization not already provided
in Venndir should be attempted by creating a new marquee style, then
applying it as an inline style.
Creating a new style is straightforward, shown below.
Each style inherits attributes of the existing style.
For example, it continues using the same font family, size, and color
until any attribute is modified. The examples below change the
font family, force it to have normal weight/width (not bold), and
enlarge by 1.5 relative to the existing font size.
```{r inline-style-0}
ms <- list(
chalk=marquee::style(
family="Chalkduster",
weight="normal", width="normal",
size=marquee::relative(1.5)),
cursive=marquee::style(
family="Above The Sky",
weight="normal", width="normal",
size=marquee::relative(1.5)),
gothic=marquee::style(
family="AcademyEngravedLetPlain",
weight="normal", width="normal",
size=marquee::relative(1.5)))
```
(ref:inline-style-1) Example using inline styles to customize every conceivable field in Venndir: set name, main title, item labels, legend setlist, legend headers, legend count font.
```{r inline-style-1, fig.height=7, fig.width=8, fig.cap="(ref:inline-style-1)", fig.alt="(ref:inline-style-1)"}
# create labels
il <- split(LETTERS, rep(letters[1:3], c(10, 10, 6)))
names(il) <- c("{.chalk A-J}",
"{.gothic K-T}", "{.cursive U-Z}")
# apply inline markup around each set of labels
il[[1]] <- paste0("{.chalk ", il[[1]], "}")
il[[2]] <- paste0("{.gothic ", il[[2]], "}")
il[[3]] <- paste0("{.cursive ", il[[3]], "}")
# draw the rest of the owl
vm <- venn_meme(il, item_buffer=-0.05, marquee_styles=ms,
expand_fraction=0.02,
fontfamily="Chalkduster",
show_labels="Ni", draw_legend=TRUE,
legend_headers=c(Set="{.cursive Sets}", Size="{.chalk Sizes}"),
main="{.chalk Custom} {.gothic Text} {.cursive Styles}")
```
Inline styles could be useful for other common operations:
* Slightly larger or smaller font size.
* Custom font family.
* Left- or right-aligned text.
* Custom font color.
* Color fill background, border, border radius.
### Inline Images
Inline images can be added using markdown syntax, which looks like this:
```

```
The `path/to/image` can be the path to a local file, a web URL address,
for example:
```

```
Further, inline R graphics can be added, in this form,
where `Robject` is the name of an R graphical object,
such as a `ggplot2` or `grid` object.
```

```