8000 Merge remote-tracking branch 'upstream/v1.2.x' · matplotlib/matplotlib@96ecc79 · GitHub
[go: up one dir, main page]

Skip to content

Commit 96ecc79

Browse files
committed
Merge remote-tracking branch 'upstream/v1.2.x'
Conflicts: .travis.yml lib/matplotlib/tests/baseline_images/test_png/pngsuite.png lib/matplotlib/tests/test_axes.py
2 parents b6b9062 + 1909fef commit 96ecc79

File tree

8 files changed

+118
-10
lines changed

8 files changed

+118
-10
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ python:
44
- 2.6
55
- 2.7
66
- 3.2
7+
- 3.3
78

89
install:
910
- pip install --use-mirrors nose python-dateutil

lib/matplotlib/axes.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9283,7 +9283,14 @@ def _make_twin_axes(self, *kl, **kwargs):
92839283
"""
92849284
make a twinx axes of self. This is used for twinx and twiny.
92859285
"""
9286-
ax2 = self.figure.add_subplot(self.get_subplotspec(), *kl, **kwargs)
9286+
from matplotlib.projections import process_projection_requirements
9287+
kl = (self.get_subplotspec(),) + kl
9288+
projection_class, kwargs, key = process_projection_requirements(
9289+
self.figure, *kl, **kwargs)
9290+
9291+
ax2 = subplot_class_factory(projection_class)(self.figure,
9292+
*kl, **kwargs)
9293+
self.figure.add_subplot(ax2)
92879294
return ax2
92889295

92899296
_subplot_classes = {}

lib/matplotlib/backends/backend_svg.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import division
22

3-
import os, base64, tempfile, urllib, gzip, io, sys, codecs
3+
import os, base64, tempfile, urllib, gzip, io, sys, codecs, re
44

55
import numpy as np
66

@@ -71,6 +71,11 @@ def escape_cdata(s):
7171
s = s.replace(u">", u">")
7272
return s
7373

74+
_escape_xml_comment = re.compile(r'-(?=-)')
75+
def escape_comment(s):
76+
s = escape_cdata(s)
77+
return _escape_xml_comment.sub('- ', s)
78+
7479
def escape_attrib(s):
7580
s = s.replace(u"&", u"&")
7681
s = s.replace(u"'", u"'")
@@ -146,7 +151,7 @@ def start(self, tag, attrib={}, **extra):
146151
def comment(self, comment):
147152
self.__flush()
148153
self.__write(self.__indentation[:len(self.__tags)])
149-
self.__write(u"<!-- %s -->\n" % escape_cdata(comment))
154+
self.__write(u"<!-- %s -->\n" % escape_comment(comment))
150155

151156
##
152157
# Adds character data to the output stream.

lib/matplotlib/collections.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ def contains(self, mouseevent):
305305
ind = mpath.point_in_path_collection(
306306
mouseevent.x, mouseevent.y, pickradius,
307307
transform.frozen(), paths, self.get_transforms(),
308-
offsets, transOffset, pickradius <= 0)
308+
offsets, transOffset, pickradius <= 0,
309+
self.get_offset_position())
309310

310311
return len(ind) > 0, dict(ind=ind)
311312

Loading

lib/matplotlib/tests/test_artist.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import print_function
22

3+
import numpy as np
4+
35
from matplotlib.testing.decorators import cleanup
46

57
import matplotlib.pyplot as plt
@@ -88,6 +90,19 @@ def test_collection_transform_of_none():
8890
assert isinstance(c._transOffset, mtrans.IdentityTransform)
8991

9092

93+
def test_point_in_path():
94+
from matplotlib.path import Path
95+
96+
# Test #1787
97+
verts2 = [(0,0), (0,1), (1,1), (1,0), (0,0)]
98+
99+
path = Path(verts2, closed=True)
100+
points = [(0.5,0.5), (1.5,0.5)]
101+
102+
assert np.all(path.contains_points(points) == [True, False])
103+
104+
105+
91106
if __name__=='__main__':
92107
import nose
93108
nose.runmodule(argv=['-s','--with-doctest'], exit=False)

lib/matplotlib/tests/test_axes.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,24 @@ def test_hexbin_extent():
438438

439439
ax.hexbin(x, y, extent=[.1, .3, .6, .7])
440440

441+
@cleanup
442+
def test_hexbin_pickable():
443+
# From #1973: Test that picking a hexbin collection works
444+
c 10000 lass FauxMouseEvent:
445+
def __init__(self, x, y):
446+
self.x = x
447+
self.y = y
448+
449+
fig = plt.figure()
450+
451+
ax = fig.add_subplot(111)
452+
data = np.arange(200.)/200.
453+
data.shape = 2, 100
454+
x, y = data
455+
hb = ax.hexbin(x, y, extent=[.1, .3, .6, .7], picker=1)
456+
457+
assert hb.contains(FauxMouseEvent(400, 300))[0]
458+
441459
@image_comparison(baseline_images=['hexbin_log'],
442460
remove_text=True,
443461
extensions=['png'])
@@ -1497,6 +1515,53 @@ def test_csd_noise():
14971515
ax3.set_ylabel('')
14981516

14991517

