在matplotlib中自定义x轴

2024-04-23 06:03:18 发布

您现在位置:Python中文网/ 问答频道 /正文

在下图中,x轴上的每个单元表示10分钟的间隔。我想定制x轴的标签,以便它显示小时,即每6个单位(60分钟)显示一个ticker。我对matplotlib不熟悉。有人能帮我吗?谢谢~ enter image description here

这是上图的代码。

x = arange(0, size_x, dx)
y = arange(0, size_y, dy)
X,Y = meshgrid(x, y)
Z = foo(x,y)
pcolor(X, Y, Z, cmap=cm.Reds)
colorbar()
axis([0,size_x-1,0,size_y-1])
show()

Tags: 代码size间隔foomatplotlib单位标签单元
1条回答
网友
1楼 · 发布于 2024-04-23 06:03:18

有不止一种方法可以做到这一点。

让我们从一个示例图开始:

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

# Generate some data...
x, y = np.mgrid[:141, :101]
z = np.cos(np.hypot(x, y))

# Plot the figure...
plt.pcolormesh(x, y, z, cmap=mpl.cm.Reds)

plt.show()

enter image description here

做你想做的事情的简单方法如下:

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

# Generate some data...
x, y = np.mgrid[:141, :101]
z = np.cos(np.hypot(x, y))

# Plot the figure...
plt.pcolormesh(x, y, z, cmap=mpl.cm.Reds)

# Set the ticks and labels...
ticks = np.arange(x.min(), x.max(), 6)
labels = range(ticks.size)
plt.xticks(ticks, labels)
plt.xlabel('Hours')

plt.show()

enter image description here

另一种方法涉及到子类化matplotlib的定位器和标记器。

就您的目的而言,上面的例子很好。

制作新定位器和标记器的优点是,轴将自动缩放为您指定的“dx”单位的合理间隔。如果你把它作为一个更大的应用程序的一部分,它是值得的。对于一个情节来说,麻烦比价值更大。

不过,如果你真的想走这条路,你可以这样做:

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

def main():
    # Generate some data...
    x, y = np.mgrid[:141, :101]
    z = np.cos(np.hypot(x, y))

    # Plot the figure...
    fig, ax = plt.subplots()
    ax.pcolormesh(x, y, z, cmap=mpl.cm.Reds)
    ax.set_xlabel('Hours')

    ax.xaxis.set_major_locator(ScaledLocator(dx=6))
    ax.xaxis.set_major_formatter(ScaledFormatter(dx=6))

    plt.show()

class ScaledLocator(mpl.ticker.MaxNLocator):
    """
    Locates regular intervals along an axis scaled by *dx* and shifted by
    *x0*. For example, this would locate minutes on an axis plotted in seconds
    if dx=60.  This differs from MultipleLocator in that an approriate interval
    of dx units will be chosen similar to the default MaxNLocator.
    """
    def __init__(self, dx=1.0, x0=0.0):
        self.dx = dx
        self.x0 = x0
        mpl.ticker.MaxNLocator.__init__(self, nbins=9, steps=[1, 2, 5, 10])

    def rescale(self, x):
        return x / self.dx + self.x0
    def inv_rescale(self, x):
        return  (x - self.x0) * self.dx

    def __call__(self): 
        vmin, vmax = self.axis.get_view_interval()
        vmin, vmax = self.rescale(vmin), self.rescale(vmax)
        vmin, vmax = mpl.transforms.nonsingular(vmin, vmax, expander = 0.05)
        locs = self.bin_boundaries(vmin, vmax)
        locs = self.inv_rescale(locs)
        prune = self._prune
        if prune=='lower':
            locs = locs[1:]
        elif prune=='upper':
            locs = locs[:-1]
        elif prune=='both':
            locs = locs[1:-1]
        return self.raise_if_exceeds(locs)

class ScaledFormatter(mpl.ticker.OldScalarFormatter):
    """Formats tick labels scaled by *dx* and shifted by *x0*."""
    def __init__(self, dx=1.0, x0=0.0, **kwargs):
        self.dx, self.x0 = dx, x0

    def rescale(self, x):
        return x / self.dx + self.x0

    def __call__(self, x, pos=None):
        xmin, xmax = self.axis.get_view_interval()
        xmin, xmax = self.rescale(xmin), self.rescale(xmax)
        d = abs(xmax - xmin)
        x = self.rescale(x)
        s = self.pprint_val(x, d)
        return s

if __name__ == '__main__':
    main()

enter image description here

相关问题 更多 >