修改标记标签文本

我想对图中选定的几个勾号标签做一些修改。

例如,如果我这样做:

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

更改了标记标签的字体大小和方向。

然而,如果尝试:

label.set_text('Foo')

标记标签被修改。如果我这样做:

print label.get_text()

什么都没有印出来。

这里还有一些奇怪的事情。当我试着这样做时:

import matplotlib.pyplot as plt
import numpy as np


axes = plt.figure().add_subplot(111)
t = np.arange(0.0, 2.0, 0.01)
s = np.sin(2*np.pi*t)
axes.plot(t, s)
for ticklabel in axes.get_xticklabels():
print(ticklabel.get_text())

只打印空字符串,但plot包含标记为'0.0'、'0.5'、'1.0'、'1.5'和'2.0'的刻度。

enter image description here

657057 次浏览

axes类有一个set_yticklabels函数,它允许你设置标记标签,如下所示:

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


ax.set_xticklabels(group_labels)

我仍在研究为什么你上面的例子不起作用。

注意:除非ticklabels已经被设置为字符串(通常在箱线图中是这样),否则这将不适用于任何更新于1.1.0的matplotlib版本。如果你正在从当前的github master工作,这将不起作用。我还不确定是什么问题……这可能是一个无意的变化,也可能不是……

通常情况下,你会这样做:

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

enter image description here

要理解为什么需要跳过这么多步骤,您需要更多地了解matplotlib的结构。

Matplotlib故意避免对刻度等进行“静态”定位,除非明确地告诉它这样做。假设您希望与图形交互,因此图形的边界、刻度、刻度标签等将动态变化。

因此,不能只设置给定标记标签的文本。默认情况下,每次绘制图形时,它都会被轴的Locator和Formatter重新设置。

然而,如果定位器和格式化器被设置为静态(分别为FixedLocatorFixedFormatter),则标记标签保持不变。

这就是set_*ticklabelsax.*axis.set_ticklabels所做的。

希望这能让您更清楚地了解为什么更改单个标记有点复杂。

通常,你真正想做的只是注释一个特定的位置。在这种情况下,应该查看annotate

你可以:

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


draw()

在较新版本的matplotlib中,如果你没有使用一堆str值设置刻度标签,它们默认为''(当绘制绘图时,标签只是刻度值)。要得到你想要的输出,需要这样做:

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

和结果: enter image description here

现在如果你检查_xticklabels,它们不再是一堆''

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

它适用于从1.1.1rc1到当前版本2.0的版本。

也可以用pylabxticks来实现

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

如此:

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

这个问题被问到已经有一段时间了。截至今天(matplotlib 2.2.2),经过一些阅读和试验,我认为最佳/适当的方式如下:

Matplotlib有一个名为ticker的模块。为了从图中修改一个特定的tick,以下对我来说是有效的:

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

正态分布随机值直方图

警告! x是tick的值,pos是它在坐标轴上的相对位置。注意,在索引时,pos接受从1开始的值,而不是通常的0


在我的例子中,我试图用百分比值格式化直方图的y-axismticker有另一个名为PercentFormatter的类,它可以很容易地做到这一点,而不需要像以前那样定义一个单独的函数:

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

正态分布随机值直方图

在本例中,xmax是对应于100%的数据值。百分比计算为x / xmax * 100,这就是为什么我们修复了xmax=1.0。另外,decimals是小数点后的位数。

这也适用于matplotlib 3:

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']


plt.xticks(x1, squad, rotation=45)

如果你不使用figax,你想修改所有标签(例如,为了标准化),你可以这样做:

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


试试这个:

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

我注意到这里发布的所有使用set_xticklabels()的解决方案都没有保留抵消,这是一个应用于刻度值的缩放因子,以创建更好看的刻度标签。例如,如果刻度在0.00001 (1e-5)的数量级上,matplotlib将自动添加1e-5的缩放因子(或offset),因此结果刻度标签可能最终为1 2 3 4,而不是1e-5 2e-5 3e-5 4e-5

下面是一个例子:

x数组是np.array([1, 2, 3, 4])/1e6,而yy=x**2。所以两个值都很小。

左列:手动更改第1和第3标签,由@Joe Kington建议。注意,偏移量丢失了。

中列:类似于@iipr的建议,使用FuncFormatter

右列:我建议的偏移保留解决方案。

< p >图: enter image description here < / p >

完整代码:

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


警告:似乎使用set_xticklabels()的解决方案,包括我自己的,依赖于FixedFormatter,它是静态的,不响应图形调整大小。要观察效果,将图形更改为较小的尺寸,例如fig, axes = plt.subplots(1, 3, figsize=(6,6))并放大图形窗口。您将注意到,只有中间列响应调整大小,并随着图形变大而添加更多刻度。左边和右边的列将有空的标记(见下图)。

