matplotlib_venn绘制韦恩图时补集着色异常问题求助
韦恩图补集着色问题解决方案
问题描述
使用matplotlib_venn库绘制韦恩图时,计算集合补集或相关表达式出现着色异常,无法让未着色部分保持纯白色。例如输入表达式x-complement(表示集合A的补集)时,韦恩图的着色不符合预期。
原代码
import matplotlib.pyplot as plt from itertools import product from matplotlib_venn import venn3, venn3_circles #Initialize universal_set = set() empty_set = set() complement = set() expression = "" setA = set() setB = set() setC = set() def evaluate_expression(formula, empty_set): for x in product([False, True], repeat=3): x_dict = dict(zip('xyz', x)) x_dict['universal_set'] = universal_set x_dict['empty_set'] = empty_set x_dict['complement'] = complement if 'empty_set' in formula: formula = formula.replace('empty_set', 'False') if 'universal_set' in formula: formula = formula.replace('universal_set', 'True') if 'complement' in formula: formula = formula.replace('complement', 'True') if eval(formula, {}, x_dict): yield ''.join(str(int(x_i)) for x_i in x) def plot_diagram(formula, empty_set): plt.figure(figsize=(6, 6)) v = venn3(subsets=[1] * 7, set_colors=['white'] * 3, subset_label_formatter=lambda x: '') for region in evaluate_expression(formula, empty_set): if region != '000': v.get_patch_by_id(region).set_color('#FFC0CB') else: ax= plt.axes() ax.figure.set_facecolor('#FFC0CB') # Add labels for setA, setB, and setC v.get_label_by_id('100').set_text(', '.join(map(str, setA - setB - setC))) v.get_label_by_id('010').set_text(', '.join(map(str, setB - setA - setC))) v.get_label_by_id('001').set_text(', '.join(map(str, setC - setB - setA))) # Add labels for intersections v.get_label_by_id('101').set_text(', '.join(map(str, setA & setC - setB))) v.get_label_by_id('110').set_text(', '.join(map(str, setA & setB - setC))) v.get_label_by_id('011').set_text(', '.join(map(str, setB & setC - setA))) v.get_label_by_id('111').set_text(', '.join(map(str, setB & setC & setA))) venn3_circles(subsets=[1] * 7, linestyle='solid') #Create menu def menu(): print("#1 Enter a number to Set A") print("#2 Enter a number to Set B") print("#3 Enter a number to Set C") print("#4 Evaluate Expression") print("#5 Display the Venn Diagram") print("#6 Exit") #Execute depending on user's choice while True: menu () choice= input("Enter your number of choice: ") if choice == '1': try: setA.update(map(int, input("Enter a number to set A (separate using space): ").split())) except ValueError: print("Error. Input must be an integer") elif choice == '2': try: setB.update(map(int, input("Enter a number to set B (separate using space): ").split())) except ValueError: print("Error. Input must be an integer ") elif choice == '3': try: setC.update(map(int, input("Enter a number to set C (separate using space): ").split())) except ValueError: print("Error. Input must be an integer") elif choice == '4': print("x for set A, y for set B, z for set C") print("| for union, & for intersection, -complement for complement, universal_set for universal set, empty_set for empty set") expression = input("Evaluate Expression: ") elif choice == '5': if expression: try: plot_diagram(expression, empty_set) plt.show() except Exception as e: print("Invalid formula. Error:", str(e)) else: print("Please evaluate an expression first.") elif choice =='6': print("Exiting the program.") break else: print("Invalid input")
问题根源
- 补集表达式解析错误:原代码将
complement直接替换为True,无法正确解析x-complement这类表示“x的补集”的逻辑,导致生成的区域ID错误。 - 未显式重置所有区域颜色:仅设置
set_colors=['white']*3不足以确保所有子集区域为纯白,部分区域可能保留默认透明度或底色。 - 背景色处理逻辑冲突:处理
000区域时直接修改整个figure背景,但未确保其他非目标区域保持白色。
解决方案
关键修改点
- 修正补集表达式解析:将
x-complement这类语法转换为not x,正确计算补集逻辑。 - 初始化为纯白底色:在着色前,将所有韦恩图区域显式设置为白色,并关闭透明度。
- 正确处理背景色:仅当
000区域属于目标集合时,才修改背景色,否则保持背景纯白。
修改后的完整代码
import matplotlib.pyplot as plt from itertools import product from matplotlib_venn import venn3, venn3_circles # Initialize universal_set = set() empty_set = set() expression = "" setA = set() setB = set() setC = set() def evaluate_expression(formula): # 处理补集语法:将 x-complement 转换为 not x formula = formula.replace('x-complement', 'not x') formula = formula.replace('y-complement', 'not y') formula = formula.replace('z-complement', 'not z') # 替换全集和空集 formula = formula.replace('universal_set', 'True') formula = formula.replace('empty_set', 'False') for x in product([False, True], repeat=3): x_dict = dict(zip('xyz', x)) if eval(formula, {}, x_dict): yield ''.join(str(int(x_i)) for x_i in x) def plot_diagram(formula): plt.figure(figsize=(6, 6), facecolor='white') # 确保figure背景默认纯白 v = venn3(subsets=[1] * 7, subset_label_formatter=lambda x: '') # 先将所有区域设置为纯白色,关闭透明度 for region_id in ['100', '010', '001', '110', '101', '011', '111']: patch = v.get_patch_by_id(region_id) if patch: patch.set_color('white') patch.set_alpha(1.0) # 关闭透明度,避免透显底层颜色 target_regions = list(evaluate_expression(formula)) # 对目标区域着色 for region in target_regions: if region != '000': patch = v.get_patch_by_id(region) if patch: patch.set_color('#FFC0CB') patch.set_alpha(1.0) else: # 000区域是全集外部分,修改背景色 plt.gcf().set_facecolor('#FFC0CB') # 添加集合元素标签(空集合时显示空字符串) v.get_label_by_id('100').set_text(', '.join(map(str, setA - setB - setC)) if (setA - setB - setC) else '') v.get_label_by_id('010').set_text(', '.join(map(str, setB - setA - setC)) if (setB - setA - setC) else '') v.get_label_by_id('001').set_text(', '.join(map(str, setC - setB - setA)) if (setC - setB - setA) else '') v.get_label_by_id('101').set_text(', '.join(map(str, setA & setC - setB)) if (setA & setC - setB) else '') v.get_label_by_id('110').set_text(', '.join(map(str, setA & setB - setC)) if (setA & setB - setC) else '') v.get_label_by_id('011').set_text(', '.join(map(str, setB & setC - setA)) if (setB & setC - setA) else '') v.get_label_by_id('111').set_text(', '.join(map(str, setA & setB & setC)) if (setA & setB & setC) else '') venn3_circles(subsets=[1] * 7, linestyle='solid') # Create menu def menu(): print("#1 Enter a number to Set A") print("#2 Enter a number to Set B") print("#3 Enter a number to Set C") print("#4 Evaluate Expression") print("#5 Display the Venn Diagram") print("#6 Exit") # Execute depending on user's choice while True: menu () choice= input("Enter your number of choice: ") if choice == '1': try: setA.update(map(int, input("Enter a number to set A (separate using space): ").split())) except ValueError: print("Error. Input must be an integer") elif choice == '2': try: setB.update(map(int, input("Enter a number to set B (separate using space): ").split())) except ValueError: print("Error. Input must be an integer ") elif choice == '3': try: setC.update(map(int, input("Enter a number to set C (separate using space): ").split())) except ValueError: print("Error. Input must be an integer") elif choice == '4': print("x for set A, y for set B, z for set C") print("| for union, & for intersection, x-complement for complement of A, universal_set for universal set, empty_set for empty set") expression = input("Evaluate Expression: ") elif choice == '5': if expression: try: plot_diagram(expression) plt.show() except Exception as e: print("Invalid formula. Error:", str(e)) else: print("Please evaluate an expression first.") elif choice =='6': print("Exiting the program.") break else: print("Invalid input")
说明
- 补集语法改为
x-complement对应“集合A的补集”,解析时转换为not x,符合逻辑运算规则。 - 所有韦恩图区域初始强制设为白色并关闭透明度,确保未着色区域不会出现底色透显。
- 仅当
000区域(全集外)属于目标表达式时,才修改figure背景色,否则保持纯白。
内容的提问来源于stack exchange,提问作者mbmocls
相关产品推荐
相关产品推荐

