通过在matplotlib中使用Latex,xticklabel中的正值和负值之间的差异

时间:2013-11-04 08:47:52

标签: python matplotlib latex

我在matplotlib中设置usetext = True来使用Latex来管理我的绘图中的字体布局。现在,x轴和xticklabel之间的空间对于正值和负值是不同的,如图所示。

是否有可能获得相同的空间?

示例:

import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(-10.0, 10.0, 100)
s = np.cos(t)

plt.rc('text', usetex=True)

plt.rc('font', family='serif', size=30)
plt.plot(t, s)

plt.show()

enter image description here

4 个答案:

答案 0 :(得分:2)

不幸的是,这个bug已经存在了很长时间,而且这里的大多数答案都认为问题是关于水平对齐而不是垂直间距。

The bug是众所周知的,并且有一个补丁来修复它,但它尚未合并,并且在过去的一年半中被列为需要审核。

有趣的是,这是一个相当令人困惑的错误。最初出现的问题是,由于某些原因,TeX给出一个减号(和其他几个数学符号)的下降值,表明它延伸到了基线以下。 dvipng,用于在光栅后端创建标签,只是裁剪到可见,所以这没关系。但为了保持对齐实际上具有下行的东西,matplotlib有一个单独的系统dviread,它从dvi文件本身读取值。这会获得奇怪的下降值。然后matplotlib的对齐系统认为png的一部分假设低于基线,将其向下移动。

错误报告中的修复非常简单,但我不完全确定它是如何工作的。不过,我已经尝试过了,它确实有效。

当然,这个问题是在2013年被问到的,所以看起来这个补丁似乎不会很快被应用。那么有哪些替代方案?

一个简单的选择是在工作时忽略对齐问题,但是,在进行演示输出时,请使用pdf后端。如果您想要图像,可以随时使用其他软件进行转换。 pdf后端不会遇到同样的问题,因为它完全不同地处理TeX部分。

另一种选择是调整负xticks的位置。从理论上讲,你可以从_get_layout中拉出精确的调整,这将给你下降值,但我不知道如何转换值。所以这是一个只关注对齐的例子:

import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(-10.0, 10.0, 100)
s = np.cos(t)

i = [-10,-5,0,5,10]

plt.rc('text', usetex=True)

plt.rc('font', family='serif', size=30)
plt.plot(t, s)

for n,l in zip(*plt.xticks()):
    if n<0: l.set_position((0,0.014))

答案 1 :(得分:1)

这是一种“hacky”方式,我不确定为什么要修复它,但使用FormatStrFormatter中的matplotlib.ticker似乎可以修复它。唯一的区别是字体粗细看起来很粗。我似乎无法改变这一点,但也许你可以解决这个问题。

import numpy as np
import matplotlib.ticker as mtick
import matplotlib.pyplot as plt

t = np.linspace(-10.0, 10.0, 100)
s = np.cos(t)

plt.rc('text', usetex=True)
plt.rc('font', family='serif', size=30)

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(t, s)

fmtx = '%.0f%%'
fmty = '%.1f%%'
xticks = mtick.FormatStrFormatter(fmtx)
yticks = mtick.FormatStrFormatter(fmty)
ax1.xaxis.set_major_formatter(xticks)
ax1.yaxis.set_major_formatter(yticks)
plt.show()

enter image description here

答案 2 :(得分:0)

我修复这样的小问题的方法是将绘图保存为SVG,然后在我最喜欢的矢量图形程序(例如InkScape)中编辑它。这将允许您选择绘图的各个部分并移动它们,同时保留高质量的矢量图形。

答案 3 :(得分:-1)

所以(遗憾的是)我只能设法提出另一个&#34; hacky&#34;解决方案,但我想我会分享:

import numpy as np
import matplotlib as mplib
import matplotlib.pyplot as plt
import types

# set up few plot options
plt.rc('text', usetex=True)
plt.rc('font', family='serif', size=30)

# get some data to plot
t = np.linspace(-10.0, 10.0, 100)
s = np.cos(t)

# plot things
fig = plt.figure()
ax  = fig.add_subplot(111)
ax.plot(t, s)

# define and register onresize callback to handle new ticks that appear on resize
def onresize(event):
    SHIFT = 0.5
    for label in ax.get_xticklabels():
        #print(label.get_text())  # test to see if new ticks appear as expected
        label.set_ha('right')
        label.customShiftValue = SHIFT
        label.set_x = types.MethodType(
                lambda self, x: mplib.text.Text.set_x(self, x+self.customShiftValue),
                label)

cid = fig.canvas.mpl_connect('resize_event', onresize)

# hold plot open
plt.show(block=True)

产生以下输出

alt_img

让我解释一下我在这里所做的事情。最初,我在for - 循环中迭代了xticklabels并使用label.set_ha('right')将所有xticklabels水平对齐到右边。然而,标签都是填充的,我没有缩小它们的边界框(甚至不确定它是否以这种方式工作!)。因此,我决定注册一个onresize回调函数,因为在调整大小时可能会出现新的xticklabels。然后,我扩充了set_x函数(代码来自:https://stackoverflow.com/a/33688795/2402281,信用给他们)。不能手动调整SHIFT变量可以做的唯一事情就是让画布大小进行一些有意义的计算,这些计算在[0.4,0.6]范围内,这似乎是良好的偏移值(经验测试.. )。

即使它只是另一个&#34; hacky&#34;解决方案提案,它可能有助于找到合适的答案!我希望它有所帮助。