![](/img/trans.png)
[英]Stacked bar charts using python matplotlib for positive and negative values
[英]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)
产生以下输出
那么让我解释一下我在这里做了什么。 最初,我迭代for
-loop中的xticklabels并使用label.set_ha('right')
将所有xticklabels水平对齐到右边。 然而,标签都是填充的,我没有缩小它们的边界框(甚至不确定它是否以这种方式工作!)。 因此,我决定注册一个onresize回调函数,因为在调整大小时可能会出现新的xticklabels。 然后,我增加了set_x
函数(代码来自: https : set_x
,归功于他们)。 不能手动调整SHIFT
变量唯一可以做的就是让画布大小进行一些有意义的计算,这些计算在[0.4,0.6]范围内,这似乎是好的偏移值(经验测试......)。
即使它只是另一个“hacky”解决方案提案,它可能有助于找到合适的答案! 我希望它有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.