Modifier le texte de l'étiquette de coche

216

Je souhaite apporter quelques modifications à quelques étiquettes de tick sélectionnées dans un tracé.

Par exemple, si je le fais:

label = axes.yaxis.get_major_ticks()[2].label
label.set_fontsize(size)
label.set_rotation('vertical')

la taille de la police et l'orientation de l'étiquette à cocher sont modifiées.

Cependant, si essayez:

label.set_text('Foo')

l'étiquette de coche n'est pas modifiée. Aussi si je le fais:

print label.get_text()

rien n'est imprimé.

Voici un peu plus d'étrangeté. Quand j'ai essayé ceci:

 from pylab import *
 axes = figure().add_subplot(111)
 t = arange(0.0, 2.0, 0.01)
 s = sin(2*pi*t)
 axes.plot(t, s)
 for ticklabel in axes.get_xticklabels():
     print ticklabel.get_text()

Seules les chaînes vides sont imprimées, mais le tracé contient des graduations intitulées «0,0», «0,5», «1,0», «1,5» et «2,0».

repoman
la source
Pouvez-vous fournir l'intrigue que vous avez utilisée pour obtenir l'étiquette?
Claudio
Vous obtenez des étiquettes vierges car vous n'avez pas encore dessiné la toile. Si vous appelez draw()avant d'essayer d'imprimer les étiquettes, vous obtiendrez ce que vous attendez. Définir des étiquettes de tick individuelles est malheureusement un peu plus difficile (ce qui se passe, c'est que le localisateur de ticks et le formateur n'ont pas été réinitialisés et qu'il remplace les choses quand vous set_text) J'ajouterai un exemple dans un instant, si quelqu'un ne me bat pas. Mais je dois prendre le bus pour le moment.
Joe Kington
@JoeKington: Super! Au plaisir de voir votre solution.
repoman
@repoman - Eh bien, il semble que j'ai parlé trop tôt. Ce que j'avais en tête fonctionne pour les anciennes versions de matplotlib, mais pas pour la dernière version. J'ai besoin de creuser un peu plus. Cela dit, cela ne devrait pas être aussi compliqué que ça ...
Joe Kington

Réponses:

298

Mise en garde: à moins que les ticklabels soient déjà définis sur une chaîne (comme c'est généralement le cas par exemple dans un boxplot), cela ne fonctionnera pas avec une version de matplotlib plus récente que 1.1.0. Si vous travaillez avec le maître github actuel, cela ne fonctionnera pas. Je ne sais pas encore quel est le problème ... Ce peut être un changement involontaire, ou ce peut ne pas être ...

Normalement, vous feriez quelque chose dans ce sens:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

# We need to draw the canvas, otherwise the labels won't be positioned and 
# won't have values yet.
fig.canvas.draw()

labels = [item.get_text() for item in ax.get_xticklabels()]
labels[1] = 'Testing'

ax.set_xticklabels(labels)

plt.show()

entrez la description de l'image ici

Pour comprendre la raison pour laquelle vous devez sauter à travers tant de cerceaux, vous devez comprendre un peu plus la structure de matplotlib.

Matplotlib évite délibérément de faire un positionnement "statique" des tiques, etc., à moins que cela ne soit explicitement demandé. L'hypothèse est que vous voudrez interagir avec l'intrigue, et donc les limites de l'intrigue, les ticks, les ticklabels, etc. changeront dynamiquement.

Par conséquent, vous ne pouvez pas simplement définir le texte d'une étiquette de tick donnée. Par défaut, il est réinitialisé par le localisateur et le formateur de l'axe chaque fois que le tracé est tracé.

Cependant, si les localisateurs et les formateurs sont définis pour être statiques ( FixedLocatoret FixedFormatter, respectivement), les étiquettes de graduation restent les mêmes.

C'est ce set_*ticklabelsou ax.*axis.set_ticklabelsfait.

J'espère que cela explique un peu plus clairement pourquoi changer une étiquette de tique individuelle est un peu compliqué.

Souvent, ce que vous voulez réellement faire, c'est simplement annoter une certaine position. Dans ce cas, regardez annotateplutôt.

Joe Kington
la source
10
cela ne semble pas fonctionner avec la version actuelle (1.20)!
Andrew Jaffe
1
Si les ticklabels sont déjà définis sur une chaîne comme par exemple dans un boxplot, cela fonctionne toujours. Cela peut être évident, mais comme la première ligne de la réponse est qu'elle ne fonctionne pas sur les versions plus récentes de matplotlib, les utilisateurs peuvent l'ignorer complètement (je l'ai fait initialement). Peut-être le mentionner brièvement.
joelostblom
2
je pense que vous pouvez le condenser en plt.gca (). set_xticklabels (labels)
alexey
que faire si je veux que le poids de police de "testing" soit boldalors que d'autres utilisent le poids de police de "light". Y a-t-il un moyen de le faire?
Steven
1
pour ceux qui l'utilisent dans un cahier jupyter, il peut être utile de noter que fig.canvas.draw()c'est crucial
wander95
96

On peut aussi le faire avec pylab et xticks

import matplotlib
import matplotlib.pyplot as plt
x = [0,1,2]
y = [90,40,65]
labels = ['high', 'low', 37337]
plt.plot(x,y, 'r')
plt.xticks(x, labels, rotation='vertical')
plt.show()

http://matplotlib.org/examples/ticks_and_spines/ticklabels_demo_rotation.html

rafaelvalle
la source
Il s'agit d'une solution simple qui fonctionne avec pyplot 1.5.1. Cela devrait être voté.
Wordsmith
Bien que la question ne le demande pas, j'apprécie que cet exemple vous permette de définir l'emplacement des ticks en même temps que de modifier leurs étiquettes.
eclark
D' après les documents modernes de matplotlib : "pylab est obsolète et son utilisation est fortement déconseillée en raison de la pollution de l'espace de noms. Utilisez plutôt pyplot."
Nathaniel Jones
93

Dans les versions plus récentes de matplotlib, si vous ne définissez pas les étiquettes de tick avec un tas de strvaleurs, elles le sont ''par défaut (et lorsque le tracé est tracé, les étiquettes sont simplement les valeurs de ticks). Sachant cela, pour obtenir la sortie souhaitée, il faudrait quelque chose comme ceci:

>>> from pylab import *
>>> axes = figure().add_subplot(111)
>>> a=axes.get_xticks().tolist()
>>> a[1]='change'
>>> axes.set_xticklabels(a)
[<matplotlib.text.Text object at 0x539aa50>, <matplotlib.text.Text object at 0x53a0c90>, 
<matplotlib.text.Text object at 0x53a73d0>, <matplotlib.text.Text object at 0x53a7a50>, 
<matplotlib.text.Text object at 0x53aa110>, <matplotlib.text.Text object at 0x53aa790>]
>>> plt.show()

et le résultat: entrez la description de l'image ici

et maintenant si vous cochez la _xticklabels, ils ne sont plus un tas de ''.

>>> [item.get_text() for item in axes.get_xticklabels()]
['0.0', 'change', '1.0', '1.5', '2.0']

Il fonctionne dans les versions de 1.1.1rc1à la version actuelle 2.0.

CT Zhu
la source
Merci, c'est la réponse que je cherchais. Solution la plus propre OMI; il suffit de fournir set_xticklabelsune liste mixte de chaînes et d'objets tick.
Luke Davis
Sachez que si les étiquettes de graduation sont définies comme des entiers, cela les changera en flottants. Facile à contourner, mais mérite d'être noté.
ApproachingDarknessFish
Celui-ci a fonctionné ( ax.get_xticks().tolist()). La solution la plus votée ne l'a pas été ( ax.get_xtickslabels()). D'une manière ou d'une autre, il n'a pas été en mesure d'extraire les étiquettes avant l' plt.show()excusion, bien que j'aie utilisé fig.canvas.draw()comme suggéré.
CypherX
Pour info, à partir des documents matplotlib modernes : "pylab est obsolète et son utilisation est fortement déconseillée en raison de la pollution de l'espace de noms. Utilisez plutôt pyplot."
Nathaniel Jones
17

Cela fait un moment que cette question n'a pas été posée. À ce jour ( matplotlib 2.2.2) et après quelques lectures et essais, je pense que la meilleure / bonne façon est la suivante:

Matplotlib a un module nommé tickerqui "contient des classes pour prendre en charge la localisation et le formatage des ticks entièrement configurables" . Pour modifier une coche spécifique de l'intrigue, la procédure suivante fonctionne pour moi:

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

def update_ticks(x, pos):
    if x == 0:
        return 'Mean'
    elif pos == 6:
        return 'pos is 6'
    else:
        return x

data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
ax.hist(data, bins=25, edgecolor='black')
ax.xaxis.set_major_formatter(mticker.FuncFormatter(update_ticks))
plt.show()

Histogramme avec des valeurs aléatoires d'une distribution normale

Caveat! xest la valeur de la tique et possa position relative dans l'ordre dans l'axe. Notez que posprend des valeurs commençant par 1, pas 0comme d'habitude lors de l'indexation.


Dans mon cas, j'essayais de formater l' y-axishistogramme avec des valeurs de pourcentage. mtickera une autre classe nommée PercentFormatterqui peut le faire facilement sans avoir besoin de définir une fonction distincte comme précédemment:

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

data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
weights = np.ones_like(data) / len(data)
ax.hist(data, bins=25, weights=weights, edgecolor='black')
ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0, decimals=1))
plt.show()

