Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6858631

Browse files
committed
Make it easier to plot text etc. with an offset: transforms.offset_copy().
svn path=/trunk/matplotlib/; revision=2638
1 parent ea70ba4 commit 6858631

4 files changed

Lines changed: 136 additions & 7 deletions

File tree

examples/transoffset.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python
2+
3+
'''
4+
This illustrates the use of transforms.offset_copy to
5+
make a transform that positions a drawing element such as
6+
a text string at a specified offset in screen coordinates
7+
(dots or inches) relative to a location given in any
8+
coordinates.
9+
10+
Every Artist--the mpl class from which classes such as
11+
Text and Line are derived--has a transform that can be
12+
set when the Artist is created, such as by the corresponding
13+
pylab command. By default this is usually the Axes.transData
14+
transform, going from data units to screen dots. We can
15+
use the offset_copy function to make a modified copy of
16+
this transform, where the modification consists of an
17+
offset.
18+
'''
19+
20+
import pylab as P
21+
from matplotlib.transforms import offset_copy
22+
23+
X = P.arange(7)
24+
Y = P.rand(7)
25+
26+
ax = P.subplot(1,1,1)
27+
28+
# If we want the same offset for each text instance,
29+
# we only need to make one transform. To get the
30+
# transform argument to offset_copy, we need to make the axes
31+
# first; the subplot command above is one way to do this.
32+
transOffset = offset_copy(ax.transData, fig=P.gcf(),
33+
x = 0.05, y=0.10, units='inches')
34+
35+
for x, y in zip(X, Y):
36+
P.plot((x,),(y,), 'ro')
37+
P.text(x, y, '%0.2f, %0.2f' % (x,y), transform=transOffset)
38+
39+
P.figure()
40+
41+
42+
# offset_copy works for polar plots also, but one can't simply
43+
# make an axes with subplot and then use the polar command to plot
44+
# in it. (This is a bug.) One way to get around this while
45+
# sticking with the pylab interface is to grab the transform
46+
# after the first polar() command.
47+
first = True
48+
for x, y in zip(X, Y):
49+
L = P.polar((x,),(y,), 'ro')
50+
if first:
51+
transOffset = offset_copy(P.gca().transData, fig=P.gcf(),
52+
y = 6, units='dots')
53+
first = False
54+
P.text(x, y, '%0.2f, %0.2f' % (x,y),
55+
transform=transOffset,
56+
horizontalalignment='center',
57+
verticalalignment='bottom')
58+
59+
60+
P.show()
61+

lib/matplotlib/transforms.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@
121121
xy_tup(xy) - transform the tuple (x,y)
122122
seq_x_y(x, y) - transform the python sequences x and y
123123
numerix_x_y(x, y) - x and y are numerix 1D arrays
124-
seq_xy_tups(seq) - seq is a sequence of xy tuples
124+
numerix_xy(xy) - xy is a numerix array of shape (N,2)
125+
inverse_numerix_xy(xy)- inverse of the above
126+
seq_xy_tups(seq) - seq is a sequence of xy tuples or a (N,2) array
125127
inverse_xy_tup(xy) - apply the inverse transformation to tuple xy
126128
127129
set_offset(xy, trans) - xy is an x,y tuple and trans is a
@@ -141,6 +143,7 @@
141143
set_funcx() - set the Func instance on x
142144
set_funcy() - set the Func instance on y
143145
146+
144147
Affine transformations
145148
----------------------
146149
@@ -423,9 +426,11 @@ def inverse_transform_bbox(trans, bbox):
423426
return Bbox(Point(Value(xmin), Value(ymin)),
424427
Point(Value(xmax), Value(ymax)))
425428

429+
## begin possibly deleted block; all transforms have deepcopy
430+
## and shallowcopy methods, we may not need any of the following
426431

427-
def copy_bbox_transform(trans):
428-
'return a deep copy of the bbox transform'
432+
def copy_separable_transform(trans):
433+
'return a deep copy of the separable transform'
429434

