理解matplotlib并如何使用一位数字格式化matplotlib轴?

3

我很难让 seaborn 热力图的刻度标签只显示单个整数(即没有浮点数)。我有两个列表,它们形成数据框的轴,然后使用 seaborn 绘制。

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as tkr

x = np.linspace(0, 15, 151)
y = np.linspace(0, 15, 151)
#substitute random data for my_data
df_map = pd.DataFrame(my_data, index = y, columns = x) 
plt.figure()
ax = sns.heatmap(df_map, square = True, xticklabels  = 20, yticklabels = 20)
ax.invert_yaxis()

原始地图

我已经检查了很多答案和文档,我的最大问题是我缺乏经验,对matplotlib的理解非常差,而且文档感觉就像是另一种语言... 下面是我尝试过的方法。

尝试1:一个略微修改的 这个问题 的解决方案:

fmtr = tkr.StrMethodFormatter('{x:.0f}')

plt.gca().xaxis.set_major_formatter(fmtr)

indices or decimal moving?

我相信tkr.StrMethodFormatter()会在我的轴字符串中遇到的每个值的第20个索引处显示该值,这可能是由于我在sns.heatmap()中的设置导致的。我尝试了不同的字符串输入到tkr.StrMethodFormatter(),但没有成功。我查看了另外两个问题,并尝试了此处此处答案中使用的不同组合的tkr类。

尝试2:

fmtr = tkr.StrMethodFormatter("{x:.0f}")
locator = tkr.MultipleLocator(50)
fstrform = tkr.FormatStrFormatter('%.0f')

plt.gca().xaxis.set_major_formatter(fmtr)
plt.gca().xaxis.set_major_locator(locator)
#plt.gca().xaxis.set_major_formatter(fstrform)

最后尝试

现在我完全不知所措了。 我发现locator更改了要绘制的第n个索引,而fmtrfstrform都更改了显示的小数位数,但是我怎么也无法让坐标轴显示存在于坐标轴列表中的整数值!

请帮帮我! 我已经苦苦挣扎了好几个小时。 这可能是简单的问题,谢谢!

另外:

有人能详细解释一下那个问题中的文档摘录吗? 具体来说:

...用于位置的字段必须标记为pos。

此外,有人能解释一下tkr.StrMethodFormatter("{x:.0f}")tkr.FormatStrFormatter('%.0f')之间的区别吗? 我觉得很烦人,因为有两种方法,每种方法都有自己的语法,以产生相同的结果。

更新:

我花了一些时间来实现@ImportanceOfBeingErnest提供的解决方案。 我采取了额外的预防措施,并将x,y数组中的数字四舍五入。 我不确定这是否必要,但我已经产生了想要的结果:

x = np.linspace(0, 15, 151)
y = np.linspace(0, 15, 151)
# round float numbers in axes arrays
x_rounded = [round(i,3) for i in x]
y_rounded = [round(i,3) for i in y]
#substitute random data for my_data
df_map = pd.DataFrame(my_data, index = y_rounded , columns = x_rounded) 
plt.figure()
ax0 = sns.heatmap(df_map, square = True, xticklabels  = 20)
ax0.invert_yaxis()

labels = [label.get_text() for label in ax0.get_xticklabels()]
ax0.set_xticklabels(map(lambda x: "{:g}".format(float(x)), labels))

已解决

虽然我仍不完全确定为什么这起作用了;可以查看我和他们之间的评论以获得更多澄清。


仅回答副注事项:大多数格式化程序将忽略 pos,所以你也可以; 它在这里没有帮助。 StrMethodFormatter("{x:.0f}")FormatStrFormatter('%.0f') 完全相同;使用哪个更容易理解就使用哪个。 - ImportanceOfBeingErnest
1个回答

2
"最初的回答"翻译成中文是"Original Answer"。
很遗憾,您并没有做错任何事情。问题在于seaborn有一种非常特殊的设置热图的方式。热图上的刻度是固定的位置和标签,因此要更改它们,需要更改这些固定标签。一种方法是收集这些标签,将它们转换回数字,然后重新设置它们。
labels = [label.get_text() for label in ax.get_xticklabels()]
ax.set_xticklabels(map(lambda x: "{:g}".format(float(x)), labels))

labels = [label.get_text() for label in ax.get_yticklabels()]
ax.set_yticklabels(map(lambda x: "{:g}".format(float(x)), labels))

需要注意的是:原则上,我们不应该仅设置刻度标签而不设置位置,但这里 seaborn 负责设置位置。我们只需要相信它能正确地完成这个任务。


如果您需要数值坐标轴并希望使用类似于问题中尝试的格式化方式来显示标签,可以直接使用 matplotlib 绘图。

import numpy as np
import seaborn as sns # seaborn only imported to get its rocket cmap
import matplotlib.pyplot as plt

my_data = np.random.rand(150,150)
x = (np.linspace(0, my_data.shape[0], my_data.shape[0]+1)-0.5)/10
y = (np.linspace(0, my_data.shape[1], my_data.shape[1]+1)-0.5)/10


fig, ax = plt.subplots()
pc = ax.pcolormesh(x, y, my_data, cmap="rocket")
fig.colorbar(pc)
ax.set_aspect("equal")
plt.show()

尽管这已经可以直接使用,但您仍可以像问题中尝试的那样使用定位器和格式化程序。"最初的回答"

谢谢你的解决方案!您的lambda函数实现起作用了,我已经发布了更新!但是,我需要一些关于为什么这个方法有效的澄清。我想先问一下,“热图上的刻度是固定位置且具有固定标签”是什么意思?对我来说不清楚ax0.get_xticklabels()对象包含什么(我希望比matplotlib文档更清晰)。我运行了for label in ax0.get_xticklabels(): print(label)并且输出Text(0.5, 0, '0')对我来说完全陌生。有人能帮我理解一下输出吗?谢谢! - T Walker
首先,这里有一个关于刻度和刻度标签的很好的教程。它可能无法回答所有问题,但可能会解决固定位置的问题。在这个具体例子中,seaborn 可能会在轴上的位置0.5、30.5、60.5等处放置刻度。每个刻度都有一个刻度标签。但是刻度标签显示的是完全不同的东西,即0.0、3.0、6.0等。所以我们在这里要做的就是获取刻度标签,获取它们的文本,例如 "0.0" ,将其转换为数字0.0,然后使用 g 格式将其重新格式化为字符串。 - ImportanceOfBeingErnest

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