Zmieniasz „częstotliwość tyknięcia” na osi x lub y w Matplotlib?

477

Próbuję naprawić sposób, w jaki Python drukuje moje dane.

Mówić

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

i

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

Potem zrobiłbym:

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

a tyknięcia na osi x są wykreślane w odstępach 5. Czy istnieje sposób, aby pokazywał odstępy 1?

Dax Feliz
źródło
6
Chociaż tiki są tutaj odpowiednim słowem, zmiana tików na rozmiar kroku z pewnością poprowadzi nowych początkujących do tego pytania.
Sibbs Gambling
9
Ściśle powiązane pytanie: stackoverflow.com/questions/6682784/... i świetne rozwiązanie:pyplot.locator_params(nbins=4)
Dr Jan-Philip Gehrcke
nbins wydaje się być przestarzałe w matplotlib2.x, niestety
jeremy_rutman

Odpowiedzi:

583

Możesz jawnie ustawić miejsce, w którym chcesz zaznaczyć znaczniki plt.xticks:

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

Na przykład,

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.arangezostał użyty zamiast rangefunkcji Pythona na wszelki wypadek min(x)i max(x)są zmiennoprzecinkowe zamiast ints.)


Funkcja plt.plot(lub ax.plot) automatycznie ustawi domyślne xi ylimity. Jeśli chcesz zachować te limity i po prostu zmienić rozmiar znaczników, możesz użyć, ax.get_xlim()aby dowiedzieć się, jakie limity Matplotlib już ustawił.

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

Domyślny formatyzator tików powinien wykonać przyzwoitą robotę zaokrąglając wartości tików do rozsądnej liczby cyfr znaczących. Jeśli jednak chcesz mieć większą kontrolę nad formatem, możesz zdefiniować własny formatyzator. Na przykład,

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

Oto możliwy do uruchomienia przykład:

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()
unutbu
źródło
72
Czy nie ma sposobu, aby nadal decydować o własnych limitach, ale po prostu zmienić rozmiar kroku? Ta metoda nie jest zbyt dobra, jeśli min ma wartość 3523.232512!
Korone
3
@Coreone, minęło trochę czasu, odkąd zapytałeś, ale zamieściłem poniżej odpowiedź, która pozwala na łatwą kontrolę wielkości kroku, nadal korzystając z automatycznego określania granic.
jthomas
3
Pamiętaj, że znak +1in plt.xticks(np.arange(min(x), max(x)+1, 1.0))jest wymagany, aby pokazać ostatni znacznik wyboru.
Alex Willison
1
Tak, np.arange(start, stop)generuje wartości w przedziale półotwartym[start, stop) , w tym, startale wykluczając stop. Więc kiedyś max(x)+1upewniałem się, że max(x)to jest uwzględnione.
unutbu
4
czy istnieje odpowiednik datetime np. plt.xticks(np.arange(min(dates), max(dates)+0.1,0.1)? wydaje się, że rysuje tylko rok
WBM
207

Innym podejściem jest ustawienie lokalizatora osi:

import matplotlib.ticker as plticker

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

Istnieje kilka różnych rodzajów lokalizatora w zależności od potrzeb.

Oto pełny przykład:

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

x = [0,5,9,10,15]
y = [0,1,2,3,4]
fig, ax = plt.subplots()
ax.plot(x,y)
loc = plticker.MultipleLocator(base=1.0) # this locator puts ticks at regular intervals
ax.xaxis.set_major_locator(loc)
plt.show()
robochat
źródło
7
To nie działa zgodnie z oczekiwaniami. W szczególności podczas korzystania z dat nie używa odpowiednich dat.
Chris Fonnesbeck
35
Korzystając z dat, powinieneś użyć metod z modułu matplotlib.dates. Na przykładmatplotlib.dates.AutoDateLocator()
robochat
3
Działa zgodnie z oczekiwaniami, z datami. To rozwiązanie jest znacznie łatwiejsze niż przyjęte.
Pablo Suau
Co tak base=1.0naprawdę oznacza / robi?
javadba
base = 1.0 oznacza, że ​​dla każdej liczby całkowitej znajdzie się lokalizator. Dokumentacja mówi, że MultipleLocator „Ustaw zaznaczenie na każdej liczbie całkowitej wielokrotności podstawy w interwale wyświetlania”. Więc jeśli base = 2, to będzie znacznik dla liczb parzystych i myślę, że możesz umieścić event base = 2.5.
robochat
124

Podoba mi się to rozwiązanie (z Matplotlib Plotting Cookbook ):

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

To rozwiązanie daje ci wyraźną kontrolę odstępów między tyknięciami za pomocą podanej liczby ticker.MultipleLocater(), pozwala na automatyczne określenie limitu i jest łatwe do odczytania później.

jthomas
źródło
3
Sposób na zrobienie tego bez jawnego obliczania tyknięć!
Zelphir Kaltstahl
4
To jest ta sama odpowiedź, co ta . Dodanie identycznej odpowiedzi dwa lata później nie ma sensu.
ImportanceOfBeingErnest
6
Dobry chwyt Nie rozpoznałem ich jako takich samych, kiedy opublikowałem odpowiedź. Myślę jednak, że ta prezentacja jest nieco łatwiejsza do zrozumienia.
jthomas
Odwołanie do książki w tej odpowiedzi stanowi również pomocne źródło dodatkowych informacji.
Steven C. Howell,
1
To ta sama odpowiedź, co robochata, który pojawił się trzy lata wcześniej.
MERose
90

W przypadku, gdy ktoś jest zainteresowany ogólną linią pojedynczą, po prostu pobierz bieżące tiki i użyj go do ustawienia nowych tików, próbkując co drugi tik.

ax.set_xticks(ax.get_xticks()[::2])
glopes
źródło
3
To jedyna możliwa do uogólnienia odpowiedź na różne typy tików (str, float, datetime)
Ryszard Cetnarski,
2
Usuń znaczniki nie będące liczbami całkowitymi: ax.set_xticks([tick for tick in ax.get_xticks() if tick % 1 == 0])
user2839288
Wiele szczegółowych rozwiązań powyżej, ale zgadzam się, że jest to najbardziej zwięzłe. Możesz nawet wyodrębnić długość ax.get_xticks () i ustawić częstotliwość krojenia przez tę długość podzieloną przez liczbę wymaganych tyknięć.
Iain D
Myślę, że to najlepsza odpowiedź. Większość innych odpowiedzi jest zbyt skomplikowana i trudna do zastosowania / uogólnienia. Dziękuję Ci!
Seankala
2
Może jedynie zmniejszyć liczbę drążków, podczas gdy w pytaniu (i moim celem jak to znalazłem) było zwiększenie.
Aleksiej Martianow
36

Jest to nieco zuchwałe, ale zdecydowanie najczystszy / najłatwiejszy do zrozumienia przykład, jaki to zrobiłem. Oto odpowiedź na SO tutaj:

Najczystszy sposób na ukrycie każdej n-tej etykiety kleszczowej w pasku kolorów Matplotlib?

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

Następnie możesz zapętlić etykiety, ustawiając je na widoczne lub nie, w zależności od żądanej gęstości.

edit: zauważ, że czasami matplotlib ustawia etykiety == '', więc może wyglądać na to, że etykieta nie jest obecna, podczas gdy w rzeczywistości jest i po prostu nic nie wyświetla. Aby mieć pewność, że przeglądasz rzeczywiste widoczne etykiety, możesz spróbować:

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)
choldgraf
źródło
3
To jest najprostsze i ogólne rozwiązanie. Drobna korekta: zazwyczaj ax.get_xticklabels()[1::2]etykiety należy ukryć.
jolvi
To nie działa z matplotlib.finance.candlestick2
BCR
@BCR może być tak, że niektóre xticklabels są właśnie ustawione ''tak, że kiedy je zapętlasz, robisz xticklabels, które są puste niewidoczne (co nie miałoby wpływu na wizualizację, ale może oznaczać, że nie ciągniesz prawidłowe etykiety). Możesz spróbować: vis_labels = [label for label in ax.get_xticklabels() if label.get_visible() is True]; plt.setp(vis_labels[::2], visible==False)
choldgraf
15

