|
From: Charles R. T. <ct...@gm...> - 2006-01-10 19:37:11
|
Alas, another question. I want to place text inside the plot, just below the top xaxis ticks. Previously I had hacked this as: sp.text(0.5, 0.96, title_str, font, transform=3Dax.transAxes) But as the graphs get taller, the text gets too far away from the top line. What I think I want is to put the top-aligned text at something like: (top - markerlen) in pixel coordinates. But where to find the properties and transforms I need? Many thanks. I will await a question I can answer. -C -- Charles R. Twardy |
|
From: Jouni K S. <jk...@ik...> - 2006-01-11 08:11:51
|
"Charles R. Twardy" <ct...@gm...> writes: > I want to place text inside the plot, just below the top xaxis ticks. > But as the graphs get taller, the text gets too far away from the top line. I wanted to do something similar, and wrote an example in the Wiki, at the bottom of http://www.scipy.org/wikis/topical_software/Transformations Does this help with your problem? -- Jouni |
|
From: Charles R. T. <ct...@gm...> - 2006-01-11 13:20:11
|
> http://www.scipy.org/wikis/topical_software/Transformations > > Does this help with your problem? Jouni, I don't think so. I looked at that. Maybe I'm mistaken, but seems that in the end, it just places the text at y position 0.9 in Axes coordinates. That's just below the markers for small subplots, but WAY below the markers for tall skinny ones. I want it to place the text at a fixed absolute y position of just below the markers. As the graph gets taller, that will go from .9 to .95 to .99, etc. in Axes coordinates. So one approach would be to find the Axes coordinates for the lower limit of the tick markers. Any ideas? -C -- Charles R. Twardy |
|
From: John H. <jdh...@ac...> - 2006-01-11 15:07:11
|
>>>>> "Charles" == Charles R Twardy <ct...@gm...> writes:
Charles> I don't think so. I looked at that. Maybe I'm mistaken,
Charles> but seems that in the end, it just places the text at y
Charles> position 0.9 in Axes coordinates. That's just below the
Charles> markers for small subplots, but WAY below the markers for
Charles> tall skinny ones. I want it to place the text at a fixed
Charles> absolute y position of just below the markers. As the
Charles> graph gets taller, that will go from .9 to .95 to .99,
Charles> etc. in Axes coordinates.
Charles> So one approach would be to find the Axes coordinates for
Charles> the lower limit of the tick markers. Any ideas?
This is a bit tricky but doable. The transformation that places the
xticks is a "blend" of the data transform and the axes transform, in
that the x value of the x ticks is a data coord, and the y value is an
axes coord(0 is bottom, 1 is top). The transform module provides a
helper function to build such a beast
from matplotlib.transforms import blend_xy_sep_transform
trans = blend_xy_sep_transform(ax.transData, ax.transAxes)
If you then make a call to text
ax.text(.2,1,'hi mom', transform=trans)
it will be placed at the top of the yaxis at 0.2 on the xaxis.
What you want to do is offset this by a couple of points below the
tick like. To do this, you need to set an offset on the transform,
where the coordinates of the offset are in points. The offset is
always an xy tuple with a transform to transform that tuple into
figure coords. In the case of points, you want to do
scale = fig.dpi/Value(72.) # points -> pixels
point_trans = scale_transform(scale, scale)
trans.set_offset((0,-ticksize-2),point_trans)
Here is a complete example: now when you resize the figure window or
pan/zoom your text will remain 2 points below the ticks...
from matplotlib import rcParams
import matplotlib.numerix as nx
from pylab import figure, show
from matplotlib.transforms import blend_xy_sep_transform, Value, scale_transform
ticksize = rcParams['xtick.major.size']
fig = figure()
ax = fig.add_subplot(111)
x,y = nx.mlab.rand(2,100)
ax.plot(x,y)
locs = nx.arange(0,1.0,0.2)
ax.set_xticks(locs)
trans = blend_xy_sep_transform(ax.transData, ax.transAxes)
scale = fig.dpi/Value(72.) # points -> pixels
point_trans = scale_transform(scale, scale)
# the offset is an xy tup and a transformation instance for that tuple
trans.set_offset((0,-ticksize-2),point_trans)
for loc in locs:
ax.text(loc,1,'%1.1f'%loc, transform=trans, va='top', ha='center')
show()
|
|
From: Charles R. T. <ct...@gm...> - 2006-01-11 22:10:18
|
John, Thanks, that did it. I don't really need to blend though. What I need it taken care of by: #trans =3D blend_xy_sep_transform(ax.transData, ax.transAxes) trans =3D blend_xy_sep_transform(ax.transAxes, ax.transAxes) scale =3D fig.dpi/Value(72.) # points -> pixels point_trans =3D scale_transform(scale, scale) trans.set_offset((0,-ticksize-2),point_trans) ax.text(0.5, 1, "My Title", ha=3D'center', va=3D'top', transform=3Dtrans) It seems a bit silly to call the blend_xy transform for that (since I'm using transAxes for both x and y), but copy.copy doesn't work, so there we are. Thanks again. -C On 1/11/06, John Hunter <jdh...@ni...> wrote: > >>>>> "Charles" =3D=3D Charles R Twardy <ct...@gm...> writes: > > Charles> I don't think so. I looked at that. Maybe I'm mistaken, > Charles> but seems that in the end, it just places the text at y > Charles> position 0.9 in Axes coordinates. That's just below the > Charles> markers for small subplots, but WAY below the markers for > Charles> tall skinny ones. I want it to place the text at a fixed > Charles> absolute y position of just below the markers. As the > Charles> graph gets taller, that will go from .9 to .95 to .99, > Charles> etc. in Axes coordinates. > > Charles> So one approach would be to find the Axes coordinates for > Charles> the lower limit of the tick markers. Any ideas? > > This is a bit tricky but doable. The transformation that places the > xticks is a "blend" of the data transform and the axes transform, in > that the x value of the x ticks is a data coord, and the y value is an > axes coord(0 is bottom, 1 is top). The transform module provides a > helper function to build such a beast > > from matplotlib.transforms import blend_xy_sep_transform > trans =3D blend_xy_sep_transform(ax.transData, ax.transAxes) > > > If you then make a call to text > > ax.text(.2,1,'hi mom', transform=3Dtrans) > > it will be placed at the top of the yaxis at 0.2 on the xaxis. > > > What you want to do is offset this by a couple of points below the > tick like. To do this, you need to set an offset on the transform, > where the coordinates of the offset are in points. The offset is > always an xy tuple with a transform to transform that tuple into > figure coords. In the case of points, you want to do > > > scale =3D fig.dpi/Value(72.) # points -> pixels > point_trans =3D scale_transform(scale, scale) > trans.set_offset((0,-ticksize-2),point_trans) > > > > Here is a complete example: now when you resize the figure window or > pan/zoom your text will remain 2 points below the ticks... > > from matplotlib import rcParams > import matplotlib.numerix as nx > from pylab import figure, show > from matplotlib.transforms import blend_xy_sep_transform, Value, scale_tr= ansform > > ticksize =3D rcParams['xtick.major.size'] > > fig =3D figure() > ax =3D fig.add_subplot(111) > x,y =3D nx.mlab.rand(2,100) > ax.plot(x,y) > locs =3D nx.arange(0,1.0,0.2) > ax.set_xticks(locs) > > > trans =3D blend_xy_sep_transform(ax.transData, ax.transAxes) > scale =3D fig.dpi/Value(72.) # points -> pixels > point_trans =3D scale_transform(scale, scale) > > # the offset is an xy tup and a transformation instance for that tuple > trans.set_offset((0,-ticksize-2),point_trans) > > for loc in locs: > ax.text(loc,1,'%1.1f'%loc, transform=3Dtrans, va=3D'top', ha=3D'cente= r') > show() > > -- Charles R. Twardy |
|
From: John H. <jdh...@ac...> - 2006-01-11 22:42:28
|
>>>>> "Charles" == Charles R Twardy <ct...@gm...> writes:
Charles> John, Thanks, that did it. I don't really need to blend
Charles> though. What I need it taken care of by:
trans = blend_xy_sep_transform(ax.transAxes, ax.transAxes)
This is basically a no-op; if the axes transform is the one you want,
just use it
ax.text(0.5, 1, "My Title", ha='center', va='top',transform=ax.transAxes)
My example placed the text below the ticks, which is where the data
component came in.
JDH
|
|
From: Charles R. T. <ct...@gm...> - 2006-01-12 18:17:28
|
> trans =3D blend_xy_sep_transform(ax.transAxes, ax.transAxes) > > This is basically a no-op; if the axes transform is the one you want, > just use it > > ax.text(0.5, 1, "My Title", ha=3D'center', va=3D'top',transform=3Dax.tr= ansAxes) Can't do that. Puts the text too high, runs into the top bar and the tickm= arks. Can't apply the offset to ax.transAxes either -- it changes *EVERYTHING*. The old "assignment is reference" problem. But if blend is nearly a no-op, then I'll use it. I don't need a data component to put the text below the tickmarks. But I *did* need the magic offset numbers rcParams['xtick.major.size'] and gcf().dpi/Value(72.), plus your knowledge of scale_transform and set_offset. And it seems blend_ gives me a copy operator for transAxes. Thanks! Thanks! Thanks! -C -- Charles R. Twardy |
|
From: John H. <jdh...@ac...> - 2006-01-12 18:31:54
|
>>>>> "Charles" == Charles R Twardy <ct...@gm...> writes:
>> trans = blend_xy_sep_transform(ax.transAxes, ax.transAxes)
>>
>> This is basically a no-op; if the axes transform is the one you
>> want, just use it
>>
>> ax.text(0.5, 1, "My Title", ha='center',
>> va='top',transform=ax.transAxes)
Charles> Can't do that. Puts the text too high, runs into the top
Charles> bar and the tickmarks. Can't apply the offset to
Oh right (slaps self on head). You need to set the offset on the
transform and you can't apply that to ax.transAxes since it will screw
up the axes transform... So you need to copy it, or duplicate it.
blend is one way to copy the transform, but there is a better way --
just mimic what axes.py does when it creates it.
from matplotlib.transforms import unit_bbox, get_bbox_transform
trans = get_bbox_transform(unit_bbox(), ax.bbox)
this transforms the (0,0), (1,1) bounding box to the axes bounding
box. You can then set the offset of this transform as before...
JDH
|
|
From: Charles R. T. <ct...@gm...> - 2006-01-13 20:46:25
|
Excellent! Thanks again! > from matplotlib.transforms import unit_bbox, get_bbox_transform > trans =3D get_bbox_transform(unit_bbox(), ax.bbox) -- Charles R. Twardy |