注意2:我还注意到,如果你的tick值是浮点数,直接调用set_xticklabels(ticks)可能会给你难看的字符串,比如1.499999999998而不是1.5

enter image description here

在这里,我们打算修改Matplotlib中的一些tick标签,但没有副作用,这工作干净,并保留偏移的科学符号。本解决方案中没有遇到其他一些答案中讨论的问题。

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


from matplotlib import rcParams
rcParams['axes.formatter.use_mathtext'] = True


class CustomScalarFormatter(matplotlib.ticker.ScalarFormatter):
def __init__(self, useOffset=None, useMathText=None, useLocale=None, replace_values=([],[])):
super().__init__(useOffset=None, useMathText=None, useLocale=None)
self.replace_values = replace_values


def __call__(self, x, pos=None):
"""
Return the format for tick value *x* at position *pos*.
"""
if len(self.locs) == 0:
return ''
elif x in self.replace_values[0]:
idx = self.replace_values[0].index(x)
return str(self.replace_values[1][idx])
else:
xp = (x - self.offset) / (10. ** self.orderOfMagnitude)
if abs(xp) < 1e-8:
xp = 0
return self._format_maybe_minus_and_locale(self.format, xp)




z = np.linspace(0, 5000, 100)
fig, ax = plt.subplots()


xmajorformatter = CustomScalarFormatter(replace_values=([2000,0],['$x_0$','']))
ymajorformatter = CustomScalarFormatter(replace_values=([1E7,0],['$y_0$','']))
ax.xaxis.set_major_formatter(xmajorformatter)
ax.yaxis.set_major_formatter(ymajorformatter)


ax.plot(z,z**2)
plt.show()

我们在这里所做的是创建了matplotlib.ticker.ScalarFormatter类的派生类,matplotlib默认使用它来格式化标签。代码从matplotlib源复制,但只复制并修改了__call__函数。后

        elif x in self.replace_values[0]:
idx = self.replace_values[0].index(x)
return str(self.replace_values[1][idx])

是添加到__call__函数中执行替换工作的新行。派生类的优点是它继承了基类的所有特性,比如偏移量标记法、科学标记法,如果值很大的话就标记。结果是:

Output of above code

  • matplotlib.axes.Axes.set_xticks,或y轴的matplotlib.axes.Axes.set_yticks,可用于更改刻度和标签 matplotlib 3.5.0开始。这些是面向对象接口的。
    • 如果使用pyplot基于状态的接口,则使用plt.xticksplt.yticks,如其他答案所示。
    • 一般来说,将数字的list / array传递给ticks参数,将list / array字符串传递给labels参数。
  • 在这种情况下,x轴由连续的数值组成,因此不存在set 文本标签,正如在回答中详细解释的那样。当图中有离散的刻度(例如箱线图、条形图)时,情况就不同了。
    • [Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, '')]ax.get_xticklabels()返回
    • [-0.25 0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. 2.25]ax.get_xticks()返回
      • type(ax.get_xticks())<class 'numpy.ndarray'>
      • type(ax.get_xticks()[0])<class 'numpy.float64'>
  • 由于OP试图用str替换数字标签,所以ndarray中的所有值必须转换为str类型,并且可以更新要更改的值。
  • python 3.10matplotlib 3.5.2中测试
import numpy as np
import matplotlib.pyplot as plt


# create figure and axes
fig, ax = plt.subplots(figsize=(8, 6))


# plot data
t = np.arange(0.0, 2.0, 0.01)
s = np.sin(2*np.pi*t)


# plot
ax.plot(t, s)


# get the xticks, which are the numeric location of the ticks
xticks = ax.get_xticks()


# get the xticks and convert the values in the array to str type
xticklabels = list(map(str, ax.get_xticks()))


# update the string to be changed
xticklabels[1] = 'Test'


# set the xticks and the labels
_ = ax.set_xticks(xticks, xticklabels)

enter image description here

  • 注意,更改xticklabels时,x轴偏移量不会保留。但是,正确的值没有偏移量。
# create figure and axes
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 6), sharex=False)


# plot data
t = np.linspace(0, 1500000, 100)
s = t**2


# plot
ax1.plot(t, s)
ax2.plot(t, s)


# get the xticks, which are the numeric location of the ticks
xticks = ax2.get_xticks()


# get the xticks and convert the values in the array to str type
xticklabels = list(map(str, ax2.get_xticks()))


# update the string to be changed
xticklabels[1] = 'Test'


# set the xticks and the labels
_ = ax2.set_xticks(xticks, xticklabels, rotation=90)

enter image description here