更改 x 轴或 y 轴的刻度频率。

763

我正在尝试修复Python绘制我的数据的方式。请说:

x = [0, 5, 9, 10, 15]
y = [0, 1, 2, 3, 4]

matplotlib.pyplot.plot(x, y)
matplotlib.pyplot.show()

x轴的刻度以5的间隔绘制。有没有办法让它显示1的间隔?

12
紧密相关的问题:https://dev59.com/A2w15IYBdhLWcg3wVKN1 和一个很好的解决方案:pyplot.locator_params(nbins=4)。翻译:这是一个与Matplotlib中如何减少刻度数密切相关的问题,并提供了一个很好的解决方法:使用 pyplot.locator_params(nbins=4)。请注意,翻译时应尽量保留原文意思和结构,不要添加额外的解释或内容。 - Dr. Jan-Philip Gehrcke
14个回答

903

您可以使用 plt.xticks 来明确设置刻度的位置:

plt.xticks(np.arange(min(x), max(x)+1, 1.0))
例如,
import numpy as np
import matplotlib.pyplot as plt

x = [0,5,9,10,15]
y = [0,1,2,3,4]
plt.plot(x,y)
plt.xticks(np.arange(min(x), max(x)+1, 1.0))
plt.show()

为了防止min(x)max(x)是浮点数而不是整数,使用了np.arange而不是Python的range函数。


plt.plot(或 ax.plot)函数会自动设置默认的xy限制。如果你希望保留这些限制,并且只改变刻度标记的步长,则可以使用ax.get_xlim()来发现Matplotlib已经设置了什么限制。

start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, stepsize))

默认的刻度格式化程序应该可以很好地将刻度值四舍五入到一个合理的有效数字。但是,如果您希望对格式有更多控制权,可以定义自己的格式化程序。例如,

ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))

这里有一个可运行的示例:

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

x = [0,5,9,10,15]
y = [0,1,2,3,4]
fig, ax = plt.subplots()
ax.plot(x,y)
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, 0.712123))
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))
plt.show()

