【问题标题】:Difference between positive and negative values in xticklabel by using Latex in matplotlib通过在 matplotlib 中使用 Latex 在 xticklabel 中的正值和负值之间的差异
【发布时间】:2013-11-14 20:44:59
【问题描述】:

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

【问题讨论】:

  • 没有简单的方法来实现这一点,因为在外部使用dvipng 处理文本,并将生成的图像插入到图中。这些没有任何空白。您必须做的是将 xtick 标签对齐设置为“右”,然后向右移动一点。但我无法让这种额外的转变工作。
  • 问题在于如何从 PS 边界框推断出文本的轮廓。对齐的是大纲框,而不是文本本身。我认为你必须深入挖掘才能改变这种行为。
  • 不要试图“过度设计”你的地块,它们已经很整洁了。
  • 除非我很困惑,否则用户询问的是负标签的 vertical 对齐方式,这是一个错误,而不是 horizo​​ntal结盟*。与优先考虑的水平定位不同,垂直对齐是完全错误的。
  • @mdurant 实际上,在这种情况下,仅按轮廓框对齐可能就可以了。但是 matplotlib 试图通过直接从 dvi 文件中读取下降值来调整对齐方式,除其他外,由于某种原因,它认为减号延伸到基线以下。

标签: python matplotlib latex


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这是一种“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()
    

    【讨论】:

    • 这在某种程度上是可行的,因为它使用文本模式而不是数学模式作为 TeX 标签,而文本模式减号没有同样的问题。
    【解决方案3】:

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

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

    【讨论】:

    • 这仍然有同样的问题。除非我感到困惑,否则问题在于轴和标签之间的 vertical 空间,而不是水平对齐。这是known bug
    • 感谢您的反馈@cge。对于那些投票给我的人……为什么?我试图提供一个解决方案,甚至承认这是一个肮脏的黑客......
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2017-02-22
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 2020-02-25
      • 1970-01-01
      • 2012-04-04
      • 1970-01-01
      • 2020-11-06
      相关资源
      最近更新 更多