Skip to content

Commit

Permalink
Merge branch 'v1.5.x' into v2.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
mdboom committed Dec 15, 2015
2 parents ebf81db + 9ca65d8 commit 7b0f9b0
Show file tree
Hide file tree
Showing 8 changed files with 620 additions and 22 deletions.
Binary file removed doc/_static/logo2.png
Binary file not shown.
520 changes: 520 additions & 0 deletions doc/_static/logo2.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion doc/_templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ <h3>We're updating the default styles for Matplotlib 2.0</h3>

<div style="background-color: white; text-align: left; padding: 10px 10px 15px 15px">
<a href="{{ pathto('index') }}"><img src="{{
pathto("_static/logo2.png", 1) }}" border="0" alt="matplotlib"/></a>
pathto("_static/logo2.svg", 1) }}" width="540px" border="0" alt="matplotlib"/></a>
</div>

{% endblock %}
Expand Down
36 changes: 36 additions & 0 deletions lib/matplotlib/tests/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from nose.tools import assert_raises, assert_equal
from matplotlib.testing.decorators import image_comparison
import matplotlib.pyplot as plt
from matplotlib import transforms


def test_readonly_path():
Expand Down Expand Up @@ -113,6 +114,41 @@ def test_marker_paths_pdf():
plt.ylim(-1, 7)


def test_path_no_doubled_point_in_to_polygon():
hand = np.array(
[[1.64516129, 1.16145833],
[1.64516129, 1.59375],
[1.35080645, 1.921875],
[1.375, 2.18229167],
[1.68548387, 1.9375],
[1.60887097, 2.55208333],
[1.68548387, 2.69791667],
[1.76209677, 2.56770833],
[1.83064516, 1.97395833],
[1.89516129, 2.75],
[1.9516129, 2.84895833],
[2.01209677, 2.76041667],
[1.99193548, 1.99479167],
[2.11290323, 2.63020833],
[2.2016129, 2.734375],
[2.25403226, 2.60416667],
[2.14919355, 1.953125],
[2.30645161, 2.36979167],
[2.39112903, 2.36979167],
[2.41532258, 2.1875],
[2.1733871, 1.703125],
[2.07782258, 1.16666667]])

(r0, c0, r1, c1) = (1.0, 1.5, 2.1, 2.5)

poly = Path(np.vstack((hand[:, 1], hand[:, 0])).T, closed=True)
clip_rect = transforms.Bbox([[r0, c0], [r1, c1]])
poly_clipped = poly.clip_to_bbox(clip_rect).to_polygons()[0]

assert np.all(poly_clipped[-2] != poly_clipped[-1])
assert np.all(poly_clipped[-1] == poly_clipped[0])


if __name__ == '__main__':
import nose
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)
2 changes: 1 addition & 1 deletion lib/matplotlib/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def onselect(epress, erelease):
extents = [int(e) for e in tool.extents]
assert extents == [70, 129, 70, 130], extents

assert tool.geometry.shape == (2, 74)
assert tool.geometry.shape == (2, 73)
assert_allclose(tool.geometry[:, 0], [70., 100])


