繁体   English   中英

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

[英]Difference between positive and negative values in xticklabel by using Latex in matplotlib

我在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()

在此输入图像描述

不幸的是,这个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))

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

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()

在此输入图像描述

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

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

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 -loop中的xticklabels并使用label.set_ha('right')将所有xticklabels水平对齐到右边。 然而,标签都是填充的,我没有缩小它们的边界框(甚至不确定它是否以这种方式工作!)。 因此,我决定注册一个onresize回调函数,因为在调整大小时可能会出现新的xticklabels。 然后,我增加了set_x函数(代码来自: httpsset_x ,归功于他们)。 不能手动调整SHIFT变量唯一可以做的就是让画布大小进行一些有意义的计算,这些计算在[0.4,0.6]范围内,这似乎是好的偏移值(经验测试......)。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM