Wijzig de tekst van het vinkje

Ik wil enkele wijzigingen aanbrengen in een paar geselecteerde vinkjes in een plot.

Als ik dat bijvoorbeeld doe:

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

de lettergrootte en de richting van het vinkje zijn gewijzigd.

Als u het echter probeert:

label.set_text('Foo')

het vinkje is nietgewijzigd. Ook als ik dat doe:

print label.get_text()

er wordt niets afgedrukt.

Hier is nog wat vreemds. Toen ik dit probeerde:

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

Alleen lege strings worden afgedrukt, maar de plot bevat vinkjes met de labels ‘0.0’, ‘0.5’, ‘1.0’, ‘1.5’ en ‘2.0’.


Antwoord 1, autoriteit 100%

Voorbehoud: tenzij de ticklabels al op een string zijn ingesteld (zoals meestal het geval is in bijvoorbeeld een boxplot), werkt dit niet met een versie van matplotlib die nieuwer is dan 1.1.0. Als je met de huidige github-master werkt, werkt dit niet. Ik weet nog niet wat het probleem is… Het kan een onbedoelde wijziging zijn, of het is misschien niet…

Normaal gesproken zou je iets in de trant van het volgende doen:

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

voer hier de afbeeldingsbeschrijving in

Om de reden te begrijpen waarom je door zoveel hoepels moet springen, moet je wat meer begrijpen over hoe matplotlib is gestructureerd.

Matplotlib vermijdt opzettelijk het doen van “statische” plaatsing van teken, enz., tenzij dit expliciet wordt gevraagd. De veronderstelling is dat je interactie wilt hebben met de plot, en dus zullen de grenzen van de plot, ticks, ticklabels, enz. dynamisch veranderen.

Daarom kun je niet zomaar de tekst van een bepaald vinkje zetten. Standaard wordt het elke keer dat de plot wordt getekend opnieuw ingesteld door de zoeker en formatter van de as.

Als de locators en formatters echter statisch zijn ingesteld (respectievelijk FixedLocatoren FixedFormatter), blijven de vinkjes hetzelfde.

Dit is wat set_*ticklabelsof ax.*axis.set_ticklabelsdoet.

Hopelijk maakt dat het iets duidelijker waarom het wijzigen van een individueel vinkje een beetje ingewikkeld is.

Vaak wil je eigenlijk gewoon een bepaalde positie annoteren. Kijk in dat geval in plaats daarvan naar annotate.


Antwoord 2, autoriteit 35%

Je kunt dit ook doen met pylaben 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()

https://matplotlib.org/stable/gallery/ticks_and_spines/ticklabels_rotation.html


Antwoord 3, autoriteit 30%

In nieuwere versies van matplotlib, als u de vinkjes niet instelt met een aantal str-waarden, zijn ze ''door standaard (en wanneer de plot wordt getekend, zijn de labels gewoon de ticks-waarden). Als je dat weet, heb je iets als dit nodig om de gewenste output te krijgen:

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

en het resultaat:
voer hier de afbeeldingsbeschrijving in

en als je nu de _xticklabelscontroleert, zijn ze niet langer een stel ''.

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

Het werkt in de versies van 1.1.1rc1tot de huidige versie 2.0.


Antwoord 4, autoriteit 6%

Het is een tijdje geleden dat deze vraag werd gesteld. Vanaf vandaag (matplotlib 2.2.2) en na wat lezen en uitproberen, denk ik dat de beste/juiste manier de volgende is:

Matplotlib heeft een module met de naam tickerdie ” bevat klassen ter ondersteuning van volledig configureerbare lokalisatie en opmaak van vinkjes”. Om een specifiek vinkje uit de plot te wijzigen, werkt het volgende voor mij:

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

Histogram met willekeurige waarden uit een normale verdeling

Voorbehoud!xis de waarde van het vinkje en posis de relatieve positie op de as. Merk op dat poswaarden aanneemt die beginnen met 1, niet in 0zoals gebruikelijk bij het indexeren.


In mijn geval probeerde ik de y-axisvan een histogram op te maken met percentagewaarden. mtickerheeft een andere klasse genaamd PercentFormatterdie dit gemakkelijk kan doen zonder de noodzaak om een aparte functie te definiëren zoals voorheen:

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

Histogram met willekeurige waarden uit een normale verdeling

In dit geval is xmaxde gegevenswaarde die overeenkomt met 100%. Percentages worden berekend als x / xmax * 100, daarom repareren we xmax=1.0. Ook is decimalshet aantal decimalen dat na de punt moet worden geplaatst.


Antwoord 5, autoriteit 4%

Dit werkt:

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


Antwoord 6, autoriteit 4%

De klasse axes heeft een set_yticklabels-functie die stelt u in staat om de vinkjes in te stellen, zoals:

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

Ik ben nog bezig met waarom uw voorbeeld hierboven niet werkte.


Antwoord 7, autoriteit 2%

