Изменение "частоты тиков" на оси x или y в matplotlib?

Я пытаюсь исправить, как Python отображает мои данные.

Сказать

x = [0,5,9,10,15]

а также

y = [0,1,2,3,4]

Тогда я бы сделал:

matplotlib.pyplot.plot(x,y)
matplotlib.pyplot.show()

и отметки по оси x нанесены с интервалами 5. Можно ли сделать так, чтобы интервалы показывали 1?

14 ответов

Решение

Вы можете явно указать, где вы хотите отметить plt.xticks:

plt.xticks(np.arange(min(x), max(x)+1, 1.0))

Например,

import numpy as np
import matplotlib.pyplot as plt

x = [0,5,9,10,15]
y = [0,1,2,3,4]
plt.plot(x,y)
plt.xticks(np.arange(min(x), max(x)+1, 1.0))
plt.show()

(np.arange был использован, а не Python range функционировать на всякий случай min(x) а также max(x) являются поплавками вместо целых.)


plt.plot (или же ax.plot) функция автоматически установит значение по умолчанию x а также y пределы. Если вы хотите сохранить эти ограничения и просто изменить размер шага отметок, то вы можете использовать ax.get_xlim() чтобы узнать, какие ограничения уже установлены Matplotlib.

start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, stepsize))

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

ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))

Вот работающий пример:

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

x = [0,5,9,10,15]
y = [0,1,2,3,4]
fig, ax = plt.subplots()
ax.plot(x,y)
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, 0.712123))
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))
plt.show()

Другой подход заключается в установке локатора оси:

import matplotlib.ticker as plticker

loc = plticker.MultipleLocator(base=1.0) # this locator puts ticks at regular intervals
ax.xaxis.set_major_locator(loc)

Есть несколько различных типов локатора в зависимости от ваших потребностей.

Мне нравится это решение (из книги рецептов Matplotlib Plotting):

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

x = [0,5,9,10,15]
y = [0,1,2,3,4]

tick_spacing = 1

fig, ax = plt.subplots(1,1)
ax.plot(x,y)
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
plt.show()

Это решение дает вам явный контроль расстояния между тиками через число ticker.MultipleLocater(), позволяет автоматически определять лимит и легко читается позже.

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

ax.set_xticks(ax.get_xticks()[::2])

Если вы просто хотите установить интервал, простой одинарный вкладыш с минимальным шаблоном:

plt.gca().xaxis.set_major_locator(plt.MultipleLocator(1))

также легко работает для мелких тиков:

plt.gca().xaxis.set_minor_locator(plt.MultipleLocator(1))

немного полный, но довольно компактный

Это немного хакерский, но, безусловно, самый чистый / легкий для понимания пример, который я нашел для этого. Это из ответа на SO здесь:

Самый простой способ скрыть каждую метку nth в цветовой панели matplotlib?

for label in ax.get_xticklabels()[::2]:
    label.set_visible(False)

Затем вы можете зациклить надписи, устанавливая их видимыми или нет в зависимости от плотности, которую вы хотите.

редактировать: обратите внимание, что иногда matplotlib устанавливает метки == '', так что может показаться, что метка отсутствует, хотя на самом деле она есть и просто ничего не отображает. Чтобы убедиться, что вы просматриваете фактические видимые метки, вы можете попробовать:

visible_labels = [lab for lab in ax.get_xticklabels() if lab.get_visible() is True and lab.get_text() != '']
plt.setp(visible_labels[::2], visible=False)

Это старая тема, но я спотыкаюсь об этом время от времени и сделал эту функцию. Это очень удобно:

import matplotlib.pyplot as pp
import numpy as np

def resadjust(ax, xres=None, yres=None):
    """
    Send in an axis and I fix the resolution as desired.
    """

    if xres:
        start, stop = ax.get_xlim()
        ticks = np.arange(start, stop + xres, xres)
        ax.set_xticks(ticks)
    if yres:
        start, stop = ax.get_ylim()
        ticks = np.arange(start, stop + yres, yres)
        ax.set_yticks(ticks)

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

gca().set_ylim(top=new_top) # for example

и снова запустите функцию перенастройки.

Я разработал не элегантное решение. Учтите, что у нас есть ось X, а также список меток для каждой точки в X.

Пример:
import matplotlib.pyplot as plt

x = [0,1,2,3,4,5]
y = [10,20,15,18,7,19]
xlabels = ['jan','feb','mar','apr','may','jun']
Допустим, я хочу показывать метки только для 'feb' и 'jun'
xlabelsnew = []
for i in xlabels:
    if i not in ['feb','jun']:
        i = ' '
        xlabelsnew.append(i)
    else:
        xlabelsnew.append(i)
Хорошо, теперь у нас есть поддельный список ярлыков. Сначала мы подготовили оригинальную версию.
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabels,rotation=45)
plt.show()
Теперь модифицированная версия.
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabelsnew,rotation=45)
plt.show()