128
有没有办法让它仍然自己决定限制,只是改变步长?如果最小值是3523.232512之类的数字,这种方法就不太好用了! - Corvus
3
@Corone,你提问已经有一段时间了,但我在下面发布了一个答案,可以在仍然使用自动边界确定的情况下轻松控制步长。尽可能保留原意,使内容更通俗易懂。 - jthomas
5
请注意,在plt.xticks(np.arange(min(x), max(x)+1, 1.0))中的+1是必需的,以显示最后一个刻度标记。 - Alex Willison
7
有没有与datetime等效的东西,例如 plt.xticks(np.arange(min(dates), max(dates)+0.1,0.1)?它似乎只绘制年份。 - William Baker Morrison
1
当x轴的格式为日期时间时,它似乎无法正常工作。 - Amir
显示剩余5条评论

294

另一种方法是设置轴定位器:

import matplotlib.ticker as plticker

loc = plticker.MultipleLocator(base=1.0) # this locator puts ticks at regular intervals
ax.xaxis.set_major_locator(loc)

根据您的需求,有几种不同类型的定位器可供选择。

以下是一个完整的示例:

import matplotlib.pyplot as plt
import matplotlib.ticker as plticker

x = [0,5,9,10,15]
y = [0,1,2,3,4]
fig, ax = plt.subplots()
ax.plot(x,y)
loc = plticker.MultipleLocator(base=1.0) # this locator puts ticks at regular intervals
ax.xaxis.set_major_locator(loc)
plt.show()

9
此功能无法按预期工作。具体而言,在使用日期时,它未使用适当的日期。 - Chris Fonnesbeck
59
使用日期时,您应该使用matplotlib.dates模块中的方法。例如 matplotlib.dates.AutoDateLocator() - robochat
6
对我来说,这个解决方案对于日期的处理和预期一样。这个解决方案比被采纳的方案要简单得多。 - Pablo Suau
4
base=1.0 实际上是什么意思/做什么? - WestCoastProjects
2
base=1.0 表示每个整数都会有一个定位器。文档中说 MultipleLocator "在视图间隔内的基数的每个整数倍上设置一个刻度线。"。因此,如果 base=2,则偶数将有一个刻度线,我认为您甚至可以将 base 设置为 2.5。 - robochat
显示剩余2条评论

197

我喜欢这个解决方案(来自Matplotlib绘图食谱):

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

x = [0,5,9,10,15]
y = [0,1,2,3,4]

tick_spacing = 1

fig, ax = plt.subplots(1,1)
ax.plot(x,y)
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
plt.show()

使用 ticker.MultipleLocator() 您可以通过给定的数字显式控制刻度间距,允许自动确定限制并且易于以后阅读。


4
一种无需显式计算刻度的方法! - Zelphir Kaltstahl
5
这个答案与这个答案相同。在两年后提供一样的答案是没有意义的。 - ImportanceOfBeingErnest
13
好发现。当我发布答案时,我没有意识到它们是相同的。不过,我认为这个展示更容易理解一些。 - jthomas
2
这个答案中提到的书籍参考资料也为获取更多信息提供了有用的来源。 - Steven C. Howell
2
为了以后参考,请不要写一个新的答案来解决同样的问题,只需编辑其他答案使其更清晰即可。我也发现你的更加清晰。 - Emir
显示剩余4条评论

157

如果有人对通用的一行代码感兴趣,只需获取当前刻度并使用它来通过每隔一个刻度进行采样来设置新的刻度。

ax.set_xticks(ax.get_xticks()[::2])

5
这是适用于不同类型的 ticks(str、float、datetime)的唯一可推广答案。 - Ryszard Cetnarski
4
移除非整数刻度:ax.set_xticks([tick for tick in ax.get_xticks() if tick % 1 == 0]) 改为:ax.set_xticks([tick for tick in ax.get_xticks() if tick % 1 == 0]) - user2839288
上面有很多详细的解决方案,但我同意这是最简洁的。你甚至可以提取ax.get_xticks()的长度,并通过该长度除以所需刻度的数量来设置切片频率。 - Iain D
2
我认为这是最好的答案。大多数其他答案都太复杂和难以应用/概括。谢谢! - Sean
13
它只能减少棍子的数量,而问题(以及我找到它的目标)是要增加数量。 - Alex Martian
如果您想更改刻度标签频率,但遇到错误,请参阅此答案以获取解决方案。 - cottontail

54

如果您只想设置间距并希望代码简洁:

plt.gca().xaxis.set_major_locator(plt.MultipleLocator(1))

同样也可以轻松处理次要刻度:

plt.gca().xaxis.set_minor_locator(plt.MultipleLocator(1))
有点啰嗦,但相当紧凑。

1
值得一提的是,参数“plt.MultipleLocator(arg)”是刻度间隔。因此,如果您希望每个刻度之间相距5个单位,请使用“plt.MultipleLocator(5)”即可。否则,像这个解决方案一样最好。谢谢! - Ray Walker
ax.xaxis.set_major_locator(plt.MultipleLocator(val)) in case you are using fig, ax = plt.subplots() - Alexander

40

这可能有点取巧,但是这是我找到的最干净/易于理解的示例。它来自SO上的答案

for label in ax.get_xticklabels()[::2]:
    label.set_visible(False)

然后您可以循环标签,根据您想要的密度将它们设置为可见或不可见。

编辑:请注意,有时matplotlib会将标签设置为'',因此可能看起来像标签不存在,实际上它是存在的,只是没有显示任何内容。为了确保您正在循环遍历实际可见的标签,您可以尝试:

visible_labels = [lab for lab in ax.get_xticklabels() if lab.get_visible() is True and lab.get_text() != '']
plt.setp(visible_labels[::2], visible=False)

3
这是最简单和通用的解决方案。一个微小的调整:通常 ax.get_xticklabels()[1::2] 是需要隐藏的标签。 - jolvi
这个在matplotlib.finance.candlestick2中不起作用。 - BCR
@BCR 可能是因为一些 xticklabels 被设置为 '',所以当你循环遍历它们时,你会产生空的不可见的 xticklabels(这对可视化没有影响,但可能意味着你没有获取正确的标签)。你可以尝试:vis_labels = [label for label in ax.get_xticklabels() if label.get_visible() is True]; plt.setp(vis_labels[::2], visible==False) - choldgraf

19

这是一个老话题,但我经常会遇到它,并且已经写了这个函数。它非常方便:

import matplotlib.pyplot as pp
import numpy as np

def resadjust(ax, xres=None, yres=None):
    """
    Send in an axis and I fix the resolution as desired.
    """

    if xres:
        start, stop = ax.get_xlim()
        ticks = np.arange(start, stop + xres, xres)
        ax.set_xticks(ticks)
    if yres:
        start, stop = ax.get_ylim()
        ticks = np.arange(start, stop + yres, yres)
        ax.set_yticks(ticks)

这种控制刻度的方法有一个注意事项,就是在添加新行后不再享受交互式自动更新最大刻度的功能。此时需要执行以下操作:

gca().set_ylim(top=new_top) # for example

并再次运行resadjust函数。


13

我开发了一个不太优美的解决方案。考虑到我们有X轴,以及每个X点的标签列表。

import matplotlib.pyplot as plt

x = [0,1,2,3,4,5]
y = [10,20,15,18,7,19]
xlabels = ['jan','feb','mar','apr','may','jun']
假设我只想显示“2月”和“6月”的刻度标签。
xlabelsnew = []
for i in xlabels:
    if i not in ['feb','jun']:
        i = ' '
        xlabelsnew.append(i)
    else:
        xlabelsnew.append(i)
好的,现在我们有一个虚假的标签列表。首先,我们绘制了原始版本。
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabels,rotation=45)
plt.show()
现在,修改后的版本。
plt.plot(x,y)
plt.xticks(range(0,len(x)),xlabelsnew,rotation=45)
plt.show()

