Python matplotlib:如何在数据坐标系中定位colorbar

8

我希望能够通过指定数据坐标的位置来将颜色条放置在散点图内部。 以下是在指定图坐标的情况下它的工作原理的示例:

import numpy as np
import matplotlib.pyplot as plt    

#Generate some random data:
a = -2
b = 2
x = (b - a) * np.random.random(50) + a
y = (b - a) * np.random.random(50) + a
z = (b) * np.random.random(50)

#Do a scatter plot
fig = plt.figure()
hdl = plt.scatter(x,y,s=20,c=z,marker='o',vmin=0,vmax=2)
ax = plt.gca()
ax.set_xlim([-2,2])
ax.set_ylim([-2,2])

#Specifying figure coordinates works fine:
fig_coord = [0.2,0.8,0.25,0.05]
cbar_ax = fig.add_axes(fig_coord)

clevs = [0, 1 , 2]
cb1 = plt.colorbar(hdl, cax=cbar_ax, orientation='horizontal', ticks=clevs)

plt.show()

现在的问题是,我该如何将颜色条定位到数据坐标上,例如出现在: left, bottom, width, height: -1.5, 1.5, 1, 0.25

我尝试过一些方法,比如确定图中轴的位置并将其转换为数据坐标,但没有成功。

非常感谢您提供的想法或指向已经解决类似问题的链接!

这是我所做的(不是特别美观,但很有帮助)。感谢tcaswell!

#[lower left x, lower left y, upper right x, upper right y] of the desired colorbar:
dat_coord = [-1.5,1.5,-0.5,1.75]
#transform the two points from data coordinates to display coordinates:
tr1 = ax.transData.transform([(dat_coord[0],dat_coord[1]),(dat_coord[2],dat_coord[3])])
#create an inverse transversion from display to figure coordinates:
inv = fig.transFigure.inverted()
tr2 = inv.transform(tr1)
#left, bottom, width, height are obtained like this:
datco = [tr2[0,0], tr2[0,1], tr2[1,0]-tr2[0,0],tr2[1,1]-tr2[0,1]]
#and finally the new colorabar axes at the right position!
cbar_ax = fig.add_axes(datco)
#the rest stays the same:
clevs = [0, 1 , 2]
cb1 = plt.colorbar(hdl, cax=cbar_ax, orientation='horizontal', ticks=clevs)

plt.show()

1
色条在它自己的轴对象中,因此您无法指定它在数据单位中的位置。您可以确定正确的图形坐标,以便在数据空间中处于给定位置,但如果您平移/缩放,它将不会更新。 - tacaswell
请参阅:http://matplotlib.org/1.3.1/users/transforms_tutorial.html 您想要进行数据->屏幕->图形的操作。 - tacaswell
非常感谢,您的评论帮助解决了我的问题。 - yngwaz
你能否把你所做的作为回答写在自己的问题中呢? - tacaswell
我本想这样做的,但是我的声望不足,无法在大约8小时内回答自己的问题...这就是为什么我编辑了我的问题并附上了答案... - yngwaz
有趣...好的,如果时间允许,请进行编写,这样既可以整理代码,也可以获得声望,如果其他人发现它有用的话。 - tacaswell
2个回答

2

根据我最初提问的评论,这是我所做的:

import numpy as np
import matplotlib.pyplot as plt    

a = -2
b = 2

x = (b - a) * np.random.random(50) + a
y = (b - a) * np.random.random(50) + a
z = (b) * np.random.random(50)

fig = plt.figure()
hdl = plt.scatter(x,y,s=20,c=z,marker='o',vmin=0,vmax=2)
ax = plt.gca()
ax.set_xlim([-2,2])
ax.set_ylim([-2,2])

#[(lower left x, lower left y), (upper right x, upper right y)] of the desired colorbar:
dat_coord = [(-1.5,1.5),(-0.5,1.75)]
#transform the two points from data coordinates to display coordinates:
tr1 = ax.transData.transform(dat_coord)
#create an inverse transversion from display to figure coordinates:
inv = fig.transFigure.inverted()
tr2 = inv.transform(tr1)
#left, bottom, width, height are obtained like this:
datco = [tr2[0,0], tr2[0,1], tr2[1,0]-tr2[0,0],tr2[1,1]-tr2[0,1]]
#and finally the new colorabar axes at the right position!
cbar_ax = fig.add_axes(datco)
#the rest stays the same:
clevs = [0, 1 , 2]
cb1 = plt.colorbar(hdl, cax=cbar_ax, orientation='horizontal', ticks=clevs)

plt.show()

1

指定Axes中数据坐标的位置有两个步骤:

  1. 使用Axes.set_axes_locator()设置一个返回Bbox对象在图像坐标系中的函数。
  2. 通过set_clip_box()方法设置Axes中所有子元素的剪辑框:

以下是完整代码:

import numpy as np
import matplotlib.pyplot as plt    

#Generate some random data:
a = -2
b = 2
x = (b - a) * np.random.random(50) + a
y = (b - a) * np.random.random(50) + a
z = (b) * np.random.random(50)

#Do a scatter plot
fig = plt.figure()
hdl = plt.scatter(x,y,s=20,c=z,marker='o',vmin=0,vmax=2)
ax = plt.gca()
ax.set_xlim([-2,2])
ax.set_ylim([-2,2])

#Specifying figure coordinates works fine:
fig_coord = [0.2,0.8,0.25,0.05]
cbar_ax = fig.add_axes(fig_coord)

def get_ax_loc(cbar_ax, render):
    from matplotlib.transforms import Bbox
    tr = ax.transData + fig.transFigure.inverted()
    bbox = Bbox(tr.transform([[1, -0.5], [1.8, 0]]))
    return bbox

clevs = [0, 1 , 2]
cb1 = plt.colorbar(hdl, cax=cbar_ax, orientation='horizontal', ticks=clevs)

def get_ax_loc(cbar_ax, render):
    from matplotlib.transforms import Bbox
    tr = ax.transData + fig.transFigure.inverted()
    bbox = Bbox(tr.transform([[1, -0.5], [1.8, 0]]))
    return bbox

def set_children_clip_box(artist, box):
    for c in artist.get_children():
        c.set_clip_box(box)
        set_children_clip_box(c, box)

cbar_ax.set_axes_locator(get_ax_loc)
set_children_clip_box(cbar_ax, hdl.get_clip_box())

plt.show()

这里是输出:

enter image description here


谢谢这个解决方案,它看起来比我的更强大。唯一的缺点是,我无法将数据坐标传递给函数get_ax_loc。 - yngwaz

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