Подтвердить что ты не робот

Разница между положительными и отрицательными значениями в xticklabel с использованием латекса в matplotlib

Я устанавливаю usetext = True в matplotlib, чтобы использовать 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()

enter image description here

4b9b3361

Ответ 1

Несчастливо, что эта ошибка была так долго, и большинство ответов здесь показало, что вопрос касался горизонтального выравнивания, а не вертикального интервала.

Известна ошибка, и есть исправление для ее исправления, но она не была объединена и просто указана как нуждающихся в обзоре за последние полтора года.

Интересно, что это ошибка, которая довольно запутанна. Вначале проблема состоит в том, что по какой-то причине TeX дает знак минус (и несколько других математических символов) значение descender, предполагая, что оно распространяется ниже базовой линии. dvipng, используемый для создания меток в растровых бэкэндах, только урожая до видимого, так что это не имеет значения. Но чтобы сохранить выравнивание, которое на самом деле имеет descenders, matplotlib имеет отдельную систему dviread, которая считывает значения из самого файла dvi. Это подхватывает нечетное значение descender. Затем система выравнивания matplotlib, считая, что часть png должна находиться ниже базовой линии, перемещает ее вниз.

Исправление в отчете об ошибке очень просто, но я не совсем уверен, как это работает. Я пробовал это, однако, и это работает.

Конечно, этот вопрос задавали в 2013 году, поэтому не похоже, что патч будет применен в ближайшее время. Итак, каковы альтернативы?

Один простой вариант - просто игнорировать проблему выравнивания при работе, но при выполнении вывода презентации используйте pdf файл. Если вы хотите получать изображения, вы всегда можете использовать другое программное обеспечение для конвертирования. Бэкэнд PDF не страдает от одной и той же проблемы, так как обрабатывает части TeX совершенно по-другому.

Другой вариант - просто настроить положение отрицательных xticks. Теоретически вы можете вытащить точную настройку из _get_layout, которая даст вам значение descender, но я не уверен, как преобразовать значения. Итак, вот пример простого просмотра выравнивания:

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

Ответ 2

То, как я исправляю такие незначительные проблемы, как сохранить сюжет как SVG, а затем отредактировать его в моей любимой программе векторной графики (например, InkScape). Это позволит вам выбрать отдельные части сюжета и переместить их, сохранив при этом качественную векторную графику.

Ответ 3

Это своего рода "хакерский" способ сделать это, и я не уверен, почему он его исправляет, но использование FormatStrFormatter from matplotlib.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()

введите описание изображения здесь

Ответ 4

так (к сожалению) мне только удалось придумать другое "взломанное" решение, но я подумал, что поделюсь:

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


Итак, позвольте мне объяснить, что я здесь сделал. Первоначально я повторил xticklabels в for -loop и использовал label.set_ha('right') для горизонтального выравнивания всех xticklabels справа. Тем не менее, эти ярлыки были дополнены, и я не смог сжать свою ограничительную рамку (даже не уверен, что так работает!). Следовательно, я решил зарегистрировать функцию обратного вызова onresize, потому что при изменении размера могут появиться новые xticklabels. Затем я увеличил функцию set_x (код заимствован из: fooobar.com/info/309854/..., кредитов для них). Единственное, что можно было бы сделать, чтобы вручную не настроить переменную SHIFT, - это получить размер холста для выполнения значимых вычислений, находящихся в диапазоне [0,4, 0,6], которые, как представляется, являются хорошими значениями смещения (эмпирически проверены...).

Несмотря на то, что это просто еще одно "решение для взлома", оно может помочь найти подходящий ответ! Надеюсь, это поможет.