9

纯Python实现

以下是所需功能的纯Python实现,可处理任何数字系列(int或float),包括正数、负数或混合值,并允许用户指定所需的步长:

import math

def computeTicks (x, step = 5):
    """
    Computes domain with given step encompassing series x
    @ params
    x    - Required - A list-like object of integers or floats
    step - Optional - Tick frequency
    """
    xMax, xMin = math.ceil(max(x)), math.floor(min(x))
    dMax, dMin = xMax + abs((xMax % step) - step) + (step if (xMax % step != 0) else 0), xMin - abs((xMin % step))
    return range(dMin, dMax, step)

样例输出

# Negative to Positive
series = [-2, 18, 24, 29, 43]
print(list(computeTicks(series)))

[-5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45]

# Negative to 0
series = [-30, -14, -10, -9, -3, 0]
print(list(computeTicks(series)))

[-30, -25, -20, -15, -10, -5, 0]

# 0 to Positive
series = [19, 23, 24, 27]
print(list(computeTicks(series)))

[15, 20, 25, 30]

# Floats
series = [1.8, 12.0, 21.2]
print(list(computeTicks(series)))

[0, 5, 10, 15, 20, 25]

# Step – 100
series = [118.3, 293.2, 768.1]
print(list(computeTicks(series, step = 100)))

[100, 200, 300, 400, 500, 600, 700, 800]

使用示例

import matplotlib.pyplot as plt

x = [0,5,9,10,15]
y = [0,1,2,3,4]
plt.plot(x,y)
plt.xticks(computeTicks(x))
plt.show()

使用示例的图表

请注意,x轴上的整数值是均匀间隔的5个,而y轴具有不同的间隔(这是由于未指定刻度标记的matplotlib默认行为)。


9

只需导入Numpy的通用一行代码:

ax.set_xticks(np.arange(min(x),max(x),1))

当问题的背景已经确定时:
import numpy as np
import matplotlib.pyplot as plt 
fig, ax = plt.subplots()
x = [0,5,9,10,15]
y = [0,1,2,3,4]
ax.plot(x,y)
ax.set_xticks(np.arange(min(x),max(x),1))
plt.show()

工作原理:

  1. fig, ax = plt.subplots() 返回包含轴的ax对象。
  2. np.arange(min(x),max(x),1) 返回从x的最小值到最大值之间间隔为1的数组。这是我们想要的新x刻度。
  3. ax.set_xticks() 改变ax对象上的刻度。

那么,你能解释一下这段代码吗? - jagapathi
我已经重写了它,使其更清晰。希望有所帮助。 - Johnny V

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接