如何用Matplotlib绘制带自定义条纹的透明圆形代币?
圆形代币内自定义粗条纹的简便实现
需求说明
- 在圆形代币内添加斜向、垂直或水平的粗条纹,复刻目标代币样式
- 输出必须为带透明背景的PNG,主圆形外不能包含任何额外图形元素
现有无条纹版本代码
import matplotlib.pyplot as plt import matplotlib.font_manager as fm from matplotlib.patches import Ellipse,Rectangle prop = fm.FontProperties(fname="mydirectory/JUST Sans ExBold.otf") class Team: def __init__(self): self.color = '#8bb5da' self.edge_type = 'thin' self.edge_color = 'black' self.name = 'man-city' self.font_color = 'black' def define_jerseys(): jerseys = [] mancity = Team() arsenal = Team() arsenal.color = '#EF0107' arsenal.edge_type = 'full' arsenal.edge_color = 'white' arsenal.name = 'arsenal' arsenal.font_color = 'white' jerseys = [mancity,arsenal] return jerseys def draw_token(jersey,n,save=True): plt.close('all') fig= plt.figure('token',figsize=(10,10)) ax = fig.add_subplot(111) ax.grid(False) ax.axis('off') x0, y0 = ax.transAxes.transform((0, 0)) # lower left in pixels x1, y1 = ax.transAxes.transform((1, 1)) # upper right in pixes dx = x1 - x0 dy = y1 - y0 maxd = max(dx, dy) width = 0.4* maxd / dx height = 0.4* maxd / dy if jersey.edge_type=='full': ax.add_artist(Ellipse((.45, .45), width, height,fc=jersey.edge_color)) ax.add_artist(Ellipse((.45, .45), 0.9*width, 0.9*height,fc=jersey.color)) if jersey.edge_type=='thin': ax.add_artist(Ellipse((.45, .45), width, height,fc=jersey.color)) ax.add_artist(Ellipse((.45, .45), width*0.9, height*0.9,ec=jersey.edge_color,fc=None,fill=False,lw=3)) plt.text(0.444,0.426,str(n),fontproperties=prop,fontsize=170,ha='center',va='center',color=jersey.font_color) if n == 6: ax.add_artist(Rectangle((.41,.31),0.08,0.01,color=jersey.font_color)) if save: plt.savefig('./'+jersey.name+'/'+jersey.name+'_'+str(n)+'.png',transparent=True,dpi=96/5) else: plt.show() def create_one(jersey): for i in range(1,12): draw_token(jersey,i) def create_all(jerseys): for jersey in jerseys: create_one(jersey) if __name__=='__main__': jerseys = define_jerseys() arsenal = jerseys[1] create_one(arsenal)
现有代码生成的示例图


