不使用twiny显示imshow的上方坐标轴标签?
我有一行数据,想要给它做个热力图,但不想用twiny(),因为那样会出现对齐问题。我在这个网站上搜索了很多,得到了以下结果:
import numpy as np
import matplotlib.pyplot as plt
x = "0.2, 0.3, 0.4, 0.5, 0.6".split(",")
y = "180, 175, 170, 169, 150".split(",")
z = [[5000, 4800, 4500, 4450, 4300]]
fig, ax1 = plt.subplots()
image = z
im = ax1.imshow(image, cmap=plt.cm.Blues, interpolation='nearest')
plt.colorbar(im)
ax1.set_xticks(np.arange(len(x)), minor=False)
ax1.set_xticklabels(x, minor=False)
#ax1.set_yticklabels(y, minor=False)
ax1.tick_params(labelbottom='on',labeltop='on', labelleft="off")
plt.show()
你可以看到,上面的坐标轴和下面的坐标轴上的文字是完全一样的。我想要的是把y
放在上面的坐标轴上。
提前谢谢你们 :)
4 个回答
0
如果我理解得没错的话,我想你只需要把x改成y:
ax1.set_xticklabels(y, minor=False)
如果我这么做的话,我会在图的顶部和底部看到列表y的标签。
1
使用 twin()
和 from mpl_toolkits.axes_grid1 import host_subplot
。
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
import numpy as np
x = "0.2, 0.3, 0.4, 0.5, 0.6".split(",")
y = "180, 175, 170, 169, 150".split(",")
z = [[5000, 4800, 4500, 4450, 4300]]
#fig, ax1 = plt.subplots()
ax1 = host_subplot(111, axes_class=AA.Axes)
ax2 = ax1.twin()
image = z
im = ax1.imshow(image, cmap=plt.cm.Blues, interpolation='nearest')
plt.colorbar(im)
ax1.set_xticks(np.arange(len(x)), minor=False)
ax2.set_xticks(np.arange(len(y)), minor=False)
#ax1.tick_params(labelbottom='on',labeltop='on', labelleft="off")
#ax2.tick_params(labelbottom='on',labeltop='on', labelleft="off")
ax1.set_yticklabels([])
ax2.set_yticklabels([])
ax1.tick_params(labelbottom='on',labeltop='on', labelleft="off")
plt.show()
1
我找到了一种替代方案,使用文本而不是改变坐标轴的数值。
import numpy as np
import matplotlib.pyplot as plt
font = {'family' : 'sans-serif',
'color' : 'k',
'weight' : 'normal',
'size' : 12,
}
x = "0.2, 0.3, 0.4, 0.5, 0.6".split(",")
y = "180, 175, 170, 169, 150".split(",")
z = [[5000, 4800, 4500, 4450, 4300]]
fig, ax1 = plt.subplots()
#fig, ax1 = plt.subplots()
image = z
im = ax1.imshow(z, cmap=plt.cm.Blues, interpolation='nearest')
xticks = ax1.get_xticks()
top_lables_width_spacings = 0.83
top_lables_hight_spacings = -.53
for i in range(len(y)):
ax1.text(xticks[i] + top_lables_width_spacings, top_lables_hight_spacings, y[i], fontdict=font)
#ax1.set_aspect('auto')
fig.colorbar(im, orientation='vertical')
ax1.set_xticks(np.arange(len(x)), minor=False)
ax1.set_xticklabels(x, minor=False)
ax1.tick_params(labelbottom='on',labeltop='off', labelleft="off")
ax1.set_title('$\eta$\n', size=17) # represents the top axes label
plt.xlabel(r'$\theta$', size=17) # represents the bottom axes label
plt.show()
4
看起来,twiny
和设置了equal
比例的坐标轴不太能共存。我觉得这可能是个bug,但也许有其他解释。
所以,我们可以通过在同一个位置上绘制两个坐标轴来解决这个问题。这听起来简单,但其实并不容易,因为如果两个子图在同一个位置,matplotlib
会把它们当成同一个图。不过,使用add_plot
就没有这个问题。
import numpy as np
import matplotlib.pyplot as plt
x = "0.2, 0.3, 0.4, 0.5, 0.6".split(",")
y = "180, 175, 170, 169, 150".split(",")
z = [[5000, 4800, 4500, 4450, 4300]]
fig = plt.figure()
ax1 = fig.add_subplot(111)
image = z
im = ax1.imshow(image, cmap=plt.cm.Blues, interpolation='nearest')
plt.colorbar(im)
ax1.set_xticks(np.arange(len(x)), minor=False)
ax1.set_xticklabels(x, minor=False)
ax1.tick_params(labelbottom='on',labeltop='off', labelleft="off",
top='off', left='off', right='off')
# create another axes on the same position:
# - create second axes on top of the first one without background
# - make the background invisible
# - set the x scale according to that of `ax1`
# - set the top ticks on and everything else off
# - set the size according to the size of `ax1`
ax2 = fig.add_axes(ax1.get_position(), frameon=False)
ax2.tick_params(labelbottom='off',labeltop='on', labelleft="off", labelright='off',
bottom='off', left='off', right='off')
ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks(np.arange(len(y)))
ax2.set_xticklabels(y, minor=False)
plt.draw()
ax2.set_position(ax1.get_position())
plt.draw()
plt.show()
在调用set_position
之前需要用plt.draw()
,否则get_position
会因为使用了equal
比例而返回错误的位置(这可能就是twiny
失败的原因)。
如果你需要有多行,解决方案也差不多:
import numpy as np
import matplotlib.pyplot as plt
x = "0.2, 0.3, 0.4, 0.5, 0.6".split(",")
y = "180, 175, 170, 169, 150".split(",")
z = [[5000, 4800, 4500, 4450, 4300]]
numRows = 8
fig, subaxes = plt.subplots(nrows=numRows, ncols=1)
axeslist = subaxes.flatten()
for ax in axeslist:
im = ax.imshow(z, cmap=plt.cm.Blues, interpolation='nearest')
ax.tick_params(labelbottom='off',labeltop='off', labelleft="off", labelright='off',
bottom='off', top='off', left='off', right='off')
if ax == axeslist[0]:
ax.set_title('Avg. (s)\n', size=13)
elif ax == axeslist[-1]:
ax.tick_params(bottom='on', labelbottom='on')
ax.set_xticks(range(len(x)))
ax.set_xticklabels(x)
# reserve some space between the subplots
fig.subplots_adjust(hspace=0.07*(numRows-1))
# create the overlay images, add them as extra properties of the original images
for ax in axeslist:
axnew = fig.add_axes(ax.get_position(), frameon=False)
axnew.tick_params(labelbottom='off',labeltop='on', labelleft="off", labelright='off',
bottom='off', top='on', left='off', right='off')
axnew.set_xlim(ax.get_xlim())
axnew.set_xticks(range(len(y)))
axnew.set_xticklabels(y)
ax.extra_axes = axnew
# update the secondary axes positions
# draw() only if there was something changed (important!)
def update_secondary(event=None):
position_changed = False
for ax in axeslist:
if ax.extra_axes.get_position().bounds == ax.get_position().bounds:
continue
position_changed = True
ax.extra_axes.set_position(ax.get_position())
if position_changed:
plt.draw()
# register the secondary axes updater as a callback
fig.canvas.mpl_connect('draw_event', update_secondary)
# make sure everything is drawn
plt.draw()
由于重叠的更新必须在其他所有内容绘制完后进行,这里是通过后端的draw_event
来完成的。结果是,在某些原因下图像被重新绘制后,重叠部分会被重新调整,如果有任何位置发生变化,整个场景会被重新绘制。
这个方法有效,但看起来不太美观。