Matplotlib демонстрирует ярлыки x-tick, перекрывающиеся, несмотря на все усилия

Посмотрите на график ниже: enter image description here

Это подзадача этой более крупной фигуры: enter image description here

Я вижу две проблемы с ним. Во-первых, метки оси x перекрываются друг с другом (это моя главная проблема). Во-вторых. расположение небольших линий сетки оси x кажется немного неустойчивым. Слева от графика они выглядят правильно разнесенными. Но справа они, похоже, переполняют основные линии сетки... как будто основные местоположения сетки не являются подходящими кратными небольшим местоположениям тика.

Моя настройка заключается в том, что у меня есть DataFrame с именем df, который имеет DatetimeIndex в строках и столбец с именем value, который содержит поплавки. В случае необходимости я могу привести пример содержимого df. Около дюжины строк df находятся в нижней части этого сообщения для справки.

Здесь код, который создает рисунок:

now = dt.datetime.now()

fig, axes = plt.subplots(2, 2, figsize=(15, 8), dpi=200)
for i, d in enumerate([360, 30, 7, 1]):
    ax = axes.flatten()[i]
    earlycut = now - relativedelta(days=d)
    data = df.loc[df.index>=earlycut, :]
    ax.plot(data.index, data['value'])
    ax.xaxis_date()

    ax.get_xaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())
    ax.get_yaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())

    ax.grid(b=True, which='major', color='w', linewidth=1.5)
    ax.grid(b=True, which='minor', color='w', linewidth=0.75)

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

Я нахожусь на Pandas 0.13.1, numpy 1.8.0 и matplotlib 1.4.x.

Вот небольшой фрагмент df для справки:

                                    id scale  tempseries_id    value
timestamp                                                           
2014-11-02 14:45:10.302204+00:00  7564     F              1  68.0000
2014-11-02 14:25:13.532391+00:00  7563     F              1  68.5616
2014-11-02 14:15:12.102229+00:00  7562     F              1  68.9000
2014-11-02 14:05:13.252371+00:00  7561     F              1  69.0116
2014-11-02 13:55:11.792191+00:00  7560     F              1  68.7866
2014-11-02 13:45:10.782227+00:00  7559     F              1  68.6750
2014-11-02 13:35:10.972248+00:00  7558     F              1  68.4500
2014-11-02 13:25:10.362213+00:00  7557     F              1  68.1116
2014-11-02 13:15:10.822247+00:00  7556     F              1  68.2250
2014-11-02 13:05:10.102200+00:00  7555     F              1  68.5616
2014-11-02 12:55:10.292217+00:00  7554     F              1  69.0116
2014-11-02 12:45:10.382226+00:00  7553     F              1  69.3500
2014-11-02 12:35:10.642245+00:00  7552     F              1  69.2366
2014-11-02 12:25:12.642255+00:00  7551     F              1  69.1250
2014-11-02 12:15:11.122382+00:00  7550     F              1  68.7866
2014-11-02 12:05:11.332224+00:00  7549     F              1  68.5616
2014-11-02 11:55:11.662311+00:00  7548     F              1  68.2250
2014-11-02 11:45:11.122193+00:00  7547     F              1  68.4500
2014-11-02 11:35:11.162271+00:00  7546     F              1  68.7866
2014-11-02 11:25:12.102211+00:00  7545     F              1  69.2366
2014-11-02 11:15:10.422226+00:00  7544     F              1  69.4616
2014-11-02 11:05:11.412216+00:00  7543     F              1  69.3500
2014-11-02 10:55:10.772212+00:00  7542     F              1  69.1250
2014-11-02 10:45:11.332220+00:00  7541     F              1  68.7866
2014-11-02 10:35:11.332232+00:00  7540     F              1  68.5616
2014-11-02 10:25:11.202411+00:00  7539     F              1  68.2250
2014-11-02 10:15:11.932326+00:00  7538     F              1  68.5616
2014-11-02 10:05:10.922229+00:00  7537     F              1  68.9000
2014-11-02 09:55:11.602357+00:00  7536     F              1  69.3500

Изменить: Попытка fig.autofmt_xdate(): Я не думаю, что это будет делать трюк. Кажется, что эти же метки x-tick используются для обоих графиков слева, а также для обоих графиков справа. Это неверно, учитывая мои данные. См. Проблемный вывод ниже:

enter image description here

Ответ 1

Хорошо, наконец, он работает. Хитрость заключалась в том, чтобы использовать plt.setp для ручного поворота меток тика. Использование fig.autofmt_xdate() не работало, так как оно вызывает некоторые неожиданные вещи, когда на вашей фигуре имеется несколько подзаговоров. Здесь рабочий код с его выходом:

for i, d in enumerate([360, 30, 7, 1]):
    ax = axes.flatten()[i]
    earlycut = now - relativedelta(days=d)
    data = df.loc[df.index>=earlycut, :]
    ax.plot(data.index, data['value'])

    ax.get_xaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())
    ax.get_yaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())

    ax.grid(b=True, which='major', color='w', linewidth=1.5)
    ax.grid(b=True, which='minor', color='w', linewidth=0.75)

    plt.setp(ax.get_xticklabels(), rotation=30, horizontalalignment='right')

fig.tight_layout()

enter image description here

Кстати, комментарий ранее о некоторых вещах matplotlib, занимающих навсегда, очень интересен здесь. Я использую малиновый пи, чтобы действовать как метеостанция в отдаленном месте. Он собирает данные и обслуживает результаты через Интернет. И мальчик, мальчик, он действительно хрипит, пытаясь выпустить эту графику.

Ответ 2

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

Поэтому лучше всего поворачивать ярлыки ярлыков. Поскольку даты чаще всего имеют эту проблему, существует метод fig.autofmt_xdate(), который будет (среди прочего) вращать метки тика, чтобы сделать их более читаемыми. (Примечание. Если вы используете метод pandas plot, он возвращает объект осей, поэтому вам нужно использовать ax.figure.autofmt_xdate().)

В качестве быстрого примера:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

time = pd.date_range('01/01/2014', '4/01/2014', freq='H')
values = np.random.normal(0, 1, time.size).cumsum()

fig, ax = plt.subplots()
ax.plot_date(time, values, marker='', linestyle='-')

fig.autofmt_xdate()
plt.show()

Если мы выйдем из fig.autofmt_xdate() out:

enter image description here

И если мы используем fig.autofmt_xdate():

enter image description here