Matplotlib 使中心圆透明

Matplotlib Make Center Circle Transparent

我正在绘制饼图,使 png 图像中的背景看起来透明。我怎样才能使中心圆看起来也透明而不是白色?

import matplotlib.pyplot as plt

# Pie chart, where the slices will be ordered and plotted counter-clockwise:
labels = 'Correct', 'Wrong'
sizes = [20, 80]

fig1, ax1 = plt.subplots()
ax1.pie(sizes,colors=['green','red'], labels=labels,autopct='%1.1f%%', 
shadow=True, startangle=90)
centre_circle = plt.Circle((0,0),0.75,edgecolor='black', 
facecolor='white',fill=True,linewidth=0.25)
fig1 = plt.gcf()
fig1.gca().add_artist(centre_circle)
ax1.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.
fig1.savefig('foo.png', transparent=True)

问题是你没有真正制作一个真正的圆环图。有了这部分代码

centre_circle = plt.Circle((0,0),0.75,edgecolor='black', 
facecolor='white',fill=True,linewidth=0.25)

你在饼图中间画了一个圆圈。问题是如果你让这个圆透明,你会再次看到饼图的中间。我建议使用像 pixlr 这样的免费照片编辑程序来让它透明。除非你能找到一种方法来制作真正的圆环图,不幸的是我不知道该怎么做。

你在上面的代码中创建白色中间部分的方法是通过一个圆来混淆饼图的中心。这当然不能产生透明的内部。

这个问题的解决方案也可以在更复杂的问题 中找到。让我详细说说:

为了制作一个真正的中间有孔的甜甜圈图,需要切割楔子,使它们成为部分环。幸运的是,matplotlib 提供了这样做的工具。饼图由几个楔形组成。 来自 matplotlib.patches.Wedge 我们学习的文档

class matplotlib.patches.Wedge(center, r, theta1, theta2, width=None, **kwargs)
Wedge shaped patch. [...] If width is given, then a partial wedge is drawn from inner radius r - width to outer radius r.

为了设置所有楔形的宽度,一个简单的方法是使用plt.setp

wedges, _ = ax.pie([20,80], ...)
plt.setp( wedges, width=0.25)

完整示例:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
fig.set_facecolor("#fff9c9") # set yellow background color to see effect

wedges, text, autotext = ax.pie([25, 40], colors=['limegreen','crimson'],
                                labels=['Correct', 'Wrong'], autopct='%1.1f%%')
plt.setp( wedges, width=0.25)

ax.set_aspect("equal")
# the produced png will have a transparent background
plt.savefig(__file__+".png", transparent=True)
plt.show()


如果 Wedge 没有 width 参数,以下是解决问题的方法。 由于饼图以 (0,0) 为中心,复制外部路径坐标,还原它们并乘以某个较小的数字 1(在下面的代码中称为 r 用于半径),给出内环的坐标。加入这两个坐标列表并注意正确的路径代码可以根据需要创建环形。

import matplotlib.pyplot as plt
import matplotlib.path as mpath
import matplotlib.patches as mpatches
import numpy as np

def cutwedge(wedge, r=0.8):
    path = wedge.get_path()
    verts = path.vertices[:-3]
    codes = path.codes[:-3]
    new_verts = np.vstack((verts , verts[::-1]*r, verts[0,:]))
    new_codes =  np.concatenate((codes , codes[::-1], np.array([79])) )
    new_codes[len(codes)] = 2
    new_path = mpath.Path(new_verts, new_codes)
    new_patch = mpatches.PathPatch(new_path)
    new_patch.update_from(wedge)
    wedge.set_visible(False)
    wedge.axes.add_patch(new_patch)
    return new_patch

fig, ax = plt.subplots()
fig.set_facecolor("#fff9c9") # set yellow background color to see effect


wedges, text, autotext = ax.pie([25, 75], colors=['limegreen','indigo'], 
                                labels=['Correct', 'Wrong'], autopct='%1.1f%%')

for w in wedges:
    cutwedge(w)
    # or try cutwedge(w, r=0.4)

ax.set_aspect("equal")

# the produced png will have a transparent background
plt.savefig(__file__+".png", transparent=True)
plt.show()

solution referenced by importanceofbeingearnest 类似,您需要使用 plt.setp(pie, width=width) 来设置饼图的宽度,这将使它成为真正的圆环,而不是画有实心圆的饼图在上面。

import matplotlib.pyplot as plt
fig1, ax1 = plt.subplots()
ax1.axis('equal')

# Set the width of the pie slices;
# this is equivalent to (1.0-0.75), or 
# (the radius of the pie chart - the radius of the inner circle)
width=0.25 

# Pie chart, where the slices will be ordered and plotted counter-clockwise:
labels = ['Correct', 'Wrong']
sizes = [20., 80.]

# ax1.pie will return three values:
# 1. pie (the dimensions of each wedge of the pie), 
# 2. labtext (the coordinates and text for the labels)
# 3. labpct (the coordinates and text of the "XX.X%"" labels)
pie, labtext, labpct = ax1.pie(x=sizes,
                labels=labels,
                colors=['green','red'],
                startangle=90,
                shadow=True,
                autopct='%1.1f%%'
                )
# apply "plt.setp" to set width property
plt.setp(pie, width=width)

# save the figure as transparent
fig1.savefig('foo.png', transparent=True)