From 8e2b7a923db673677087f69b1df0cd1a1a7c7a4f Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Tue, 17 May 2016 09:58:04 -0400 Subject: [PATCH 1/9] Defer to 2D scatter() for handling of 'c'. Closes #5974. --- lib/mpl_toolkits/mplot3d/axes3d.py | 22 +++++++++++------- .../test_mplot3d/scatter3d_color.png | Bin 0 -> 41598 bytes lib/mpl_toolkits/tests/test_mplot3d.py | 11 +++++++++ 3 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter3d_color.png diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index b1032f45091e..e4ff16cf9410 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2209,7 +2209,7 @@ def add_collection3d(self, col, zs=0, zdir='z'): Axes.add_collection(self, col) - def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', depthshade=True, + def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=True, *args, **kwargs): ''' Create a scatter plot. @@ -2233,7 +2233,9 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', 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 @@ -2262,13 +2264,15 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', depthshade=True, s = np.ma.ravel(s) # This doesn't have to match x, y in size. - 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 0000000000000000000000000000000000000000..1ded1b33885072645a41bb261781f0bcebe28f0b GIT binary patch literal 41598 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 UhFJDaYoy`J#c=_ZYwx%7UuCfH$p8QV literal 0 HcmV?d00001 diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index 42718166d32d..5b8485f802b8 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() From 7d1f71791fbee330d377d8ef42b6cb8d79bd1f3d Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 11:05:30 -0600 Subject: [PATCH 2/9] MNT: Raise an error for invalid args in animation.save. When passed arguments that are only used when creating a new MovieWriter instance, raise an error if writer is an existing instance rather than silently ignoring the arguments. Also document the fact that these arguments are invalid in that case. --- lib/matplotlib/animation.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index b45d3ca3561a..256d31bb808b 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -686,28 +686,35 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, *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. + per second. This argument is only valid if *writer* is not a + :class:`MovieWriter` instance. *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`. + value specified by the rcparam `animation.codec`. This argument is only + valid if *writer* is not a :class:`MovieWriter` instance. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam - `animation.bitrate`. + `animation.bitrate`. This argument is only valid if *writer* is not a + :class:`MovieWriter` instance. *extra_args* is a list of extra string arguments to be passed to the underlying movie utility. The default is None, which passes the - additional arguments in the 'animation.extra_args' rcParam. + additional arguments in the 'animation.extra_args' rcParam. This + argument is only valid if *writer* is not a :class:`MovieWriter` + instance. *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. + title, artist, genre, subject, copyright, srcform, comment. This + argument is only valid if *writer* is not a :class:`MovieWriter` + instance. *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 @@ -720,6 +727,20 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, 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 +756,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'] From ecfc1e724173e2ac7bb8e3d1fe9a368e976b3df5 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 11:07:15 -0600 Subject: [PATCH 3/9] MNT: Improve error message when saving animation fails. --- lib/matplotlib/animation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 256d31bb808b..6a9232f1d834 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): 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. ' + 'Stdout: {0} StdError: {1}. It may help to re-run ' + 'with --verbose-debug.'.format(out, err)) def _frame_sink(self): 'Returns the place to which frames should be written.' From 5e5999f8a3b26a8d34d7cb69d5ab5b697af3c7a1 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 13:10:11 -0600 Subject: [PATCH 4/9] MNT: Add original exception to raised IOError. --- lib/matplotlib/animation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 6a9232f1d834..52cafea7fc0f 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -234,14 +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, IOError): + 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 IOError('Error saving animation to file. ' - 'Stdout: {0} StdError: {1}. It may help to re-run ' - 'with --verbose-debug.'.format(out, err)) + 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.' From 7c98a9886e5be6186edcfb701e761776a6f7d40f Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 13:10:41 -0600 Subject: [PATCH 5/9] MNT: Re-arrange docs to avoid repeating save verbiage. --- lib/matplotlib/animation.py | 49 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 52cafea7fc0f..a86871fe255d 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -686,48 +686,45 @@ 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. - *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. This argument is only valid if *writer* is not a - :class:`MovieWriter` instance. - *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. + *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`. This argument is only - valid if *writer* is not a :class:`MovieWriter` instance. + value specified by the rcparam `animation.codec`. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam - `animation.bitrate`. This argument is only valid if *writer* is not a - :class:`MovieWriter` instance. + `animation.bitrate`. *extra_args* is a list of extra string arguments to be passed to the underlying movie utility. The default is None, which passes the - additional arguments in the 'animation.extra_args' rcParam. This - argument is only valid if *writer* is not a :class:`MovieWriter` - instance. + additional arguments in the 'animation.extra_args' rcParam. *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. This - argument is only valid if *writer* is not a :class:`MovieWriter` - instance. - - *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. + title, artist, genre, subject, copyright, srcform, comment. ''' # If the writer is None, use the rc param to find the name of the one # to use From 27d119900dd30846548f21d141f2af3740dbeb47 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 19 May 2016 08:15:33 -0400 Subject: [PATCH 6/9] Revert 2c1bc6b for performance --- lib/matplotlib/tests/test_path.py | 1 - src/_path.h | 16 ++++++++-------- src/_path_wrapper.cpp | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 22035b3dc501..6543137c0e1f 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/src/_path.h b/src/_path.h index 6b1b3d1f7053..8ba732509366 100644 --- a/src/_path.h +++ b/src/_path.h @@ -79,7 +79,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 +89,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; @@ -118,7 +118,7 @@ void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &ins // get test bit for above/below X axis yflag0[i] = (vty0 >= ty); - subpath_flag[i] = false; + subpath_flag[i] = 0; } } @@ -164,7 +164,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; } } @@ -196,8 +196,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; } } 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))); From 2c5d2927688870f1f3cdfdcb06f85dd3e24a82ba Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 19 May 2016 08:16:44 -0400 Subject: [PATCH 7/9] Use ( , ) instead of [] for indexing Fix #6444 --- src/_path.h | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/_path.h b/src/_path.h index 8ba732509366..b8cee3629410 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 { @@ -112,7 +113,7 @@ 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 @@ -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; @@ -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; @@ -242,11 +243,10 @@ 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 +285,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; From 7976970830a10e5572e114fb1da2d4458ebd01c9 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 19 May 2016 08:18:40 -0400 Subject: [PATCH 8/9] Rename operator[] to subarray... Since we now know the performance is so bad, this should discourage its use and flag it as something special. Also, use () in more places --- src/_backend_agg.h | 26 +++++++++++++------------- src/_image.h | 28 ++++++++++++---------------- src/_path.h | 31 +++++++++++++++---------------- src/_png.cpp | 2 +- src/numpy_cpp.h | 4 ++-- 5 files changed, 43 insertions(+), 48 deletions(-) diff --git a/src/_backend_agg.h b/src/_backend_agg.h index 4816cd826f60..2467084eb5cc 100644 --- a/src/_backend_agg.h +++ b/src/_backend_agg.h @@ -961,13 +961,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; @@ -989,13 +989,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); @@ -1274,8 +1274,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 0385f45fd9aa..8a9bb8626ad4 100644 --- a/src/_image.h +++ b/src/_image.h @@ -126,14 +126,12 @@ Image *from_color_array(ArrayType &array, bool isoutput) for (size_t rownum = 0; rownum < (size_t)array.dim(0); rownum++) { for (size_t colnum = 0; colnum < (size_t)array.dim(1); colnum++) { - typename ArrayType::sub_t::sub_t color = array[rownum][colnum]; - - r = color(0); - g = color(1); - b = color(2); + r = array(rownum, colnum, 0); + g = array(rownum, colnum, 1); + b = array(rownum, colnum, 2); if (rgba) { - alpha = color(3); + alpha = array(rownum, colnum, 3); } *buffer++ = int(255 * r); // red @@ -164,13 +162,12 @@ Image *frombyte(ArrayType &array, bool isoutput) for (size_t rownum = 0; rownum < (size_t)array.dim(0); rownum++) { for (size_t colnum = 0; colnum < (size_t)array.dim(1); colnum++) { - typename ArrayType::sub_t::sub_t color = array[rownum][colnum]; - r = color(0); - g = color(1); - b = color(2); + r = array(rownum, colnum, 0); + g = array(rownum, colnum, 1); + b = array(rownum, colnum, 2); if (rgba) { - alpha = color(3); + alpha = array(rownum, colnum, 3); } *buffer++ = r; // red @@ -295,13 +292,12 @@ Image *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 b8cee3629410..71da86b0f42c 100644 --- a/src/_path.h +++ b/src/_path.h @@ -384,13 +384,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; } @@ -436,13 +436,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; @@ -770,8 +770,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/_png.cpp b/src/_png.cpp index 05ac9b28960c..974b47d5e56a 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); From aef86ada619fe81e3b2d665ef3c286b509a9a5be Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 19 May 2016 08:19:19 -0400 Subject: [PATCH 9/9] Don't use contouring on the path unless necessary --- src/_path.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/_path.h b/src/_path.h index 71da86b0f42c..bb730be71ff2 100644 --- a/src/_path.h +++ b/src/_path.h @@ -233,10 +233,13 @@ 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