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

Как переместить метку в matplotlib?

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

Более конкретно, при вращении меток с plt.setp, центры текста меток остаются выровненными с тиками. Я хотел бы сместить эти метки вправо, так что ближние концы меток выравниваются, как показано на изображении ниже.

enter image description here

Я знаю этот пост и этот, однако ответы интересные клоды, а не строгие ответы на вопрос.

мой код:

import matplotlib.pyplot as plt
import numpy as np
import datetime

# my fake data
dates = np.array([datetime.datetime(2000,1,1) + datetime.timedelta(days=i) for i in range(365*5)])
data = np.sin(np.arange(365*5)/365.0*2*np.pi - 0.25*np.pi) + np.random.rand(365*5) /3

# creates fig with 2 subplots
fig = plt.figure(figsize=(10.0, 6.0))
ax = plt.subplot2grid((2,1), (0, 0))
ax2 = plt.subplot2grid((2,1), (1, 0))
## plot dates
ax2.plot_date( dates, data )

# rotates labels 
plt.setp( ax2.xaxis.get_majorticklabels(), rotation=-45 ) 

# try to shift labels to the right
ax2.xaxis.get_majorticklabels()[2].set_y(-.1)
ax2.xaxis.get_majorticklabels()[2].set_x(10**99)

plt.show()

Как ни странно, set_y ведет себя так, как ожидалось, но даже если бы я установил x в fantasillion, метки не сдвинулись бы на одну точку. (Использование plot_date может ввести дополнительную путаницу, но то же самое происходит с plot.)

4b9b3361

Ответ 1

Я нашел способ сдвинуть метки тика оси х произвольным и точным количеством, но этот путь опасно приближается к крутым и скользким скалам, возвышающимся над морем безумия. Так что только очень храбрый или отчаянный должен читать дальше...

При этом проблема заключается в том, что позиция x меток задается при визуализации чертежа (я не рассматривал эту часть кода, но это мое понимание). Итак, все, что вы делаете с set_x(), переопределяется позже. Тем не менее, есть способ обойти это: вы можете установить patch_x обезьяны для определенных тиков, чтобы метки не рисовались там, где рендеринг хочет их рисовать:

import types
SHIFT = 10. # Data coordinates
for label in ax2.xaxis.get_majorticklabels():
    label.customShiftValue = SHIFT
    label.set_x = types.MethodType( lambda self, x: matplotlib.text.Text.set_x(self, x-self.customShiftValue ), 
                                    label, matplotlib.text.Text )

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

Если кто-нибудь знает, как это сделать на более низком уровне безумия, мне было бы очень интересно...

Ответ 2

Вместо

ax2.xaxis.get_majorticklabels()[2].set_y(-.1)
ax2.xaxis.get_majorticklabels()[2].set_x(10**99)

используйте set_horizontalalignment() для каждого тика по оси:

for tick in ax2.xaxis.get_majorticklabels():
    tick.set_horizontalalignment("left")

в результате:

Ответ 3

Другой способ горизонтального выравнивания:

plt.xticks(ha='left')

Ответ 4

Прежде всего, позвольте использовать mcve, чтобы показать проблему.

import numpy as np
import datetime
import matplotlib.pyplot as plt
plt.rcParams["date.autoformatter.month"] = "%b %Y"

# my fake data
dates = np.array([datetime.datetime(2000,1,1) + datetime.timedelta(days=i) for i in range(365)])
data = np.sin(np.arange(365)/365.0*2*np.pi - 0.25*np.pi) + np.random.rand(365) /3

# creates fig with 2 subplots
fig, ax = plt.subplots(figsize=(6,2))
## plot dates
ax.plot_date( dates, data )

# rotates labels 
plt.setp( ax.xaxis.get_majorticklabels(), rotation=-45 ) 

plt.tight_layout()
plt.show()

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

Теперь, как уже указывали другие участники, вы можете использовать горизонтальное выравнивание текста.

# rotates labels and aligns them horizontally to left 
plt.setp( ax.xaxis.get_majorticklabels(), rotation=-45, ha="left" )

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

Вы можете использовать аргумент rotation_mode, чтобы ротация происходила в верхней левой части текста, давая в этом случае немного приятный результат.

# rotates labels and aligns them horizontally to left 
plt.setp( ax.xaxis.get_majorticklabels(), rotation=-45, ha="left", rotation_mode="anchor") 

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

Если эти параметры недостаточно мелкие, то есть вы хотите более точно расположить метки. переместив его в сторону на некоторые точки, вы можете использовать преобразование. Следующее будет смещать метку на 5 точек в горизонтальном направлении, используя matplotlib.transforms.ScaledTranslation.

import matplotlib.transforms

plt.setp( ax.xaxis.get_majorticklabels(), rotation=-45) 

# Create offset transform by 5 points in x direction
dx = 5/72.; dy = 0/72. 
offset = matplotlib.transforms.ScaledTranslation(dx, dy, fig.dpi_scale_trans)

# apply offset transform to all x ticklabels.
for label in ax.xaxis.get_majorticklabels():
    label.set_transform(label.get_transform() + offset)

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

Преимущество этого, по сравнению с, например, решение, предоставленное @explorerDude, заключается в том, что смещение не зависит от данных на графике, так что оно обычно применимо к любому сюжету и будет выглядеть одинаково для данного шрифта.