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 × 6
#>   id                                          geometry compo…¹ item  count name 
#>   <chr>                                   <LINESTRING> <chr>   <nam> <int> <chr>
#> 1 1     (0.1025126 0.7174874, 0.09412107 0.7081191, 0… setEdge <chr>   100 A    
#> 2 2     (0.2525126 0.8174874, 0.246341 0.8103391, 0.2… setEdge <chr>   200 B    
#> 3 3     (0.7333452 0.8033452, 0.7262248 0.8095447, 0.… setEdge <chr>   300 C    
#> 4 4     (0.8974874 0.7174874, 0.8881191 0.7258789, 0.… setEdge <chr>   200 D    
#> # … with abbreviated variable name ¹​component
#> 
#> 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 × 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 × 6
#>    id                                         geometry compo…¹ item  count name 
#>    <chr>                                     <POLYGON> <chr>   <lis> <int> <chr>
#>  1 1     ((0.1025126 0.7174874, 0.1118809 0.7258789, … region  <chr>    43 A    
#>  2 2     ((0.2525126 0.8174874, 0.2596609 0.823659, 0… region  <chr>    99 B    
#>  3 3     ((0.7333452 0.8033452, 0.7395447 0.7962248, … region  <chr>   174 C    
#>  4 4     ((0.8974874 0.7174874, 0.9058789 0.7081191, … region  <chr>   107 D    
#>  5 12    ((0.2494531 0.7508377, 0.266399 0.7472201, 0… region  <chr>    10 A..B 
#>  6 13    ((0.3598131 0.3161471, 0.3466157 0.3144203, … region  <chr>    22 A..C 
#>  7 14    ((0.6341476 0.306281, 0.6321686 0.2919527, 0… region  <chr>    12 A..D 
#>  8 23    ((0.4087951 0.6905086, 0.4240163 0.7044756, … region  <chr>    48 B..C 
#>  9 24    ((0.7013464 0.5605964, 0.7121743 0.5437184, … region  <chr>    25 B..D 
#> 10 34    ((0.7562978 0.7359764, 0.7555797 0.7233843, … region  <chr>    41 C..D 
#> 11 123   ((0.4254307 0.668526, 0.4425419 0.6552909, 0… region  <chr>     5 A..B…
#> 12 124   ((0.6020164 0.4567956, 0.6098817 0.4389429, … region  <chr>     5 A..B…
#> 13 134   ((0.4966178 0.374675, 0.4805314 0.3646387, 0… region  <chr>     2 A..C…
#> 14 234   ((0.5085786 0.6114214, 0.5243976 0.6266822, … region  <chr>     7 B..C…
#> 15 1234  ((0.5066822 0.5956024, 0.5213246 0.5792878, … region  <chr>     1 A..B…
#> # … with abbreviated variable name ¹​component

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 = yulab.utils::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.