Matplotlib: Hoe vinklabels voor integers te forceren?

Mijn pythonscript gebruikt matplotlib om een ​​2D “heatmap” van een x, y, z-dataset te plotten. Mijn x- en y-waarden vertegenwoordigen aminozuurresten in een eiwit en kunnen daarom alleen gehele getallen zijn. Als ik inzoom op de plot, ziet het er als volgt uit:

2D-warmtekaart met zwevende maatstreepjes

Zoals ik al zei, hebben float-waarden op de x-y-assen geen zin met mijn gegevens en daarom wil ik dat het er als volgt uitziet:
voer hier de afbeeldingsbeschrijving in

Enig idee hoe dit te bereiken?
Dit is de code die de plot genereert:

def plotDistanceMap(self):
    # Read on x,y,z
    x = self.currentGraph['xData']
    y = self.currentGraph['yData']
    X, Y = numpy.meshgrid(x, y)
    Z = self.currentGraph['zData']
    # Define colormap
    cmap = colors.ListedColormap(['blue', 'green', 'orange', 'red'])
    cmap.set_under('white')
    cmap.set_over('white')
    bounds = [1,15,50,80,100]
    norm = colors.BoundaryNorm(bounds, cmap.N)
    # Draw surface plot
    img = self.axes.pcolor(X, Y, Z, cmap=cmap, norm=norm)
    self.axes.set_xlim(x.min(), x.max())
    self.axes.set_ylim(y.min(), y.max())
    self.axes.set_xlabel(self.currentGraph['xTitle'])
    self.axes.set_ylabel(self.currentGraph['yTitle'])
    # Cosmetics
    #matplotlib.rcParams.update({'font.size': 12})
    xminorLocator = MultipleLocator(10)
    yminorLocator = MultipleLocator(10)
    self.axes.xaxis.set_minor_locator(xminorLocator)
    self.axes.yaxis.set_minor_locator(yminorLocator)
    self.axes.tick_params(direction='out', length=6, width=1)
    self.axes.tick_params(which='minor', direction='out', length=3, width=1)
    self.axes.xaxis.labelpad = 15
    self.axes.yaxis.labelpad = 15
    # Draw colorbar
    colorbar = self.figure.colorbar(img, boundaries = [0,1,15,50,80,100], 
                                    spacing = 'proportional',
                                    ticks = [15,50,80,100], 
                                    extend = 'both')
    colorbar.ax.set_xlabel('Angstrom')
    colorbar.ax.xaxis.set_label_position('top')
    colorbar.ax.xaxis.labelpad = 20
    self.figure.tight_layout()      
    self.canvas.draw()

Antwoord 1, autoriteit 100%

Dit zou eenvoudiger moeten zijn:

(van https://scivision.co/matplotlib-force-integer -labeling-of-axis/)

import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
#...
ax = plt.figure().gca()
#...
ax.xaxis.set_major_locator(MaxNLocator(integer=True))

Antwoord 2, autoriteit 3%

De volgende oplossing door simpelweg de index inaar string te casten werkte voor mij:

   import matplotlib.pyplot as plt
    import time
    datay = [1,6,8,4] # Just an example
    datax = []
    # In the following for loop datax in the end will have the same size of datay, 
    # can be changed by replacing the range with wathever you need
    for i in range(len(datay)):
        # In the following assignment statement every value in the datax 
        # list will be set as a string, this solves the floating point issue
        datax += [str(1 + i)]
    a = plt
    # The plot function sets the datax content as the x ticks, the datay values
    # are used as the actual values to plot
    a.plot(datax, datay)
    a.show()

Antwoord 3

Op basis van een antwoord voor het aanpassen van vinkjeskwam ik met een oplossing, weet niet of het gaat werken in uw geval omdat uw codefragment niet op zichzelf kan worden uitgevoerd.

Het idee is om de tick-labels te forceren tot een afstand van .5, en dan elke .5 tick te vervangen door zijn integere tegenhanger, en andere door een lege string.

import numpy
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1,2)
x1, x2 = 1, 5
y1, y2 = 3, 7
# first axis: ticks spaced at 0.5
ax1.plot([x1, x2], [y1, y2])
ax1.set_xticks(numpy.arange(x1-1, x2+1, 0.5))
ax1.set_yticks(numpy.arange(y1-1, y2+1, 0.5))
# second axis: tick labels will be replaced
ax2.plot([x1, x2], [y1, y2])
ax2.set_xticks(numpy.arange(x1-1, x2+1, 0.5))
ax2.set_yticks(numpy.arange(y1-1, y2+1, 0.5))
# We need to draw the canvas, otherwise the labels won't be positioned and 
# won't have values yet.
fig.canvas.draw()
# new x ticks  '1'->'', '1.5'->'1', '2'->'', '2.5'->'2' etc.
labels = [item.get_text() for item in ax2.get_xticklabels()]
new_labels = [ "%d" % int(float(l)) if '.5' in l else '' for l in labels]
ax2.set_xticklabels(new_labels)
# new y ticks
labels = [item.get_text() for item in ax2.get_yticklabels()]
new_labels = [ "%d" % int(float(l)) if '.5' in l else '' for l in labels]
ax2.set_yticklabels(new_labels)
fig.canvas.draw()
plt.show()

Als je veel wilt uitzoomen, heb je wat extra aandacht nodig, omdat deze dan een zeer dichte reeks vinklabels produceert.


Antwoord 4

ax.set_xticks([2,3])
ax.set_yticks([2,3])

Other episodes