簡體   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