From 7c28bcdb156e17050b47a24269713f23a8326b64 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 23 Nov 2016 20:13:09 -0500 Subject: [PATCH 1/2] Add Axes method for drawing infinite lines. Clean up axline Add axline image test Fix test image Add what's new Add note about log axes Error if trying to draw line on non-linear axes Fix scale checking Fix docstring interpolation Chnage to using xy1, xy2 Fix docs and closeness checking Raise error if points are the same Swap axline test to image comparison --- .../next_whats_new/2017-12-08-axline.rst | 5 ++ lib/matplotlib/axes/_axes.py | 73 +++++++++++++++++++ lib/matplotlib/tests/test_axes.py | 15 ++++ 3 files changed, 93 insertions(+) create mode 100644 doc/users/next_whats_new/2017-12-08-axline.rst diff --git a/doc/users/next_whats_new/2017-12-08-axline.rst b/doc/users/next_whats_new/2017-12-08-axline.rst new file mode 100644 index 000000000000..6e5652e8ec77 --- /dev/null +++ b/doc/users/next_whats_new/2017-12-08-axline.rst @@ -0,0 +1,5 @@ +New `axline` method +------------------- + +A new `axline` method has been added to draw infinitely long lines that pass +through two points. diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index ebef65a6fd68..651299530fd1 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -908,6 +908,79 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs): self.autoscale_view(scalex=scalex, scaley=False) return l + @docstring.dedent_interpd + def axline(self, xy1, xy2, **kwargs): + """ + Add an infinitely long straight line that passes through two points. + + Parameters + ---------- + xy1, xy2 : (float, float) + Points for the line to pass through. + + Returns + ------- + :class:`~matplotlib.lines.Line2D` + + Other Parameters + ---------------- + Valid kwargs are :class:`~matplotlib.lines.Line2D` properties, + with the exception of 'transform': + + %(_Line2D_docstr)s + + Examples + -------- + * Draw a thick red line passing through (0, 0) with a gradient of 1:: + + >>> axline((0, 0), (1, 1), linewidth=4, color='r') + + + See Also + -------- + axhline : for horizontal lines + axvline : for vertical lines + + Notes + ----- + Currently this method does not work properly with non-linear axes. + """ + if not self.get_xscale() == self.get_yscale() == 'linear': + raise NotImplementedError('axline() is only supported on ' + 'linearly scaled axes') + + if "transform" in kwargs: + raise TypeError("'transform' is not allowed as a kwarg; " + "axline generates its own transform.") + + x1, y1 = xy1 + x2, y2 = xy2 + # If x values the same, we have a vertical line + if np.allclose(x1, x2): + if np.allclose(y1, y2): + raise ValueError( + 'Cannot draw a line through two identical points ' + f'(got x1={x1}, x2={x2}, y1={y1}, y2={y2}).') + line = self.axvline(x1, **kwargs) + return line + + slope = (y2 - y1) / (x2 - x1) + intercept = y1 - (slope * x1) + + xtrans = mtransforms.BboxTransformTo(self.viewLim) + viewLimT = mtransforms.TransformedBbox( + self.viewLim, + mtransforms.Affine2D().rotate_deg(90).scale(-1, 1)) + ytrans = (mtransforms.BboxTransformTo(viewLimT) + + mtransforms.Affine2D().scale(slope).translate(0, intercept)) + trans = mtransforms.blended_transform_factory(xtrans, ytrans) + + line = mlines.Line2D([0, 1], [0, 1], + transform=trans + self.transData, + **kwargs) + self.add_line(line) + return line + @docstring.dedent_interpd def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs): """ diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 25dc08dc5420..39abbe198714 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -3504,6 +3504,21 @@ def test_eb_line_zorder(): ax.set_title("errorbar zorder test") +@check_figures_equal() +def test_axline(fig_test, fig_ref): + ax = fig_test.subplots() + ax.set(xlim=(-1, 1), ylim=(-1, 1)) + ax.axline((0, 0), (1, 1)) + ax.axline((0, 0), (1, 0), color='C1') + ax.axline((0, 0.5), (1, 0.5), color='C2') + + ax = fig_ref.subplots() + ax.set(xlim=(-1, 1), ylim=(-1, 1)) + ax.plot([-1, 1], [-1, 1]) + ax.axhline(0, color='C1') + ax.axhline(0.5, color='C2') + + @image_comparison( baseline_images=['vlines_basic', 'vlines_with_nan', 'vlines_masked'], extensions=['png'] From b2b4faff951cfb9819846a9ade0a69134b37b5dd Mon Sep 17 00:00:00 2001 From: David Stansby Date: Thu, 7 Mar 2019 13:17:06 +0000 Subject: [PATCH 2/2] Small doc fixes --- doc/users/next_whats_new/2017-12-08-axline.rst | 4 ++-- lib/matplotlib/axes/_axes.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/users/next_whats_new/2017-12-08-axline.rst b/doc/users/next_whats_new/2017-12-08-axline.rst index 6e5652e8ec77..22e64a04b8cc 100644 --- a/doc/users/next_whats_new/2017-12-08-axline.rst +++ b/doc/users/next_whats_new/2017-12-08-axline.rst @@ -1,5 +1,5 @@ New `axline` method ------------------- -A new `axline` method has been added to draw infinitely long lines that pass -through two points. +A new `~.axes.Axes.axline` method has been added to draw infinitely long lines +that pass through two points. diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 651299530fd1..1d7a6560271d 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -803,6 +803,7 @@ def axhline(self, y=0, xmin=0, xmax=1, **kwargs): -------- hlines : Add horizontal lines in data coordinates. axhspan : Add a horizontal span (rectangle) across the axis. + axhline : Add a line with an arbitrary slope. Examples -------- @@ -888,6 +889,7 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs): -------- vlines : Add vertical lines in data coordinates. axvspan : Add a vertical span (rectangle) across the axis. + axline : Add a line with an abritrary slope. """ if "transform" in kwargs: @@ -931,7 +933,7 @@ def axline(self, xy1, xy2, **kwargs): Examples -------- - * Draw a thick red line passing through (0, 0) with a gradient of 1:: + Draw a thick red line passing through (0, 0) and (1, 1):: >>> axline((0, 0), (1, 1), linewidth=4, color='r')