Expand Down
14 changes: 9 additions & 5 deletions lib/matplotlib/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def on_clicked(self, func):
"""
When the button is clicked, call this *func* with event.
A connection id is returned. It can be used to disconnect
A connection id is returned. It can be used to disconnect
the button from its callback.
"""
cid = self.cnt
Expand All @@ -265,7 +265,7 @@ class Slider(AxesWidget):
"""
A slider representing a floating point range.
For the slider to remain responsive you must maintain a
For the slider to remain responsive you must maintain a
reference to it.
The following attributes are defined
Expand Down Expand Up @@ -1473,6 +1473,7 @@ def new_axes(self, ax):
transform=trans,
visible=False,
**self.rectprops)
self.stay_rect.set_animated(False)
self.ax.add_patch(self.stay_rect)

self.ax.add_patch(self.rect)
Expand All @@ -1487,7 +1488,10 @@ def _press(self, event):
self.rect.set_visible(self.visible)
if self.span_stays:
self.stay_rect.set_visible(False)

# really force a draw so that the stay rect is not in
# the blit background
if self.useblit:
self.canvas.draw()
xdata, ydata = self._get_data(event)
if self.direction == 'horizontal':
self.pressv = xdata
Expand All @@ -1510,7 +1514,7 @@ def _release(self, event):
self.stay_rect.set_height(self.rect.get_height())
self.stay_rect.set_visible(True)

self.canvas.draw()
self.canvas.draw_idle()
vmin = self.pressv
xdata, ydata = self._get_data(event)
if self.direction == 'horizontal':
Expand Down Expand Up @@ -2036,7 +2040,7 @@ def geometry(self):
if hasattr(self.to_draw, 'get_verts'):
xfm = self.ax.transData.inverted()
y, x = xfm.transform(self.to_draw.get_verts()).T
return np.array([x[:-1], y[:-1]])
return np.array([x, y])
else:
return np.array(self.to_draw.get_data())

Expand Down
45 changes: 35 additions & 10 deletions src/_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ struct XY
XY(double x_, double y_) : x(x_), y(y_)
{
}

bool operator==(const XY& o)
{
return (x == o.x && y == o.y);
}

bool operator!=(const XY& o)
{
return (x != o.x || y != o.y);
}
};

//
Expand Down Expand Up @@ -838,6 +848,25 @@ bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2)
return false;
}

void _finalize_polygon(std::vector<Polygon> &result)
{
Polygon &polygon = result.back();

if (result.size() == 0) {
return;
}

/* Clean up the last polygon in the result. If less than a
triangle, remove it. */
if (polygon.size() < 3) {
result.pop_back();
} else {
if (polygon.front() != polygon.back()) {
polygon.push_back(polygon.front());
}
}
}

template <class PathIterator>
void convert_path_to_polygons(PathIterator &path,
agg::trans_affine &trans,
Expand Down Expand Up @@ -867,24 +896,20 @@ void convert_path_to_polygons(PathIterator &path,

while ((code = curve.vertex(&x, &y)) != agg::path_cmd_stop) {
if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
if (polygon->size() >= 1) {
polygon->push_back((*polygon)[0]);
result.push_back(Polygon());
polygon = &result.back();
}
_finalize_polygon(result);
result.push_back(Polygon());
polygon = &result.back();
} else {
if (code == agg::path_cmd_move_to && polygon->size() >= 1) {
polygon->push_back((*polygon)[0]);
if (code == agg::path_cmd_move_to) {
_finalize_polygon(result);
result.push_back(Polygon());
polygon = &result.back();
}
polygon->push_back(XY(x, y));
}
}

if (polygon->size() == 0) {
result.pop_back();
}
_finalize_polygon(result);
}

template <class VertexSource>
Expand Down
23 changes: 18 additions & 5 deletions src/_path_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,29 @@
PyObject *convert_polygon_vector(std::vector<Polygon> &polygons)
{
PyObject *pyresult = PyList_New(polygons.size());
bool fix_endpoints;

for (size_t i = 0; i < polygons.size(); ++i) {
Polygon poly = polygons[i];
npy_intp dims[] = {(npy_intp)poly.size() + 1, 2 };
numpy::array_view<double, 2> subresult(dims);
npy_intp dims[2];
dims[1] = 2;

if (poly.front() != poly.back()) {
/* Make last point same as first, if not already */
dims[0] = (npy_intp)poly.size() + 1;
fix_endpoints = true;
} else {
dims[0] = (npy_intp)poly.size();
fix_endpoints = false;
}

/* Make last point same as first. */
numpy::array_view<double, 2> subresult(dims);
memcpy(subresult.data(), &poly[0], sizeof(double) * poly.size() * 2);
subresult(poly.size(), 0) = poly[0].x;
subresult(poly.size(), 1) = poly[0].y;

if (fix_endpoints) {
subresult(poly.size(), 0) = poly.front().x;
subresult(poly.size(), 1) = poly.front().y;
}

if (PyList_SetItem(pyresult, i, subresult.pyobj())) {
Py_DECREF(pyresult);
Expand Down

0 comments on commit 7b0f9b0

Please sign in to comment.