Histogramme avec des valeurs aléatoires d'une distribution normale

Dans ce cas, xmaxc'est la valeur des données qui correspond à 100%. Les pourcentages sont calculés comme x / xmax * 100, c'est pourquoi nous corrigeons xmax=1.0. Est également decimalsle nombre de décimales à placer après le point.

iipr
la source
12

La classe axes a une fonction set_yticklabels qui vous permet de définir les étiquettes de tick, comme ceci:

#ax is the axes instance
group_labels = ['control', 'cold treatment',
             'hot treatment', 'another treatment',
             'the last one']

ax.set_xticklabels(group_labels)

Je travaille toujours sur la raison pour laquelle votre exemple ci-dessus n'a pas fonctionné.

Stanri
la source
3
Mais je veux seulement modifier une seule étiquette. L'astuce ci-dessus nécessite que vous extrayiez toutes les étiquettes de graduation et que vous définissiez celle souhaitée sur une nouvelle valeur. Mais comment puis-je extraire les étiquettes de tick lorsque label.get_text () ne renvoie rien?
repoman
11

Cela marche:

import matplotlib.pyplot as plt

fig, ax1 = plt.subplots(1,1)

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']

ax1.set_xticks(x1)
ax1.set_xticklabels(squad, minor=False, rotation=45)

FEDS

Soham
la source
7

Cela fonctionne également dans matplotlib 3:

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']

plt.xticks(x1, squad, rotation=45)
MichaelSB
la source
5

Si vous ne travaillez pas avec figet axque vous souhaitez modifier toutes les étiquettes (par exemple pour la normalisation), vous pouvez le faire:

labels, locations = plt.yticks()
plt.yticks(labels, labels/max(labels))
dopexxx
la source
1

Essaye ça :

  fig,axis = plt.subplots(nrows=1,ncols=1,figsize=(13,6),sharex=True)
  axis.set_xticklabels(['0', 'testing', '10000', '20000', '30000'],fontsize=22)
Aymen Alsaadi
la source
-4

tu peux faire:

for k in ax.get_xmajorticklabels():
    if some-condition:
        k.set_color(any_colour_you_like)

draw()
Hachi Manzur
la source
Quelqu'un peut-il expliquer pourquoi cette réponse est si fortement rejetée?
Hlynur Davíð Hlynsson
@ HlynurDavíðHlynsson Je pense que cela n'a pas vraiment quelque chose à voir avec la question. Eh bien, peut-être avec quelques modifications ... Veuillez les modifier, si vous arrivez à les relier à la question. ;)
loves.by.Jesus