You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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)

现有代码生成的示例图

arsenal6代币示例
mancity1代币示例

简便实现方案(无需三角函数/圆弧计算)

利用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:09:56