1518+
@image_comparison(baseline_images=['twin_spines'], remove_text=True,
1519+
extensions=['png'])
1520+
def test_twin_spines():
1521+
1522+
def make_patch_spines_invisible(ax):
1523+
ax.set_frame_on(True)
1524+
ax.patch.set_visible(False)
1525+
for sp in ax.spines.itervalues():
1526+
sp.set_visible(False)
1527+
1528+
fig = plt.figure(figsize=(4, 3))
1529+
fig.subplots_adjust(right=0.75)
1530+
1531+
host = fig.add_subplot(111)
1532+
par1 = host.twinx()
1533+
par2 = host.twinx()
1534+
1535+
# Offset the right spine of par2. The ticks and label have already been
1536+
# placed on the right by twinx above.
1537+
par2.spines["right"].set_position(("axes", 1.2))
1538+
# Having been created by twinx, par2 has its frame off, so the line of its
1539+
# detached spine is invisible. First, activate the frame but make the patch
1540+
# and spines invisible.
1541+
make_patch_spines_invisible(par2)
1542+
# Second, show the right spine.
1543+
par2.spines["right"].set_visible(True)
1544+
1545+
p1, = host.plot([0, 1, 2], [0, 1, 2], "b-")
1546+
p2, = par1.plot([0, 1, 2], [0, 3, 2], "r-")
1547+
p3, = par2.plot([0, 1, 2], [50, 30, 15], "g-")
1548+
1549+
host.set_xlim(0, 2)
1550+
host.set_ylim(0, 2)
1551+
par1.set_ylim(0, 4)
1552+
par2.set_ylim(1, 65)
1553+
1554+
host.yaxis.label.set_color(p1.get_color())
1555+
par1.yaxis.label.set_color(p2.get_color())
1556+
par2.yaxis.label.set_color(p3.get_color())
1557+
1558+
tkw = dict(size=4, width=1.5)
1559+
host.tick_params(axis='y', colors=p1.get_color(), **tkw)
1560+
par1.tick_params(axis='y', colors=p2.get_color(), **tkw)
1561+
par2.tick_params(axis='y', colors=p3.get_color(), **tkw)
1562+
host.tick_params(axis='x', **tkw)
1563+
1564+
15001565
if __name__ == '__main__':
15011566
import nose
15021567
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

src/_path.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ point_in_path_impl(const void* const points_, const size_t s0,
128128
npy_bool* const inside_flag)
129129
{
130130
int *yflag0;
131+
int *subpath_flag;
131132
int yflag1;
132133
double vtx0, vty0, vtx1, vty1;
133134
double tx, ty;
@@ -138,6 +139,7 @@ point_in_path_impl(const void* const points_, const size_t s0,
138139
const char *const points = (const char * const)points_;
139140

140141
yflag0 = (int *)malloc(n * sizeof(int));
142+
subpath_flag = (int *)malloc(n * sizeof(int));
141143

142144
path.rewind(0);
143145

@@ -151,6 +153,10 @@ point_in_path_impl(const void* const points_, const size_t s0,
151153
if (code != agg::path_cmd_move_to)
152154
{
153155
code = path.vertex(&x, &y);
156+
if (code == agg::path_cmd_stop ||
157+
(code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
158+
continue;
159+
}
154160
}
155161

156162
sx = vtx0 = vtx1 = x;
@@ -162,7 +168,7 @@ point_in_path_impl(const void* const points_, const size_t s0,
162168
// get test bit for above/below X axis
163169
yflag0[i] = (vty0 >= ty);
164170

165-
inside_flag[i] = 0;
171+
subpath_flag[i] = 0;
166172
}
167173

168174
do
@@ -208,7 +214,7 @@ point_in_path_impl(const void* const points_, const size_t s0,
208214
// tests.
209215
if (((vty1 - ty) * (vtx0 - vtx1) >=
210216
(vtx1 - tx) * (vty0 - vty1)) == yflag1) {
211-
inside_flag[i] ^= 1;
217+
subpath_flag[i] ^= 1;
212218
}
213219
}
214220

@@ -235,10 +241,10 @@ point_in_path_impl(const void* const points_, const size_t s0,
235241
if (yflag0[i] != yflag1) {
236242
if (((vty1 - ty) * (vtx0 - vtx1) >=
237243
(vtx1 - tx) * (vty0 - vty1)) == yflag1) {
238-
inside_flag[i] ^= 1;
244+
subpath_flag[i] ^= 1;
239245
}
240246
}
241-
247+
inside_flag[i] |= subpath_flag[i];
242248
if (inside_flag[i] == 0) {
243249
all_done = 0;
244250
}
@@ -253,6 +259,7 @@ point_in_path_impl(const void* const points_, const size_t s0,
253259
exit:
254260

255261
free(yflag0);
262+
free(subpath_flag);
256263
}
257264

258265
inline void
@@ -699,7 +706,7 @@ _path_module::get_path_collection_extents(const Py::Tuple& args)
699706
Py::Object
700707
_path_module::point_in_path_collection(const Py::Tuple& args)
701708
{
702-
args.verify_length(9);
709+
args.verify_length(10);
703710

704711
//segments, trans, clipbox, colors, linewidths, antialiaseds
705712
double x = Py::Float(args[0]);
@@ -711,6 +718,9 @@ _path_module::point_in_path_collection(const Py::Tuple& args)
711718
Py::SeqBase<Py::Object> offsets_obj = args[6];
712719
agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7].ptr());
713720
bool filled = Py::Boolean(args[8]);
721+
std::string offset_position = Py::String(args[9]);
722+
723+
bool data_offsets = (offset_position == "data");
714724

715725
PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(
716726
offsets_obj.ptr(), PyArray_DOUBLE, 0, 2);
@@ -761,7 +771,11 @@ _path_module::point_in_path_collection(const Py::Tuple& args)
761771
double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0);
762772
double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1);
763773
offset_trans.transform(&xo, &yo);
764-
trans *= agg::trans_affine_translation(xo, yo);
774+
if (data_offsets) {
775+
trans = agg::trans_affine_translation(xo, yo) * trans;
776+
} else {
777+
trans *= agg::trans_affine_translation(xo, yo);
778+
}
765779
}
766780

767781
if (filled)

0 commit comments

Comments
 (0)
0