简便实现方案(无需三角函数/圆弧计算)
利用Matplotlib的**裁剪(clip_path)**功能,直接绘制条纹后用圆形路径裁剪,只保留圆形内的部分,无需手动计算复杂几何:
修改后的完整代码
import matplotlib.pyplot as plt import matplotlib.font_manager as fm from matplotlib.patches import Ellipse, Rectangle from matplotlib.transforms import Affine2D prop = fm.FontProperties(fname="mydirectory/JUST Sans ExBold.otf") class Team: def __init__(self): self.color = '#8bb5da' self.edge_type = 'thin' self.edge_color = 'black' self.name = 'man-city' self.font_color = 'black' # 新增条纹配置:(方向, 条纹颜色, 条纹宽度, 间距) # 方向可选:'horizontal'/'vertical'/'diagonal' self.stripes = None def define_jerseys(): jerseys = [] mancity = Team() # 给曼城添加斜向白条纹 mancity.stripes = ('diagonal', 'white', 0.04, 0.06) arsenal = Team() arsenal.color = '#EF0107' arsenal.edge_type = 'full' arsenal.edge_color = 'white' arsenal.name = 'arsenal' arsenal.font_color = 'white' # 给阿森纳添加垂直白条纹 arsenal.stripes = ('vertical', 'white', 0.05, 0.05) jerseys = [mancity,arsenal] return jerseys def draw_token(jersey,n,save=True): plt.close('all') fig= plt.figure('token',figsize=(10,10)) ax = fig.add_subplot(111) ax.grid(False) ax.axis('off') x0, y0 = ax.transAxes.transform((0, 0)) # lower left in pixels x1, y1 = ax.transAxes.transform((1, 1)) # upper right in pixes dx = x1 - x0 dy = y1 - y0 maxd = max(dx, dy) width = 0.4* maxd / dx height = 0.4* maxd / dy # 绘制基础圆形结构 inner_circle_radius_x = 0.9*width/2 inner_circle_radius_y = 0.9*height/2 if jersey.edge_type=='full': ax.add_artist(Ellipse((.45, .45), width, height,fc=jersey.edge_color)) inner_circle = Ellipse((.45, .45), 0.9*width, 0.9*height,fc=jersey.color) ax.add_artist(inner_circle) if jersey.edge_type=='thin': ax.add_artist(Ellipse((.45, .45), width, height,fc=jersey.color)) inner_circle = Ellipse((.45, .45), width*0.9, height*0.9,ec=jersey.edge_color,fc=None,fill=False,lw=3) ax.add_artist(inner_circle) # 绘制条纹(如果配置了) if jersey.stripes is not None: stripe_dir, stripe_color, stripe_width, stripe_spacing = jersey.stripes # 创建裁剪用的路径(和内部圆形完全一致) clip_path = Ellipse((.45, .45), 0.9*width, 0.9*height) if stripe_dir == 'horizontal': # 生成覆盖画布的水平条纹,裁剪后只保留圆形内部分 y_pos = -0.5 while y_pos < 1.5: stripe = Rectangle((-0.5, y_pos), 2, stripe_width, fc=stripe_color) stripe.set_clip_path(clip_path) ax.add_artist(stripe) y_pos += stripe_width + stripe_spacing elif stripe_dir == 'vertical': # 垂直条纹 x_pos = -0.5 while x_pos < 1.5: stripe = Rectangle((x_pos, -0.5), stripe_width, 2, fc=stripe_color) stripe.set_clip_path(clip_path) ax.add_artist(stripe) x_pos += stripe_width + stripe_spacing elif stripe_dir == 'diagonal': # 45度斜条纹,通过旋转矩形实现 rotate_transform = Affine2D().rotate_deg(45) + ax.transData x_pos = -1 while x_pos < 2: stripe = Rectangle((x_pos, -1), stripe_width, 4, fc=stripe_color) stripe.set_transform(rotate_transform) stripe.set_clip_path(clip_path) ax.add_artist(stripe) x_pos += stripe_width + stripe_spacing # 绘制数字和特殊标记 plt.text(0.444,0.426,str(n),fontproperties=prop,fontsize=170,ha='center',va='center',color=jersey.font_color) if n == 6: ax.add_artist(Rectangle((.41,.31),0.08,0.01,color=jersey.font_color)) if save: plt.savefig('./'+jersey.name+'/'+jersey.name+'_'+str(n)+'.png',transparent=True,dpi=96/5) else: plt.show() def create_one(jersey): for i in range(1,12): draw_token(jersey,i) def create_all(jerseys): for jersey in jerseys: create_one(jersey) if __name__=='__main__': jerseys = define_jerseys() arsenal = jerseys[1] create_one(arsenal)
方案优势
- 完全避免手动计算圆弧、三角函数等复杂几何逻辑,代码简洁易维护
- 条纹的方向、颜色、粗细、间距都可通过
Team类的stripes参数灵活调整 - 利用裁剪功能自动确保条纹只出现在圆形内部,完全符合“主圆形外无额外元素”的要求
- 输出依然是带透明背景的PNG,满足格式要求
内容的提问来源于stack exchange,提问作者daydaybroskii
相关产品推荐
相关产品推荐