Dit werkt ook in matplotlib 3:

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']
plt.xticks(x1, squad, rotation=45)

Antwoord 8

Als u niet met figen axwerkt en u wilt alle labels wijzigen (bijvoorbeeld voor normalisatie), dan kunt u dit doen:

labels, locations = plt.yticks()
plt.yticks(labels, labels/max(labels))

Antwoord 9

Probeer dit:

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

Antwoord 10

Ik heb gemerkt dat alle hier geposte oplossingen die set_xticklabels()gebruiken, de offsetniet behouden, wat een schaalfactor is die wordt toegepast op de ticks-waarden om betere- op zoek naar tekenlabels. Als de vinkjes bijvoorbeeld in de orde van 0,00001 (1e-5) zijn, zal matplotlib automatisch een schaalfactor (of offset) van 1e-5toevoegen, zodat de resulterende vinkjes kunnen eindigen als 1 2 3 4, in plaats van 1e-5 2e-5 3e-5 4e-5.

Hieronder staat een voorbeeld:

De xarray is np.array([1, 2, 3, 4])/1e6, en yis y=x**2. Beide zijn dus zeer kleine waarden.

Linkerkolom: verander handmatig de 1e en 3e labels, zoals voorgesteld door @Joe Kington. Merk op dat de offset verloren gaat.

Midden kolom: vergelijkbaar met de suggestie van @iipr, met een FuncFormatter.

Rechterkolom: mijn voorgestelde oplossing om offset te behouden.

Figuur hier:
voer hier de afbeeldingsbeschrijving in

Volledige code hier:

import matplotlib.pyplot as plt
import numpy as np
# create some *small* data to plot
x = np.arange(5)/1e6
y = x**2
fig, axes = plt.subplots(1, 3, figsize=(10,6))
#------------------The set_xticklabels() solution------------------
ax1 = axes[0]
ax1.plot(x, y)
fig.canvas.draw()
labels = [item.get_text() for item in ax1.get_xticklabels()]
# Modify specific labels
labels[1] = 'Testing'
labels[3] = 'Testing2'
ax1.set_xticklabels(labels)
ax1.set_title('set_xticklabels()')
#--------------FuncFormatter solution--------------
import matplotlib.ticker as mticker
def update_ticks(x, pos):
    if pos==1:
        return 'testing'
    elif pos==3:
        return 'testing2'
    else:
        return x
ax2=axes[1]
ax2.plot(x,y)
ax2.xaxis.set_major_formatter(mticker.FuncFormatter(update_ticks))
ax2.set_title('Func Formatter')
#-------------------My solution-------------------
def changeLabels(axis, pos, newlabels):
    '''Change specific x/y tick labels
    Args:
        axis (Axis): .xaxis or .yaxis obj.
        pos (list): indices for labels to change.
        newlabels (list): new labels corresponding to indices in <pos>.
    '''
    if len(pos) != len(newlabels):
        raise Exception("Length of <pos> doesn't equal that of <newlabels>.")
    ticks = axis.get_majorticklocs()
    # get the default tick formatter
    formatter = axis.get_major_formatter()
    # format the ticks into strings
    labels = formatter.format_ticks(ticks)
    # Modify specific labels
    for pii, lii in zip(pos, newlabels):
        labels[pii] = lii
    # Update the ticks and ticklabels. Order is important here.
    # Need to first get the offset (1e-6 in this case):
    offset = formatter.get_offset()
    # Then set the modified labels:
    axis.set_ticklabels(labels)
    # In doing so, matplotlib creates a new FixedFormatter and sets it to the xaxis
    # and the new FixedFormatter has no offset. So we need to query the
    # formatter again and re-assign the offset:
    axis.get_major_formatter().set_offset_string(offset)
    return
ax3 = axes[2]
ax3.plot(x, y)
changeLabels(ax3.xaxis, [1, 3], ['Testing', 'Testing2'])
ax3.set_title('With offset')
fig.show()
plt.savefig('tick_labels.png')

Voorbehoud: het lijkt erop dat oplossingen die set_xticklabels()gebruiken, inclusief de mijne, vertrouwen op FixedFormatter, dat statisch is en niet t reageren op het formaat wijzigen. Om het effect te observeren, verander de figuur naar een kleinere maat, b.v. fig, axes = plt.subplots(1, 3, figsize=(6,6))en vergroot het figuurvenster. U zult merken dat alleen de middelste kolom reageert op het wijzigen van het formaat en meer vinkjes toevoegt naarmate het cijfer groter wordt. De linker- en rechterkolom hebben lege vinkjes (zie onderstaande afbeelding).

Voorbehoud 2: ik heb ook gemerkt dat als je tick-waarden floats zijn, het rechtstreeks aanroepen van set_xticklabels(ticks)je lelijke strings kan opleveren, zoals 1.499999999998in plaats van 1.5.

voer hier de afbeeldingsbeschrijving in


Antwoord 11

u kunt doen:

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

Other episodes