質問

I would like to position a colorbar inside a scatter plot by specifying the position in data coordinates. Here is an example of how it works when specifying figure coordinates:

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

...Ok, can't include an image of the plot here because I am lacking reputation. But the above code will give you an impression....

Now the question is, how could I position the colorbar at data coordinates, to appear at e.g.: left, bottom, width, height: -1.5, 1.5, 1, 0.25

I have experimented with a few things, like determining the axes position within the figure and transforming it to data coordinates but didn't succeed.

Many thanks for ideas or pointing me to already answered similar questions!

Here is what I did (not particularly beautiful but it helps). Thanks 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()
役に立ちましたか?

解決

Here is what I did, based on the comments to my original question:

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

他のヒント

Two step to specify the position in data coordinates of an Axes:

  1. use Axes.set_axes_locator() to set a function that return a Bbox object in figure coordinate.
  2. set the clip box of all children in the Axes by set_clip_box() method:

Here is the full code:

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

And here is the output:

enter image description here

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top