Fully Customed Venn Diagram

library(ggVennDiagram)

Comprehensive customization by using helper functions

The main function ggVennDiagram() accepts a list input, and output a ggplot object. By measuring the length of input list, it automatically applies internal functions to build a plot in two steps: data preparation and visualization.

Data preparation was packaged into one function process_data(). Its output is a S4 VennPlotData class object, which contains three slots, setEdge, setLabel and region. These slot data then can be further plotted with ggplot functions.

See below for a better understanding.

Generate example data.

genes <- paste0("gene",1:1000)
set.seed(20210302)
gene_list <- list(A = sample(genes,100),
                  B = sample(genes,200),
                  C = sample(genes,300),
                  D = sample(genes,200))

library(ggVennDiagram)
library(ggplot2)

Then we can reproduce the plot of ggVennDiagram() with several lines.

venn <- Venn(gene_list)
data <- process_data(venn)
ggplot() +
  # 1. region count layer
  geom_sf(aes(fill = count), data = venn_region(data)) +
  # 2. set edge layer
  geom_sf(aes(color = id), data = venn_setedge(data), show.legend = FALSE) +
  # 3. set label layer
  geom_sf_text(aes(label = name), data = venn_setlabel(data)) +
  # 4. region label layer
  geom_sf_label(aes(label = count), data = venn_region(data)) +
  theme_void()

The variable data is a S4 class object that has three slots.

data
#> An object of class "VennPlotData"
#> Slot "setEdge":
#> Simple feature collection with 4 features and 5 fields
#> Geometry type: LINESTRING
#> Dimension:     XY
#> Bounding box:  xmin: 0.0649949 ymin: 0.1849949 xmax: 0.9350051 ymax: 0.8391534
#> CRS:           NA
#> # A tibble: 4 x 6
#>   id                                      geometry component item    count name 
#>   <chr>                               <LINESTRING> <chr>     <named> <int> <chr>
#> 1 1     (0.1025126 0.7174874, 0.09412107 0.708119~ setEdge   <chr [~   100 A    
#> 2 2     (0.2525126 0.8174874, 0.246341 0.8103391,~ setEdge   <chr [~   200 B    
#> 3 3     (0.7333452 0.8033452, 0.7262248 0.8095447~ setEdge   <chr [~   300 C    
#> 4 4     (0.8974874 0.7174874, 0.8881191 0.7258789~ setEdge   <chr [~   200 D    
#> 
#> Slot "setLabel":
#> Simple feature collection with 4 features and 3 fields
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: 0.08 ymin: 0.78 xmax: 0.93 ymax: 0.86
#> CRS:           NA
#> # A tibble: 4 x 4
#>   id       geometry component name 
#>   <chr>     <POINT> <chr>     <chr>
#> 1 1     (0.08 0.78) setLabel  A    
#> 2 2     (0.26 0.86) setLabel  B    
#> 3 3     (0.71 0.85) setLabel  C    
#> 4 4     (0.93 0.78) setLabel  D    
#> 
#> Slot "region":
#> Simple feature collection with 15 features and 5 fields
#> Geometry type: POLYGON
#> Dimension:     XY
#> Bounding box:  xmin: 0.0649949 ymin: 0.1849949 xmax: 0.9350051 ymax: 0.8391534
#> CRS:           NA
#> # A tibble: 15 x 6
#>    id                                    geometry component item    count name  
#>    <chr>                                <POLYGON> <chr>     <list>  <int> <chr> 
#>  1 1     ((0.0649949 0.6187446, 0.06585244 0.633~ region    <chr [~    43 A     
#>  2 2     ((0.4872824 0.7545178, 0.4712329 0.7429~ region    <chr [~    99 B     
#>  3 3     ((0.5033822 0.765325, 0.5194686 0.77536~ region    <chr [~   174 C     
#>  4 4     ((0.5 0.1850668, 0.513719 0.1858524, 0.~ region    <chr [~   107 D     
#>  5 12    ((0.2986536 0.5794036, 0.2878257 0.5962~ region    <chr [~    10 A..B  
#>  6 13    ((0.3598131 0.3161471, 0.3466157 0.3144~ region    <chr [~    22 A..C  
#>  7 14    ((0.4719527 0.1878314, 0.4583271 0.1909~ region    <chr [~    12 A..D  
#>  8 23    ((0.5919781 0.6809775, 0.5745693 0.6685~ region    <chr [~    48 B..C  
#>  9 24    ((0.6350051 0.3212554, 0.6347379 0.3368~ region    <chr [~    25 B..D  
#> 10 34    ((0.6897239 0.5775115, 0.6773526 0.5943~ region    <chr [~    41 C..D  
#> 11 123   ((0.393934 0.463934, 0.3786034 0.479683~ region    <chr [~     5 A..B.~
#> 12 124   ((0.6020164 0.4567956, 0.6098817 0.4389~ region    <chr [~     5 A..B.~
#> 13 134   ((0.4966178 0.374675, 0.4805314 0.36463~ region    <chr [~     2 A..C.~
#> 14 234   ((0.5931564 0.4747005, 0.5833369 0.4925~ region    <chr [~     7 B..C.~
#> 15 1234  ((0.4068436 0.4747005, 0.4166631 0.4925~ region    <chr [~     1 A..B.~

ggVennDiagram export functions to get these data, and they can be used for comprehensive customization in user-side.

For example, you may change edge/fill/label properties as you will.

ggplot() +
  # change mapping of color filling
  geom_sf(aes(fill = id), data = venn_region(data), show.legend = FALSE) +  
  # adjust edge size and color
  geom_sf(color="grey", size = 3, data = venn_setedge(data), show.legend = FALSE) +  
  # show set label in bold
  geom_sf_text(aes(label = name), fontface = "bold", data = venn_setlabel(data)) +  
  # add a alternative region name
  geom_sf_label(aes(label = name), data = venn_region(data), alpha = 0.5) +  
  theme_void()

Stepwise plotly

This is for issue #26.

venn <- Venn(gene_list)
data <- process_data(venn)
items <- venn_region(data) %>%
  dplyr::rowwise() %>%
  dplyr::mutate(text = stringr::str_wrap(paste0(.data$item, collapse = " "),
                                         width = 40)) %>%
  sf::st_as_sf()
label_coord = sf::st_centroid(items$geometry) %>% sf::st_coordinates()
p <- ggplot(items) +
  geom_sf(aes_string(fill="count")) +
  geom_sf_text(aes_string(label = "name"),
               data = data@setLabel,
               inherit.aes = F) +
  geom_text(aes_string(label = "count", text = "text"),
            x = label_coord[,1],
            y = label_coord[,2],
            show.legend = FALSE) +
  theme_void() +
  scale_fill_distiller(palette = "RdBu")
#> Warning: Ignoring unknown aesthetics: text
ax <- list(
  showline = FALSE
)
plotly::ggplotly(p, tooltip = c("text")) %>%
  plotly::layout(xaxis = ax, yaxis = ax)

Note: Please be aware that due to the poor compatibility between plotly and ggplot, this feature is only experimental.