diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index cbc6a5cdd4a5..7e0267c81edd 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -1404,6 +1404,11 @@ def test_bar_tick_label_single(): ax.bar("a", "b", align='edge', tick_label='0', data=data) +def test_nan_bar_values(): + fig, ax = plt.subplots() + ax.bar([0, 1], [np.nan, 4]) + + def test_bar_ticklabel_fail(): fig, ax = plt.subplots() ax.bar([], []) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 3ff83da499ff..ebe2e1a46de7 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -452,3 +452,26 @@ def test_intersect_zero_length_segment(): assert outline_path.intersects_path(this_path) assert this_path.intersects_path(outline_path) + + +def test_cleanup_closepoly(): + # if the first connected component of a Path ends in a CLOSEPOLY, but that + # component contains a NaN, then Path.cleaned should ignore not just the + # control points but also the CLOSEPOLY, since it has nowhere valid to + # point. + paths = [ + Path([[np.nan, np.nan], [np.nan, np.nan]], + [Path.MOVETO, Path.CLOSEPOLY]), + # we trigger a different path in the C++ code if we don't pass any + # codes explicitly, so we must also make sure that this works + Path([[np.nan, np.nan], [np.nan, np.nan]]), + # we should also make sure that this cleanup works if there's some + # multi-vertex curves + Path([[np.nan, np.nan], [np.nan, np.nan], [np.nan, np.nan], + [np.nan, np.nan]], + [Path.MOVETO, Path.CURVE3, Path.CURVE3, Path.CLOSEPOLY]) + ] + for p in paths: + cleaned = p.cleaned(remove_nans=True) + assert len(cleaned) == 1 + assert cleaned.codes[0] == Path.STOP diff --git a/src/path_converters.h b/src/path_converters.h index 86d803341d51..7c16ae42b9c5 100644 --- a/src/path_converters.h +++ b/src/path_converters.h @@ -163,6 +163,7 @@ class PathNanRemover : protected EmbeddedQueue<4> VertexSource *m_source; bool m_remove_nans; bool m_has_curves; + bool valid_segment_exists; public: /* has_curves should be true if the path contains bezier curve @@ -172,7 +173,9 @@ class PathNanRemover : protected EmbeddedQueue<4> PathNanRemover(VertexSource &source, bool remove_nans, bool has_curves) : m_source(&source), m_remove_nans(remove_nans), m_has_curves(has_curves) { - // empty + // ignore all close/end_poly commands until after the first valid + // (nan-free) command is encountered + valid_segment_exists = false; } inline void rewind(unsigned path_id) @@ -202,8 +205,13 @@ class PathNanRemover : protected EmbeddedQueue<4> are found along the way, the queue is emptied, and the next curve segment is handled. */ code = m_source->vertex(x, y); + /* The vertices attached to STOP and CLOSEPOLY left are never + used, so we leave them as-is even if NaN. However, CLOSEPOLY + only makes sense if a valid MOVETO command has already been + emitted. */ if (code == agg::path_cmd_stop || - code == (agg::path_cmd_end_poly | agg::path_flags_close)) { + (code == (agg::path_cmd_end_poly | agg::path_flags_close) && + valid_segment_exists)) { return code; } @@ -224,6 +232,7 @@ class PathNanRemover : protected EmbeddedQueue<4> } if (!has_nan) { + valid_segment_exists = true; break; } @@ -251,7 +260,8 @@ class PathNanRemover : protected EmbeddedQueue<4> code = m_source->vertex(x, y); if (code == agg::path_cmd_stop || - code == (agg::path_cmd_end_poly | agg::path_flags_close)) { + (code == (agg::path_cmd_end_poly | agg::path_flags_close) && + valid_segment_exists)) { return code; } @@ -259,13 +269,14 @@ class PathNanRemover : protected EmbeddedQueue<4> do { code = m_source->vertex(x, y); if (code == agg::path_cmd_stop || - code == (agg::path_cmd_end_poly | agg::path_flags_close)) { + (code == (agg::path_cmd_end_poly | agg::path_flags_close) && + valid_segment_exists)) { return code; } } while (!(std::isfinite(*x) && std::isfinite(*y))); return agg::path_cmd_move_to; } - + valid_segment_exists = true; return code; } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy