diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index ab92747bd583..7997e856d48e 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -234,12 +234,14 @@ def grab_frame(self, **savefig_kwargs): # frame format and dpi. self.fig.savefig(self._frame_sink(), format=self.frame_format, dpi=self.dpi, **savefig_kwargs) - except RuntimeError: + except (RuntimeError, IOError) as e: out, err = self._proc.communicate() verbose.report('MovieWriter -- Error ' 'running proc:\n%s\n%s' % (out, err), level='helpful') - raise + raise IOError('Error saving animation to file (cause: {0}) ' + 'Stdout: {1} StdError: {2}. It may help to re-run ' + 'with --verbose-debug.'.format(e, out, err)) def _frame_sink(self): 'Returns the place to which frames should be written.' @@ -684,13 +686,28 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, If nothing is passed, the value of the rcparam `animation.writer` is used. + *dpi* controls the dots per inch for the movie frames. This combined + with the figure's size in inches controls the size of the movie. + + *savefig_kwargs* is a dictionary containing keyword arguments to be + passed on to the 'savefig' command which is called repeatedly to save + the individual frames. This can be used to set tight bounding boxes, + for example. + + *extra_anim* is a list of additional `Animation` objects that should + be included in the saved movie file. These need to be from the same + `matplotlib.Figure` instance. Also, animation frames will just be + simply combined, so there should be a 1:1 correspondence between + the frames from the different animations. + + These remaining arguments are used to construct a :class:`MovieWriter` + instance when necessary and are only considered valid if *writer* is + not a :class:`MovieWriter` instance. + *fps* is the frames per second in the movie. Defaults to None, which will use the animation's specified interval to set the frames per second. - *dpi* controls the dots per inch for the movie frames. This combined - with the figure's size in inches controls the size of the movie. - *codec* is the video codec to be used. Not all codecs are supported by a given :class:`MovieWriter`. If none is given, this defaults to the value specified by the rcparam `animation.codec`. @@ -708,18 +725,21 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, *metadata* is a dictionary of keys and values for metadata to include in the output file. Some keys that may be of use include: title, artist, genre, subject, copyright, srcform, comment. - - *extra_anim* is a list of additional `Animation` objects that should - be included in the saved movie file. These need to be from the same - `matplotlib.Figure` instance. Also, animation frames will just be - simply combined, so there should be a 1:1 correspondence between - the frames from the different animations. - - *savefig_kwargs* is a dictionary containing keyword arguments to be - passed on to the 'savefig' command which is called repeatedly to save - the individual frames. This can be used to set tight bounding boxes, - for example. ''' + # If the writer is None, use the rc param to find the name of the one + # to use + if writer is None: + writer = rcParams['animation.writer'] + elif (not is_string_like(writer) and + any(arg is not None + for arg in (fps, codec, bitrate, extra_args, metadata))): + raise RuntimeError('Passing in values for arguments for arguments ' + 'fps, codec, bitrate, extra_args, or metadata ' + 'is not supported when writer is an existing ' + 'MovieWriter instance. These should instead be ' + 'passed as arguments when creating the ' + 'MovieWriter instance.') + if savefig_kwargs is None: savefig_kwargs = {} @@ -735,11 +755,6 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, # Convert interval in ms to frames per second fps = 1000. / self._interval - # If the writer is None, use the rc param to find the name of the one - # to use - if writer is None: - writer = rcParams['animation.writer'] - # Re-use the savefig DPI for ours if none is given if dpi is None: dpi = rcParams['savefig.dpi'] diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 5f606461916e..d397d54f40e4 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -39,7 +39,6 @@ def test_contains_points_negative_radius(): expected = [True, False, False] result = path.contains_points(points, radius=-0.5) - assert result.dtype == np.bool assert np.all(result == expected) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index cc048a034bcd..eb5f620c29a4 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2240,7 +2240,9 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=True, that *c* should not be a single numeric RGB or RGBA sequence because that is indistinguishable from an array of values to be colormapped. *c* can be a 2-D array in - which the rows are RGB or RGBA, however. + which the rows are RGB or RGBA, however, including the + case of a single row to specify the same color for + all points. *depthshade* Whether or not to shade the scatter markers to give @@ -2269,15 +2271,15 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=True, s = np.ma.ravel(s) # This doesn't have to match x, y in size. - if c is None: - c = self._get_lines.get_next_color() - cstr = cbook.is_string_like(c) or cbook.is_sequence_of_strings(c) - if not cstr: - c = np.asanyarray(c) - if c.size == xs.size: - c = np.ma.ravel(c) - - xs, ys, zs, s, c = cbook.delete_masked_points(xs, ys, zs, s, c) + if c is not None: + cstr = cbook.is_string_like(c) or cbook.is_sequence_of_strings(c) + if not cstr: + c = np.asanyarray(c) + if c.size == xs.size: + c = np.ma.ravel(c) + xs, ys, zs, s, c = cbook.delete_masked_points(xs, ys, zs, s, c) + else: + xs, ys, zs, s = cbook.delete_masked_points(xs, ys, zs, s) patches = Axes.scatter(self, xs, ys, s=s, c=c, *args, **kwargs) if not cbook.iterable(zs): diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter3d_color.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter3d_color.png new file mode 100644 index 000000000000..1ded1b338850 Binary files /dev/null and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter3d_color.png differ diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index 1327ca2498f8..96070a8ed436 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -110,6 +110,17 @@ def test_scatter3d(): c='b', marker='^') +@image_comparison(baseline_images=['scatter3d_color'], remove_text=True, + extensions=['png']) +def test_scatter3d_color(): + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + ax.scatter(np.arange(10), np.arange(10), np.arange(10), + color='r', marker='o') + ax.scatter(np.arange(10, 20), np.arange(10, 20), np.arange(10, 20), + color='b', marker='s') + + @image_comparison(baseline_images=['surface3d'], remove_text=True) def test_surface3d(): fig = plt.figure() diff --git a/src/_backend_agg.h b/src/_backend_agg.h index 01574f28f3c8..a792852a282e 100644 --- a/src/_backend_agg.h +++ b/src/_backend_agg.h @@ -956,13 +956,13 @@ inline void RendererAgg::_draw_path_collection_generic(GCAgg &gc, typename PathGenerator::path_iterator path = path_generator(i); if (Ntransforms) { - typename TransformArray::sub_t subtrans = transforms[i % Ntransforms]; - trans = agg::trans_affine(subtrans(0, 0), - subtrans(1, 0), - subtrans(0, 1), - subtrans(1, 1), - subtrans(0, 2), - subtrans(1, 2)); + int it = i % Ntransforms; + trans = agg::trans_affine(transforms(it, 0, 0), + transforms(it, 1, 0), + transforms(it, 0, 1), + transforms(it, 1, 1), + transforms(it, 0, 2), + transforms(it, 1, 2)); trans *= master_transform; } else { trans = master_transform; @@ -984,13 +984,13 @@ inline void RendererAgg::_draw_path_collection_generic(GCAgg &gc, trans *= agg::trans_affine_translation(0.0, (double)height); if (Nfacecolors) { - typename ColorArray::sub_t facecolor = facecolors[i % Nfacecolors]; - face.second = agg::rgba(facecolor(0), facecolor(1), facecolor(2), facecolor(3)); + int ic = i % Nfacecolors; + face.second = agg::rgba(facecolors(ic, 0), facecolors(ic, 1), facecolors(ic, 2), facecolors(ic, 3)); } if (Nedgecolors) { - typename ColorArray::sub_t edgecolor = edgecolors[i % Nedgecolors]; - gc.color = agg::rgba(edgecolor(0), edgecolor(1), edgecolor(2), edgecolor(3)); + int ic = i % Nedgecolors; + gc.color = agg::rgba(edgecolors(ic, 0), edgecolors(ic, 1), edgecolors(ic, 2), edgecolors(ic, 3)); if (Nlinewidths) { gc.linewidth = linewidths(i % Nlinewidths); @@ -1269,8 +1269,8 @@ inline void RendererAgg::draw_gouraud_triangles(GCAgg &gc, bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans); for (int i = 0; i < points.dim(0); ++i) { - typename PointArray::sub_t point = points[i]; - typename ColorArray::sub_t color = colors[i]; + typename PointArray::sub_t point = points.subarray(i); + typename ColorArray::sub_t color = colors.subarray(i); _draw_gouraud_triangle(point, color, trans, has_clippath); } diff --git a/src/_image.h b/src/_image.h index 87ee5a9fb0db..798f2a47ddf9 100644 --- a/src/_image.h +++ b/src/_image.h @@ -120,13 +120,12 @@ void pcolor(CoordinateArray &x, a10 = (1.0 - alpha) * beta; a11 = 1.0 - a00 - a01 - a10; - typename ColorArray::sub_t::sub_t start00 = d[rowstart[i]][colstart[j]]; - typename ColorArray::sub_t::sub_t start01 = d[rowstart[i]][colstart[j] + 1]; - typename ColorArray::sub_t::sub_t start10 = d[rowstart[i] + 1][colstart[j]]; - typename ColorArray::sub_t::sub_t start11 = d[rowstart[i] + 1][colstart[j] + 1]; for (size_t k = 0; k < 4; ++k) { position[k] = - start00(k) * a00 + start01(k) * a01 + start10(k) * a10 + start11(k) * a11; + d(rowstart[i], colstart[j], k) * a00 + + d(rowstart[i], colstart[j] + 1, k) * a01 + + d(rowstart[i] + 1, colstart[j], k) * a10 + + d(rowstart[i] + 1, colstart[j] + 1, k) * a11; } position += 4; } diff --git a/src/_path.h b/src/_path.h index 6b1b3d1f7053..bb730be71ff2 100644 --- a/src/_path.h +++ b/src/_path.h @@ -18,6 +18,7 @@ #include "path_converters.h" #include "_backend_agg_basic_types.h" +#include "numpy_cpp.h" struct XY { @@ -79,7 +80,7 @@ struct XY template void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &inside_flag) { - bool yflag1; + uint8_t yflag1; double vtx0, vty0, vtx1, vty1; double tx, ty; double sx, sy; @@ -89,13 +90,13 @@ void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &ins size_t n = points.size(); - std::vector yflag0(n); - std::vector subpath_flag(n); + std::vector yflag0(n); + std::vector subpath_flag(n); path.rewind(0); for (i = 0; i < n; ++i) { - inside_flag[i] = false; + inside_flag[i] = 0; } unsigned code = 0; @@ -112,13 +113,13 @@ void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &ins sy = vty0 = vty1 = y; for (i = 0; i < n; ++i) { - ty = points[i][1]; + ty = points(i, 1); if (std::isfinite(ty)) { // get test bit for above/below X axis yflag0[i] = (vty0 >= ty); - subpath_flag[i] = false; + subpath_flag[i] = 0; } } @@ -135,8 +136,8 @@ void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &ins } for (i = 0; i < n; ++i) { - tx = points[i][0]; - ty = points[i][1]; + tx = points(i, 0); + ty = points(i, 1); if (!(std::isfinite(tx) && std::isfinite(ty))) { continue; @@ -164,7 +165,7 @@ void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &ins // Haigh-Hutchinson's different polygon inclusion // tests. if (((vty1 - ty) * (vtx0 - vtx1) >= (vtx1 - tx) * (vty0 - vty1)) == yflag1) { - subpath_flag[i] = subpath_flag[i] ^ true; + subpath_flag[i] ^= 1; } } @@ -183,8 +184,8 @@ void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &ins all_done = true; for (i = 0; i < n; ++i) { - tx = points[i][0]; - ty = points[i][1]; + tx = points(i, 0); + ty = points(i, 1); if (!(std::isfinite(tx) && std::isfinite(ty))) { continue; @@ -196,8 +197,8 @@ void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &ins subpath_flag[i] = subpath_flag[i] ^ true; } } - inside_flag[i] = inside_flag[i] || subpath_flag[i]; - if (inside_flag[i] == false) { + inside_flag[i] |= subpath_flag[i]; + if (inside_flag[i] == 0) { all_done = false; } } @@ -232,21 +233,23 @@ inline void points_in_path(PointArray &points, transformed_path_t trans_path(path, trans); no_nans_t no_nans_path(trans_path, true, path.has_curves()); curve_t curved_path(no_nans_path); - contour_t contoured_path(curved_path); - contoured_path.width(r); - - point_in_path_impl(points, contoured_path, result); + if (r != 0.0) { + contour_t contoured_path(curved_path); + contoured_path.width(r); + point_in_path_impl(points, contoured_path, result); + } else { + point_in_path_impl(points, curved_path, result); + } } template inline bool point_in_path( double x, double y, const double r, PathIterator &path, agg::trans_affine &trans) { - std::vector point; - std::vector > points; - point.push_back(x); - point.push_back(y); - points.push_back(point); + npy_intp shape[] = {1, 2}; + numpy::array_view points(shape); + points(0, 0) = x; + points(0, 1) = y; int result[1]; result[0] = 0; @@ -285,11 +288,10 @@ template inline bool point_on_path( double x, double y, const double r, PathIterator &path, agg::trans_affine &trans) { - std::vector point; - std::vector > points; - point.push_back(x); - point.push_back(y); - points.push_back(point); + npy_intp shape[] = {1, 2}; + numpy::array_view points(shape); + points(0, 0) = x; + points(0, 1) = y; int result[1]; result[0] = 0; @@ -385,13 +387,13 @@ void get_path_collection_extents(agg::trans_affine &master_transform, for (i = 0; i < N; ++i) { typename PathGenerator::path_iterator path(paths(i % Npaths)); if (Ntransforms) { - typename TransformArray::sub_t subtrans = transforms[i % Ntransforms]; - trans = agg::trans_affine(subtrans(0, 0), - subtrans(1, 0), - subtrans(0, 1), - subtrans(1, 1), - subtrans(0, 2), - subtrans(1, 2)); + size_t ti = i % Ntransforms; + trans = agg::trans_affine(transforms(ti, 0, 0), + transforms(ti, 1, 0), + transforms(ti, 0, 1), + transforms(ti, 1, 1), + transforms(ti, 0, 2), + transforms(ti, 1, 2)); } else { trans = master_transform; } @@ -437,13 +439,13 @@ void point_in_path_collection(double x, typename PathGenerator::path_iterator path = paths(i % Npaths); if (Ntransforms) { - typename TransformArray::sub_t subtrans = transforms[i % Ntransforms]; - trans = agg::trans_affine(subtrans(0, 0), - subtrans(1, 0), - subtrans(0, 1), - subtrans(1, 1), - subtrans(0, 2), - subtrans(1, 2)); + size_t ti = i % Ntransforms; + trans = agg::trans_affine(transforms(ti, 0, 0), + transforms(ti, 1, 0), + transforms(ti, 0, 1), + transforms(ti, 1, 1), + transforms(ti, 0, 2), + transforms(ti, 1, 2)); trans *= master_transform; } else { trans = master_transform; @@ -771,8 +773,7 @@ int count_bboxes_overlapping_bbox(agg::rect_d &a, BBoxArray &bboxes) size_t num_bboxes = bboxes.size(); for (size_t i = 0; i < num_bboxes; ++i) { - typename BBoxArray::sub_t bbox_b = bboxes[i]; - b = agg::rect_d(bbox_b(0, 0), bbox_b(0, 1), bbox_b(1, 0), bbox_b(1, 1)); + b = agg::rect_d(bboxes(i, 0, 0), bboxes(i, 0, 1), bboxes(i, 1, 0), bboxes(i, 1, 1)); if (b.x2 < b.x1) { std::swap(b.x1, b.x2); diff --git a/src/_path_wrapper.cpp b/src/_path_wrapper.cpp index 4a4fc2db1eb3..45c1e288e86c 100644 --- a/src/_path_wrapper.cpp +++ b/src/_path_wrapper.cpp @@ -93,7 +93,7 @@ static PyObject *Py_points_in_path(PyObject *self, PyObject *args, PyObject *kwd } npy_intp dims[] = { (npy_intp)points.size() }; - numpy::array_view results(dims); + numpy::array_view results(dims); CALL_CPP("points_in_path", (points_in_path(points, r, path, trans, results))); @@ -152,7 +152,7 @@ static PyObject *Py_points_on_path(PyObject *self, PyObject *args, PyObject *kwd } npy_intp dims[] = { (npy_intp)points.size() }; - numpy::array_view results(dims); + numpy::array_view results(dims); CALL_CPP("points_on_path", (points_on_path(points, r, path, trans, results))); diff --git a/src/_png.cpp b/src/_png.cpp index e15456023f09..c2882a8ec13d 100644 --- a/src/_png.cpp +++ b/src/_png.cpp @@ -91,7 +91,7 @@ static PyObject *Py_write_png(PyObject *self, PyObject *args, PyObject *kwds) int channels = buffer.dim(2); std::vector row_pointers(height); for (png_uint_32 row = 0; row < (png_uint_32)height; ++row) { - row_pointers[row] = (png_bytep)buffer[row].data(); + row_pointers[row] = (png_bytep)&buffer(row, 0, 0); } FILE *fp = NULL; diff --git a/src/numpy_cpp.h b/src/numpy_cpp.h index cbf8907f7cf0..887ffe48aee7 100644 --- a/src/numpy_cpp.h +++ b/src/numpy_cpp.h @@ -284,7 +284,7 @@ class array_view_accessors self->m_strides[1] * j); } - sub_t operator[](npy_intp i) const + sub_t subarray(npy_intp i) const { const AVC *self = static_cast(this); @@ -318,7 +318,7 @@ class array_view_accessors self->m_strides[1] * j + self->m_strides[2] * k); } - sub_t operator[](npy_intp i) const + sub_t subarray(npy_intp i) const { const AVC *self = static_cast(this);