17

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

在此处输入图像描述

4

4 回答 4

2

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

该错误是已知的,并且有一个补丁可以修复它,但尚未合并,只是在过去一年半的时间里被列为需要审查。

有趣的是,这是一个相当令人困惑的错误。最初出现的问题是,出于某种原因,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))
于 2017-09-08T18:00:44.387 回答
1

这是一种“hacky”的做法,我不确定为什么要修复它,但使用FormatStrFormatterfrommatplotlib.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()

在此处输入图像描述

于 2017-01-01T01:42:53.080 回答
0

所以(可悲)我只设法想出了另一个“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功能(代码来自:https ://stackoverflow.com/a/33688795/2402281 ,归功于他们)。唯一可以不手动调整SHIFT变量的方法是让画布大小在 [0.4, 0.6] 范围内进行一些有意义的计算,这似乎是很好的偏移值(经过经验测试......)。

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

于 2017-03-12T08:44:34.483 回答
-1

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

于 2014-10-02T22:13:33.977 回答