To jest stary temat, ale od czasu do czasu potykam się o to i stworzyłem tę funkcję. To bardzo wygodne:

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)

Jednym z ostrzeżeń związanych z kontrolowaniem taktów jest to, że nie cieszy się już interaktywną automatyczną aktualizacją maksymalnej skali po dodaniu linii. Więc zrób

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

i ponownie uruchom funkcję resadjust.

Tompa
źródło
11

Opracowałem nieeleganckie rozwiązanie. Rozważ, że mamy oś X, a także listę etykiet dla każdego punktu w X.

Przykład:
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']
Powiedzmy, że chcę pokazywać etykiety z kleszczami tylko dla „feb” i „Jun”
xlabelsnew = []
for i in xlabels:
    if i not in ['feb','jun']:
        i = ' '
        xlabelsnew.append(i)
    else:
        xlabelsnew.append(i)
Dobrze, teraz mamy fałszywą listę etykiet. Najpierw nakreśliliśmy oryginalną wersję.
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabels,rotation=45)
plt.show()
Teraz zmodyfikowana wersja.
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabelsnew,rotation=45)
plt.show()
Deninhos
źródło
6

jeśli chcesz tylko ustawić odstęp prostą wkładką z minimalną płytą grzewczą:

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

działa również łatwo w przypadku drobnych kleszczy:

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

trochę kęs, ale dość kompaktowy

Gary Steele
źródło
2
xmarks=[i for i in range(1,length+1,1)]

plt.xticks(xmarks)

To zadziałało dla mnie

jeśli chcesz zaznaczyć od [1,5] (od 1 do 5 włącznie), zamień

length = 5
Piyush Gupta
źródło
1
fyi, możesz po prostu pisać xmarks = range(1, length+1, 1). całkiem pewne, że lista jest zbędna.
Neal
2

Implementacja Pure Python

Poniżej znajduje się czysta implementacja żądanej funkcjonalności w języku Python, która obsługuje dowolne szeregi liczbowe (int lub float) o wartościach dodatnich, ujemnych lub mieszanych i pozwala użytkownikowi określić żądany rozmiar kroku:

import math

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

Przykładowe dane wyjściowe

# 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]

Przykładowe użycie

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

Wykres użycia próbki

Zauważ, że oś x ma wartości całkowite równomiernie rozmieszczone o 5, podczas gdy oś y ma inny przedział ( matplotlibzachowanie domyślne, ponieważ tiki nie zostały określone).

Greenstick
źródło