Changer la "fréquence des ticks" sur l'axe x ou y dans matplotlib?


477

J'essaie de corriger la façon dont python trace mes données.

Dire

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

et

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

Ensuite, je ferais:

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

et les graduations de l'axe x sont tracées à des intervalles de 5. Existe-t-il un moyen de lui faire afficher des intervalles de 1?


6
Bien que tiques soit le mot approprié ici, changer les tiques en taille de pas guidera certainement plus de débutants à cette question.
Sibbs Gambling

9
Question étroitement liée: stackoverflow.com/questions/6682784/… et une excellente solution:pyplot.locator_params(nbins=4)
Dr Jan-Philip Gehrcke

nbins semble avoir été déprécié dans matplotlib2.x, malheureusement
jeremy_rutman

Réponses:


584

Vous pouvez définir explicitement où vous souhaitez cocher les marques avec plt.xticks:

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

Par exemple,

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

(a np.arangeété utilisé plutôt que la rangefonction de Python juste au cas où min(x)et max(x)sont des flottants au lieu d'ints.)


La fonction plt.plot(ou ax.plot) définira automatiquement les valeurs par défaut xet les ylimites. Si vous souhaitez conserver ces limites et simplement modifier la taille des pas des graduations, vous pouvez utiliser ax.get_xlim()pour découvrir quelles limites Matplotlib a déjà définies.

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

Le formateur de tick par défaut devrait faire un travail décent en arrondissant les valeurs de tick à un nombre sensible de chiffres significatifs. Cependant, si vous souhaitez avoir plus de contrôle sur le format, vous pouvez définir votre propre formateur. Par exemple,

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

Voici un exemple exécutable:

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

72
N'y a-t-il aucun moyen de lui faire décider de ses propres limites, mais simplement de changer la taille du pas? Cette méthode n'est pas très bonne si le min est quelque chose comme 3523.232512!
Korone

3
@Corone, Cela fait longtemps que vous ne l'avez pas demandé, mais j'ai posté une réponse ci-dessous qui permet un contrôle facile de la taille des pas tout en utilisant la détermination automatique des limites.
jthomas

3
Notez que l' +1entrée plt.xticks(np.arange(min(x), max(x)+1, 1.0))est requise pour afficher la dernière coche.
Alex Willison

1
Oui, np.arange(start, stop)génère des valeurs dans l' intervalle semi-ouvert[start, stop) , incluant startmais excluant stop. J'ai donc l'habitude max(x)+1de m'assurer que cela max(x)est inclus.
unutbu

4
y a-t-il un équivalent pour datetime par exemple plt.xticks(np.arange(min(dates), max(dates)+0.1,0.1)? il ne semble que tracer l'année
WBM

207

Une autre approche consiste à définir le localisateur d'axe:

import matplotlib.ticker as plticker

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

Il existe plusieurs types de localisateurs selon vos besoins.

Voici un exemple complet:

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

7
Cela ne fonctionne pas comme prévu. Plus précisément, lors de l'utilisation de dates, il n'utilise pas les dates appropriées.
Chris Fonnesbeck

35
Lorsque vous utilisez des dates, vous devez utiliser les méthodes du module matplotlib.dates. Par exemplematplotlib.dates.AutoDateLocator()
robochat

3
Cela a fonctionné comme prévu pour moi, avec des dates. Cette solution est beaucoup plus simple que la solution acceptée.
Pablo Suau

Que base=1.0signifie / fait réellement?
javadba

base = 1.0 signifie qu'il y aura un localisateur pour chaque nombre entier. La documentation indique que MultipleLocator "Définit [s] une coche sur chaque multiple entier d'une base dans l'intervalle d'affichage.". Donc, si base = 2, il y aura une coche pour les nombres pairs et je pense que vous pourriez mettre base = 2,5.
robochat

124

J'aime cette solution (tirée du livre de recettes de traçage Matplotlib ):

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

Cette solution vous donne un contrôle explicite de l'espacement des graduations via le nombre donné à ticker.MultipleLocater(), permet une détermination automatique des limites et est facile à lire plus tard.


3
Un moyen de le faire sans calculer explicitement les ticks!
Zelphir Kaltstahl

4
C'est la même réponse que celle-ci . Il n'est pas logique d'ajouter une réponse identique deux ans plus tard.
ImportanceOfBeingErnest

6
Bonne prise. Je ne les ai pas reconnus comme identiques lorsque j'ai posté la réponse. Pourtant, je pense que cette présentation est un peu plus facile à comprendre.
jthomas

La référence du livre dans cette réponse fournit également une source utile pour plus d'informations.
Steven C. Howell

1
C'est la même réponse que celle de robochat, qui est arrivée trois ans plus tôt.
MERose

90

Dans le cas où quelqu'un est intéressé par un one-liner général, obtenez simplement les ticks actuels et utilisez-le pour définir les nouveaux ticks en échantillonnant tous les autres ticks.

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

3
C'est la seule réponse généralisable pour différents types de ticks (str, float, datetime)
Ryszard Cetnarski

2
Supprimer les ax.set_xticks([tick for tick in ax.get_xticks() if tick % 1 == 0])
graduations

Beaucoup de solutions détaillées ci-dessus mais je conviens que c'est la plus concise. Vous pouvez même extraire la longueur de ax.get_xticks () et définir la fréquence de découpage par cette longueur divisée par le nombre de ticks requis.
Iain D

Je pense que c'est la meilleure réponse. La plupart des autres réponses sont trop compliquées et difficiles à appliquer / généraliser. Je vous remercie!
Seankala

2
Cela ne peut que réduire le nombre de bâtons, alors que dans la question (et mon objectif, comment je l'ai trouvé), c'était de l'augmenter.
Alexei Martianov

36

C'est un peu hacky, mais de loin l'exemple le plus propre / le plus facile à comprendre que j'ai trouvé pour le faire. C'est à partir d'une réponse sur SO ici:

Le moyen le plus propre de masquer chaque étiquette de nième tique dans la barre de couleurs matplotlib?

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

Ensuite, vous pouvez parcourir les étiquettes en les définissant sur visibles ou non en fonction de la densité souhaitée.

edit: notez que parfois matplotlib définit les étiquettes == '', il peut donc sembler qu'une étiquette n'est pas présente, alors qu'en fait elle n'affiche rien. Pour vous assurer que vous parcourez les étiquettes visibles réelles, vous pouvez essayer:

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)

3
Il s'agit de la solution la plus simple et générique. Un petit ajustement: ce ax.get_xticklabels()[1::2]sont généralement les étiquettes à cacher.
jolvi

Cela ne fonctionne pas avec matplotlib.finance.candlestick2
BCR

@BCR il se pourrait que certains des xticklabels soient juste définis de ''sorte que lorsque vous les parcourez, vous faites des xticklabels qui sont vides et invisibles (ce qui n'aurait aucun effet sur la visualisation, mais pourrait signifier que vous ne tirez pas les bonnes étiquettes). Vous pouvez essayer: vis_labels = [label for label in ax.get_xticklabels() if label.get_visible() is True]; plt.setp(vis_labels[::2], visible==False)
choldgraf le

15

C'est un vieux sujet, mais je tombe dessus de temps en temps et j'ai fait cette fonction. C'est très pratique:

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)

Une mise en garde de contrôler les tiques comme ceci est que l'on ne profite plus de la mise à jour automagique interactive de l'échelle maximale après une ligne ajoutée. Alors fais

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

et exécutez à nouveau la fonction de réajustement.


11

J'ai développé une solution inélégante. Considérez que nous avons l'axe X et également une liste d'étiquettes pour chaque point dans X.

Exemple:
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']
Disons que je veux afficher les étiquettes des ticks uniquement pour 'feb' et 'jun'
xlabelsnew = []
for i in xlabels:
    if i not in ['feb','jun']:
        i = ' '
        xlabelsnew.append(i)
    else:
        xlabelsnew.append(i)
Bon, maintenant nous avons une fausse liste d'étiquettes. Tout d'abord, nous avons tracé la version originale.
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabels,rotation=45)
plt.show()
Maintenant, la version modifiée.
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabelsnew,rotation=45)
plt.show()

6

si vous voulez juste définir l'espacement d'une simple doublure avec un passe-partout minimal:

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

fonctionne également facilement pour les tiques mineures:

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

un peu plein, mais assez compact


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

plt.xticks(xmarks)

Cela a fonctionné pour moi

si vous voulez des ticks entre [1,5] (1 et 5 inclus) alors remplacez

length = 5

1
fyi, vous pourriez simplement écrire xmarks = range(1, length+1, 1). à peu près sûr que la compréhension de la liste est redondante.
Neal

2

Implémentation Pure Python

Ci-dessous, une implémentation en python pur de la fonctionnalité souhaitée qui gère toute série numérique (int ou float) avec des valeurs positives, négatives ou mixtes et permet à l'utilisateur de spécifier la taille d'étape souhaitée:

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)

Exemple de sortie

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

Exemple d'utilisation

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

Graphique d'utilisation de l'échantillon

Notez que l'axe des x a des valeurs entières toutes espacées de façon égale par 5, tandis que l'axe des y a un intervalle différent (le matplotlibcomportement par défaut, car les graduations n'étaient pas spécifiées).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.