Reputation: 55
I have the following code:
import matplotlib.pyplot as plt
from matplotlib_venn import venn3
# Convert the 'Gene_Name' columns to sets for comparison
genes_5min_Down = set(Host_5min_Down_gene['Gene_Name'])
genes_10min_Down = set(Host_10min_Down_gene['Gene_Name'])
genes_no_phage_Down = set(No_phage_Down_gene['Gene_Name'])
# Create a Venn diagram
venn = venn3([genes_5min_Down, genes_10min_Down, genes_no_phage_Down],
set_labels=('Host 5min infection', 'Host 10min infection', 'No Phage infection'))
# Customize the labels to show counts
# Get the sizes for each section
only_5min_Down = len(genes_5min_Down - genes_10min_Down - genes_no_phage_Down)
only_10min_Down = len(genes_10min_Down - genes_5min_Down - genes_no_phage_Down)
only_no_phage_Down = len(genes_no_phage_Down - genes_5min_Down - genes_10min_Down)
common_5min_10min_Down = len(genes_5min_Down & genes_10min_Down - genes_no_phage_Down)
common_5min_no_phage_Down = len(genes_5min_Down & genes_no_phage_Down - genes_10min_Down)
common_10min_no_phage_Down = len(genes_10min_Down & genes_no_phage_Down - genes_5min_Down)
common_all_Down = len(genes_5min_Down & genes_10min_Down & genes_no_phage_Down)
# Set the counts for each section
venn.get_label_by_id('100').set_text(only_5min_Down) # Only in 5min
venn.get_label_by_id('010').set_text(only_10min_Down) # Only in 10min
venn.get_label_by_id('001').set_text(only_no_phage_Down) # Only in No Phage
venn.get_label_by_id('110').set_text(common_5min_10min_Down) # Common in 5min and 10min
#venn.get_label_by_id('101').set_text(common_5min_no_phage_Down) # Common in 5min and No Phage
#venn.get_label_by_id('011').set_text(common_10min_no_phage_Down) # Common in 10min and No Phage
#venn.get_label_by_id('111').set_text(common_all_Down) # Common in all three
# Set colors for each circle
colors = ('#ADD8E6', '#FFFFE0', '#FFB6C1') # You can specify your desired colors here
for idx, color in zip(('100', '010', '001'), colors):
patch = venn.get_patch_by_id(idx)
patch.set_color(color)
patch.set_alpha(0.5) # Set transparency for blending
patch.set_edgecolor('black') # Set edge color to black
patch.set_linewidth(2) # Set edge line width
# Display the plot
plt.title("Common Genes Down Between Host 5min and 10min infection and no phage infection")
plt.show()
This is the plot that I get.
I can't for the life of me figure out how to get the overlapping circle to blend to the correct color. Yellow and blue should blend to green and not brown.
How can I achieve this or what am I doing wrong?
Upvotes: 0
Views: 93
Reputation: 11440
matplotlib_venn
artificially lightens the colors during mixing, as that so far seems to have produced slightly better results than mixing directly (and over its 10+ years of existence this has not been reported as a problem nor was there ever a request for a customizable color mixing routine).
If you want to have the subregion colors be the additive mixtures of their consistuents, you can compute them manually as follows, for example:
import numpy as np
from matplotlib.colors import ColorConverter
def set_circle_colors_with_additive_mixing(venn_diagram, set_colors):
ccv = ColorConverter()
set_colors = [np.array(ccv.to_rgb(c)) for c in set_colors]
for a in [0, 1]:
for b in [0, 1]:
for c in [0, 1]:
mixed = np.zeros(3)
if a: mixed += set_colors[0]
if b: mixed += set_colors[1]
if c: mixed += set_colors[2]
if a+b+c:
mixed /= (a+b+c)
patch = venn_diagram.get_patch_by_id(f"{a}{b}{c}")
if patch:
patch.set_color(mixed)
# Usage
from matplotlib_venn import venn3
diagram = venn3((8, 25, 9, 3, 0, 0, 0),
set_labels=('Host 5min infection', 'Host 10min infection', 'No Phage infection'),
alpha=1.0)
set_circle_colors_with_additive_mixing(diagram, ('#ADD8E6', '#FFFFE0', '#FFB6C1'))
You'll get this:
Upvotes: 0
Reputation: 13041
The method venn3.get_patch_by_id
retrieves patches that correspond to subsets, not sets. Your code isn't amending the subset patch with the brown color (subset "110" in your code).
That being said, I also can't get the color blending to work in matplotlib-venn, so it may be worth raising an issue on their github.
import matplotlib.pyplot as plt
from matplotlib_venn import venn3
set_labels = [
"No phage infection",
"After 5 min infection",
"After 10 min infection"
]
set_colors = ["#FFB6C1", "#ADD8E6", "#FFFFE0"]
subset_sizes = {
"100" : 3,
"110" : 0,
"111" : 0,
"010" : 8,
"011" : 9,
"001" : 25,
}
fig1, ax1 = plt.subplots()
venn_diagram = venn3(subset_sizes, set_labels=set_labels, set_colors=set_colors, ax=ax1)
for patch in venn_diagram.patches:
if patch:
patch.set_edgecolor("black")
patch.set_linewidth(2)
plt.show()
In the meantime, you may be interested in my matplotlib_set_diagrams library, which was inspired by matplotlib-venn but implements a better layout engine and (apparently) also improves on the color blending.
import matplotlib.pyplot as plt
from matplotlib_set_diagrams import EulerDiagram # pip install matplotlib_set_diagrams
set_labels = [
"No phage infection",
"After 5 min infection",
"After 10 min infection"
]
set_colors = ["#FFB6C1", "#ADD8E6", "#FFFFE0"]
# matplotlib_set_diagrams uses a slightly different format that generalizes better to arbitrary numbers of sets.
subset_sizes = {
(1, 0, 0) : 3,
(1, 1, 0) : 0,
(1, 1, 1) : 0,
(0, 1, 0) : 8,
(0, 1, 1) : 9,
(0, 0, 1) : 25,
}
fig2, ax2 = plt.subplots()
# (area-proportional set diagrams are actually called Euler diagrams)
euler_diagram = EulerDiagram(subset_sizes, set_labels=set_labels, set_colors=set_colors, ax=ax2)
for artist in euler_diagram.subset_artists.values():
artist.set_edgecolor("black")
artist.set_linewidth(2)
plt.show()
Upvotes: 1
Reputation: 1
patch.set_alpha(0.5)
Could you please change it to 1 and try it? Transparency will lead to brown.
Upvotes: 0