Вот чистая реализация Python желаемой функциональности, которая обрабатывает любой числовой ряд (int или float) с положительными, отрицательными или смешанными значениями:

def computeTicks (x, step = 5):
    """
    Computes domain with given step encompassing series x
    @ params
    x    - Required - A list-like object of integers or floats
    step - Optional - Tick frequency
    """
    import math as Math
    xMax, xMin = Math.ceil(max(x)), Math.floor(min(x))
    dMax, dMin = xMax + abs((xMax % step) - step) + (step if (xMax % step != 0) else 0), xMin - abs((xMin % step))
    return range(dMin, dMax, step)

Пример вывода:

# Negative to Positive
series = [-2, 18, 24, 29, 43]
print(list(computeTicks(series)))

[-5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45]

# Negative to 0
series = [-30, -14, -10, -9, -3, 0]
print(list(computeTicks(series)))

[-30, -25, -20, -15, -10, -5, 0]

# 0 to Positive
series = [19, 23, 24, 27]
print(list(computeTicks(series)))

[15, 20, 25, 30]

# Floats
series = [1.8, 12.0, 21.2]
print(list(computeTicks(series)))

[0, 5, 10, 15, 20, 25]

# Step – 100
series = [118.3, 293.2, 768.1]
print(list(computeTicks(series, step = 100)))

[100, 200, 300, 400, 500, 600, 700, 800]

И образец использования:

import matplotlib.pyplot as plt

x = [0,5,9,10,15]
y = [0,1,2,3,4]
plt.plot(x,y)
plt.xticks(computeTicks(x))
plt.show()

Обобщение одного лайнера с импортированным только Numpy:

      import numpy as np
ax.set_xticks(np.arange(min(ax.get_xticks()),max(ax.get_xticks()),1));

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

Вот образец кода, который создает беспорядочные отметки на обоих X а также Y топоры.

# Note the super cluttered ticks on both X and Y axis.

# inputs
x = np.arange(1, 101)
y = x * np.log(x) 

fig = plt.figure()     # create figure
ax = fig.add_subplot(111)
ax.plot(x, y)
ax.set_xticks(x)        # set xtick values
ax.set_yticks(y)        # set ytick values

plt.show()

Теперь мы убираем беспорядок с помощью нового графика, который показывает только разреженный набор значений по осям x и y в виде отметок.

# inputs
x = np.arange(1, 101)
y = x * np.log(x)

fig = plt.figure()       # create figure
ax = fig.add_subplot(111)
ax.plot(x, y)

ax.set_xticks(x)
ax.set_yticks(y)

# which values need to be shown?
# here, we show every third value from `x` and `y`
show_every = 3

sparse_xticks = [None] * x.shape[0]
sparse_xticks[::show_every] = x[::show_every]

sparse_yticks = [None] * y.shape[0]
sparse_yticks[::show_every] = y[::show_every]

ax.set_xticklabels(sparse_xticks, fontsize=6)   # set sparse xtick values
ax.set_yticklabels(sparse_yticks, fontsize=6)   # set sparse ytick values

plt.show()

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

Если это решение на основе шага не подходит, то можно также заполнить значения sparse_xticks или sparse_yticks через нерегулярные промежутки времени, если это то, что желательно.

xmarks=[i for i in range(1,length+1,1)]

plt.xticks(xmarks)

Это сработало для меня

если вы хотите, чтобы тики между [1,5] (1 и 5 включительно), то замените

length = 5

Если вам нужно изменить частоту меток вместе с частотой тиков, используя старые метки, используйтеset_xticksиset_xticklabelsодин за другим выдает ValueError, который выглядит следующим образом:

      ValueError: The number of FixedLocator locations (5), usually from 
a call to set_ticks, does not match the number of labels (3).

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

      import pandas as pd
ax = pd.Series(range(20), index=pd.date_range('2020', '2024', 20).date).plot()
ax.set_xticks(ax.get_xticks()[::2])             # <---- error   
ax.set_xticklabels(ax.get_xticklabels()[::2]);  # <---- error


ax = pd.Series(range(20), index=pd.date_range('2020', '2024', 20).date).plot()
ax.set(xticks=ax.get_xticks()[::2], 
       xticklabels=ax.get_xticklabels()[::2]);  # <---- OK


Для этого конкретного случая matplotlib.dates.YearLocatorи matplotlib.dates.DateFormatterявляется более гибким (например, ax.xaxis.set_major_locator(matplotlib.dates.YearLocator())) и, вероятно, является предпочтительным способом установки галочек, но сообщение выше предлагает быстрое исправление распространенной ошибки.

Вы можете просмотреть ярлыки и показать или скрыть те, которые вы хотите:

         for i, label in enumerate(ax.get_xticklabels()):
        if i % interval != 0:
            label.set_visible(False)
Другие вопросы по тегам