【问题标题】:Matplotlib: How to force integer tick labels?Matplotlib:如何强制整数刻度标签?
【发布时间】:2015-09-04 00:56:04
【问题描述】:

我的 python 脚本使用 matplotlib 绘制 x、y、z 数据集的二维“热图”。我的 x 和 y 值代表蛋白质中的氨基酸残基,因此只能是整数。当我放大情节时,它看起来像这样:

正如我所说,x-y 轴上的浮点值对我的数据没有意义,因此我希望它看起来像这样:

任何想法如何实现这一目标? 这是生成情节的代码:

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

【问题讨论】:

    标签: python matplotlib plot


    【解决方案1】:

    根据modifying tick labels 的答案,我想出了一个解决方案,不知道它是否适用于您的情况,因为您的代码 sn-p 无法自行执行。

    这个想法是强制刻度标签的间距为 0.5,然后将每个 0.5 刻度替换为其整数对应物,并将其他标记替换为空字符串。

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

    如果您想缩小很多,则需要格外小心,因为这会产生一组非常密集的刻度标签。

    【讨论】:

      【解决方案2】:

      这应该更简单:

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

      【讨论】:

      • 它没有为我将刻度标签放在给定区域的中点(如问题的示例图像中),并且每一秒(未标记)刻度都丢失了。有没有一个简单的技巧来实现这些? '2' 应该在 2.5 的位置,而不是在 2.0。
      • @Andris 对此我完全不知道。但是无论如何调整这个任务的绘图库似乎很奇怪,你可能应该修改你的数据。您所指的示例图像似乎已经用油漆或类似的东西进行了编辑,因此这并不意味着 matplotlib 可以进行这样的输出。
      • 这给了我非常奇怪的结果。它将刻度 [0, 2, 4, 8, 10] 转换为 [0.0, 1.5, 3.0, 4.5, 7.5, 9.0, 10.5]。鉴于docs 所说的不应该发生这种情况。
      • +1 表示您的答案,但 -1 表示可怕的 API! plt.axes().xaxis.set_major_locator(MaxNLocator(integer=True)) 为我工作。
      【解决方案3】:

      通过简单地将索引i 转换为字符串的以下解决方案对我有用:

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

      【讨论】:

      • 您好,欢迎来到 SO! datax 对应什么?您没有共享代码来设置刻度标签,因此不清楚 datax 是 x 刻度还是 y 刻度的标签列表(对应于 datay 变量)。例如,如果 OP 的 x 变量范围从 1 到 15,我不知道这将如何工作。我建议您使您的答案适用于任何值范围,例如当前接受的答案的情况。鉴于您是新用户,我暂时不会对这个答案投反对票,但我鼓励您尽快改进它。
      • 感谢您的建议!我的不好,我匆忙回答,如果现在回答可以,请告诉我!
      • 将整数列表转换为 str 列表 => list(map(str, list_int))
      【解决方案4】:
      ax.set_xticks([2,3])
      ax.set_yticks([2,3])
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 1970-01-01
      • 2014-03-22
      • 2021-06-14
      • 2019-07-10
      • 1970-01-01
      相关资源
      最近更新 更多