matplotlib:在线宽点和transAxes之间转换?

时间:2014-06-14 21:57:22

标签: python matplotlib

在许多情况下,我发现将方轴放在图上很方便,这样我就可以轻松地在transAxes单位工作,而不必担心图形的纵横比。但是,我遇到的一个问题是,当您绘制一条线时,线宽会从路径向任一方向延伸lw/2个点。当然,这是正常的,预期的行为,但它会导致问题,如果我试图在某些轴上写入某些东西(并使用边界框中的所有空间),这些线将在轴的边缘剪辑。我可以设置clip_on=False,但这只是为了让我想要在轴上刻的图形超出轴的边界。我的问题是 - 如何在“线宽”规格(以点为单位)和transAxes单位之间进行转换,以便我可以补偿形状的额外长度/宽度?​​

我已经编写了一个简单的MWE,应该证明我的意思:

"""
MWE demonstrating the cliping of linewidths that are inscribed in axes.
"""
from __future__ import division
from matplotlib.pyplot import figure, show, savefig
from matplotlib.pyplot import Circle
from matplotlib.lines import Line2D

# Make a figure
(fig_w, fig_h) = (7.5, 2.5)
cdpi = 150
fig_aspect = fig_h/fig_w
fig = figure(1, figsize=(fig_w, fig_h), dpi=cdpi)

# Helper functions to center the circles
get_w_from_h = lambda h: h*fig_aspect
get_b_from_h = lambda h: (1-h)/2
get_l_centered = lambda left, span, w: left+(span-w)/2

# Left circle 1 - The line at the center shows that lw is the same number of pixels no matter 
# what transform you use.
l_h = 0.25
l_w = get_w_from_h(l_h);        l_b = get_b_from_h(l_h)
l_l = get_l_centered(0, 1/3, l_w)
l_box = [l_l, l_b, l_w, l_h]

lcax = fig.add_axes(l_box)
lclw = 2.0
lcirc = Circle((0.5, 0.5), 0.5, lw=lclw, color='#FF3932', fill=False, transform=lcax.transAxes)
lline = Line2D([-0.5, 1.5], [0.5, 0.5], lw=lclw*4, color='#FF3932', 
             dashes=[5,1e-14,1e-14, 5], clip_on=False, transform=lcax.transAxes)
lcax.add_patch(lcirc)
lcax.add_line(lline)
lcax.axis('off')

# Left Circle 2
l_h2 = 0.75
l_w2 = get_w_from_h(l_h2);      l_b2 = get_b_from_h(l_h2)
l_l2 = get_l_centered(0, 1/3, l_w2)
l_box2 = [l_l2, l_b2, l_w2, l_h2]

lcax2 = fig.add_axes(l_box2)
lcirc2 = Circle((0.5, 0.5), 0.5, lw=lclw, color='#b20500', fill=False, transform=lcax2.transAxes)
lline2 = Line2D([0.1, 0.9], [0.5, 0.5], lw=lclw*4, color='#b20500', 
             dashes=[1e-14,5,5, 1e-14], transform=lcax2.transAxes)
lcax2.add_patch(lcirc2)
lcax2.add_line(lline2)
lcax2.axis('off')


# Middle circle
m_h = 0.9
m_w = get_w_from_h(m_h);        m_b = get_b_from_h(m_h)
m_l = get_l_centered(1/3, 1/3, m_w)
m_box = [m_l, m_b, m_w, m_h]

mcax = fig.add_axes(m_box)
mclw = 4.0
mcirc = Circle((0.5, 0.5), 0.5, lw=mclw, color='b', fill=False, 
               clip_on=False,
               transform=mcax.transAxes)
mcax.add_patch(mcirc)
mcax.axis('off')

# Right circle 1
r_h = 0.75
r_w = get_w_from_h(r_h);        r_b = get_b_from_h(r_h)
r_l = get_l_centered(2/3, 1/3, r_w)
r_box = [r_l, r_b, r_w, r_h]

rcax = fig.add_axes(r_box, zorder=1)
rclw = 2.0
rcirc = Circle((0.5, 0.5), 0.5, lw=rclw, edgecolor='k', facecolor='#4E4E4E', 
               fill=True, transform=rcax.transAxes)
rcax.add_patch(rcirc)
rcax.axis('off')

# Right circle 2
r_h2 = 0.5
r_w2 = get_w_from_h(r_h2);      r_b2 = get_b_from_h(r_h2)
r_l2 = get_l_centered(2/3, 1/3, r_w2)
r_box2 = [r_l2, r_b2, r_w2, r_h2]

rcax2 = fig.add_axes(r_box2, zorder=2)
rcirc2 = Circle((0.5, 0.5), 0.5, lw=rclw, edgecolor='none', facecolor='#BBBBBB', 
               fill=True, transform=rcax2.transAxes)
rcax2.add_patch(rcirc2)
rcax2.axis('off')

savefig('ClippingMWE.png', transparent=True, dpi=cdpi)

这会产生这个数字: Clipping figure

根据左侧圆圈的比较,看起来线宽始终是相同的像素数,无论它放在哪个轴上(这都是有意义的)。中心圆是我想要的圆圈(无剪裁),但当然圆圈实际上比我想要的要宽一些。右侧的圆圈表示剪切框相对于线条的作用。显然,在轴上刻有填充圆圈没有问题。

虽然我也有兴趣知道是否有标志或者我可以设置在路径的某一侧绘制线条(例如在路径的内部上划线)而不是以路径为中心),我主要对如何从lw转换为transAxes单位感兴趣,因为在尝试计算我需要容纳的空间量时我遇到了同样的问题给定大小的字体。

0 个答案:

没有答案