如何画条纹圆圈?

问题描述 投票:0回答:1

我想在圆圈内创建自定义的粗条纹(有角度、垂直或水平)。目标是重现像令牌这样的图像here

一个关键点是输出必须是具有透明背景的 PNG 格式。此外,主圈之外不得有艺术家/补丁/等。

这是我到目前为止所拥有的(没有条纹):

import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from matplotlib import rcParams
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)

生成如下图像。

我的下一步是尝试三角学、圆弧段和矩形,但如果这太过分了,我宁愿不要重新发明轮子。

python matplotlib
1个回答
1
投票

import matplotlib.pyplot as plt
import matplotlib.patches as patches

fig, ax = plt.subplots()
r_out, r_in = 25, 21
outer = patches.Circle((0, 0), radius=r_out, transform=ax.transData,
                       color='k')
inner = patches.Circle((0, 0), radius=r_in, transform=ax.transData)
ax.add_patch(outer)

width = height = 2*r_in
#################################
nstripes = 4
ratio_stripes_bg = 1.6
#################################
width_stripe = width/(nstripes+(nstripes-1)/ratio_stripes_bg)
delta_stripe = width_stripe*(1+1/ratio_stripes_bg)

for stripe in range(nstripes):
    x0 = -r_in+stripe*delta_stripe
    rect = patches.Rectangle((x0,-r_in), width_stripe, height, color="#050050")
    rect.set_clip_path(inner)
    ax.add_patch(rect)

ax.set_aspect(1)
ax.autoscale_view()
ax.axis('off')
plt.show()

更新


import matplotlib.pyplot as plt
import matplotlib.patches as patches
from math import cos, pi, sin

r_out, r_inn = 25, 22

fig, axs = plt.subplots(1, 5, figsize=(10.0, 2), layout='constrained')

width = height = 2*r_inn
nstripes = 4
ratio_stripes_bg = 1.618

width_stripe = width/(nstripes+(nstripes-1)/ratio_stripes_bg)
delta_stripe = width_stripe*(1+1/ratio_stripes_bg)

for ax, angle in zip(axs, (0.0, 22.5, 45.0, 77.5, 90.0)):
    outer = patches.Circle((0, 0), radius=r_out, color='k')
    ax.add_patch(outer)
    inner = patches.Circle((0, 0), radius=r_inn, transform=ax.transData)
    theta = angle*pi/180
    s, c = sin(theta), cos(theta)
    x0, y0 = r_inn*(s-c), -r_inn*(s+c)
    dx, dy = delta_stripe*c, delta_stripe*s
    for stripe in range(nstripes):
        x = x0+stripe*dx
        y = y0+stripe*dy
        rect = patches.Rectangle((x, y), width_stripe, height,
                                 angle=angle, color="#120857")
        rect.set_clip_path(inner)
        ax.add_patch(rect)
    ax.set_aspect(1)
    ax.set_xlim(-r_out, +r_out)
    ax.set_ylim(-r_out, +r_out)
    ax.autoscale_view()
    ax.axis('off')
plt.show()

第二次更新


我引入了一个偏移量,并且定义了一个在预先存在的轴上绘制圆的函数


import matplotlib.pyplot as plt
import matplotlib.patches as patches
from math import cos, pi, sin

def tick_stripes(ax, r_out, r_inn, n_stripes, ratio, angle, bgc, fgc, offset=0):

    width = height = 2*r_inn
    width_stripe = (width-2*offset)/(n_stripes+(n_stripes-1)/ratio)
    delta_stripe = width_stripe*(1+1/ratio)

    outer = patches.Circle((0, 0), radius=r_out, color=bgc)
    ax.add_patch(outer)
    inner = patches.Circle((0, 0), radius=r_inn, transform=ax.transData)

    theta = angle*pi/180
    s, c = sin(theta), cos(theta)
    
    x0, y0 = r_inn*(s-c)+offset*c, -r_inn*(s+c)+offset*s
    dx, dy = delta_stripe*c, delta_stripe*s
    for i_stripe in range(n_stripes):
        x = x0+i_stripe*dx
        y = y0+i_stripe*dy
        rect = patches.Rectangle((x, y), width_stripe, height,
                                 angle=angle, color=fgc)
        rect.set_clip_path(inner)
        ax.add_patch(rect)
    ax.set_aspect(1)
    ax.set_xlim(-r_out, +r_out)
    ax.set_ylim(-r_out, +r_out)
    ax.axis('off')
    

fig, axs = plt.subplots(1, 5, figsize=(10.0, 2), layout='constrained')
for ax, angle in zip(axs, range(0, 121, 30)):
    tick_stripes(ax, 40, 38, 5, 0.9, angle, '#600030', '#ffb000', 10)

fig, axs = plt.subplots(1, 5, figsize=(10.0, 2), layout='constrained')
for ax, angle in zip(axs, range(0, 121, 30)):
    tick_stripes(ax, 40, 38, 5, 0.9, angle, '#600030', '#ffb000', -7)
    
plt.show()

第三次更新


仔细观察圆圈,您可能会注意到有一个小剪辑,这可以避免增加轴尺寸一点点 - 我不会再发布图像或完整代码,足以说

    ...
    axlim = r_out*1.01
    ax.set_xlim(-axlim, axlim)
    ax.set_ylim(-axlim, axlim)
    ...
© www.soinside.com 2019 - 2024. All rights reserved.