430435
inbox = trans.get_bbox1()
431436
xmin, xmax = inbox.intervalx().get_bounds()
@@ -436,7 +441,7 @@ def copy_bbox_transform(trans):
436441
outbox = trans.get_bbox2()
437442
xmin, xmax = outbox.intervalx().get_bounds()
438443
ymin, ymax = outbox.intervaly().get_bounds()
439-
444+
440445
newOutbox = Bbox( Point(Value(xmin), Value(ymin)),
441446
Point(Value(xmax), Value(ymax)) )
442447

@@ -449,10 +454,12 @@ def copy_bbox_transform(trans):
449454
newtrans.get_funcy().set_type(typey)
450455
return newtrans
451456

457+
copy_bbox_transform = copy_separable_transform
458+
452459

453-
def copy_bbox_transform_shallow(trans):
460+
def copy_separable_transform_shallow(trans):
454461
"""
455-
return a shallow copy of the bbox transform -- the Values are
462+
return a shallow copy of the separable transform -- the Values are
456463
retained by reference but the transform is copied. This allows
457464
you to copy a transform, set a new offset to it, but not lose the
458465
value reference semantics
@@ -470,6 +477,37 @@ def copy_bbox_transform_shallow(trans):
470477
newtrans.get_funcy().set_type(typey)
471478
return newtrans
472479

480+
copy_bbox_transform_shallow = copy_separable_transform_shallow
481+
482+
def copy_transform_shallow(trans):
483+
return trans.shallowcopy()
484+
485+
## end possibly deleted block
486+
487+
def offset_copy(trans, fig=None, x=0, y=0, units='inches'):
488+
'''
489+
Return a shallow copy of a transform with an added offset.
490+
args:
491+
trans is any transform
492+
kwargs:
493+
fig is the current figure; it can be None if units are 'dots'
494+
x, y give the offset in units of 'inches' or 'dots'
495+
units is 'inches' or 'dots'
496+
'''
497+
newtrans = trans.shallowcopy()
498+
if units == 'dots':
499+
newtrans.set_offset((x,y), identity_transform())
500+
return newtrans
501+
if not units == 'inches':
502+
raise ValueError('units must be dots or inches')
503+
if fig is None:
504+
raise ValueError('For units of inches a fig kwarg is needed')
505+
tx = Value(x) * fig.dpi
506+
ty = Value(y) * fig.dpi
507+
newtrans.set_offset((0,0), translation_transform(tx, ty))
508+
return newtrans
509+
510+
473511
def get_vec6_scales(v):
474512
'v is an affine vec6 a,b,c,d,tx,ty; return sx, sy'
475513
a,b,c,d = v[:4]

src/_transforms.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1615,7 +1615,16 @@ Py::Object
16151615
SeparableTransformation::deepcopy(const Py::Tuple &args) {
16161616
_VERBOSE("SeparableTransformation::deepcopy");
16171617
args.verify_length(0);
1618-
return Py::asObject( new SeparableTransformation( static_cast<Bbox*>((_b1->_deepcopy()).ptr()),static_cast<Bbox*>((_b2->_deepcopy()).ptr()), _funcx,_funcy ));
1618+
return Py::asObject( new SeparableTransformation(
1619+
static_cast<Bbox*>((_b1->_deepcopy()).ptr()),
1620+
static_cast<Bbox*>((_b2->_deepcopy()).ptr()), _funcx,_funcy ));
1621+
}
1622+
1623+
Py::Object
1624+
SeparableTransformation::shallowcopy(const Py::Tuple &args) {
1625+
_VERBOSE("SeparableTransformation::shallowcopy");
1626+
args.verify_length(0);
1627+
return Py::asObject( new SeparableTransformation(_b1, _b2, _funcx,_funcy ));
16191628
}
16201629

16211630
NonseparableTransformation::NonseparableTransformation(Bbox *b1, Bbox *b2, FuncXY *funcxy) :
@@ -1799,6 +1808,14 @@ NonseparableTransformation::deepcopy(const Py::Tuple &args) {
17991808
return Py::asObject( new NonseparableTransformation( static_cast<Bbox*>((_b1->_deepcopy()).ptr()),static_cast<Bbox*>((_b2->_deepcopy()).ptr()), _funcxy ));
18001809
}
18011810

1811+
Py::Object
1812+
NonseparableTransformation::shallowcopy(const Py::Tuple &args) {
1813+
_VERBOSE("NonseparableTransformation::shallowcopy");
1814+
args.verify_length(0);
1815+
return Py::asObject( new NonseparableTransformation(_b1,_b2, _funcxy ));
1816+
}
1817+
1818+
18021819
Affine::Affine(LazyValue *a, LazyValue *b, LazyValue *c,
18031820
LazyValue *d, LazyValue *tx, LazyValue *ty) :
18041821
_a(a), _b(b), _c(c), _d(d), _tx(tx), _ty(ty) {
@@ -1939,6 +1956,14 @@ Affine::deepcopy(const Py::Tuple &args) {
19391956
new Value(_dval),new Value(_txval),new Value(_tyval) ));
19401957
}
19411958

1959+
Py::Object
1960+
Affine::shallowcopy(const Py::Tuple &args) {
1961+
_VERBOSE("Affine::shallowcopy");
1962+
args.verify_length(0);
1963+
1964+
return Py::asObject( new Affine( _a, _b, _c, _d, _tx, _ty ));
1965+
}
1966+
19421967

19431968

19441969
/* ------------ module methods ------------- */
@@ -2270,6 +2295,7 @@ Transformation::init_type()
22702295
add_varargs_method("as_vec6", &Transformation::as_vec6, "as_vec6(): return the affine as length 6 list of Values\n");
22712296
add_varargs_method("as_vec6_val", &Transformation::as_vec6_val, "as_vec6_val(): return the affine as length 6 list of float\n");
22722297
add_varargs_method("deepcopy", &Transformation::deepcopy, "deepcopy()\n");
2298+
add_varargs_method("shallowcopy", &Transformation::shallowcopy, "shallowcopy()\n");
22732299

22742300
}
22752301

src/_transforms.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ class Transformation: public Py::PythonExtension<Transformation> {
609609
Py::Object nonlinear_only_numerix(const Py::Tuple &args, const Py::Dict &kwargs);
610610
Py::Object inverse_xy_tup(const Py::Tuple &args);
611611
virtual Py::Object deepcopy(const Py::Tuple &args) =0;
612+
virtual Py::Object shallowcopy(const Py::Tuple &args) =0;
612613

613614
//freeze the lazy values and don't relax until thawed
614615
Py::Object freeze(const Py::Tuple &args) {
@@ -712,6 +713,7 @@ class SeparableTransformation: public BBoxTransformation {
712713
void arrayOperator(const int length, const double x[], const double y[], double newx[], double newy[]);
713714

714715
Py::Object deepcopy(const Py::Tuple &args) ;
716+
Py::Object shallowcopy(const Py::Tuple &args) ;
715717

716718
protected:
717719
Func *_funcx, *_funcy;
@@ -732,6 +734,7 @@ class NonseparableTransformation: public BBoxTransformation {
732734
std::pair<double, double> & inverse_api(const double &x, const double &y);
733735
void arrayOperator(const int length, const double x[], const double y[], double newx[], double newy[]);
734736
Py::Object deepcopy(const Py::Tuple &args) ;
737+
Py::Object shallowcopy(const Py::Tuple &args) ;
735738

736739
void nonlinear_only_api(double *x, double *y);
737740

@@ -760,6 +763,7 @@ class Affine: public Transformation {
760763
std::pair<double, double> & inverse_api(const double &x, const double &y);
761764
void eval_scalars(void);
762765
Py::Object deepcopy(const Py::Tuple &args);
766+
Py::Object shallowcopy(const Py::Tuple &args);
763767

764768
void affine_params_api(double* a, double* b, double* c, double*d, double* tx, double* ty);
765769
private:

0 commit comments

Comments
 (0)