You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			1132 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			1132 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Python
		
	
import copy
 | 
						|
 | 
						|
import numpy as np
 | 
						|
from numpy.testing import (assert_allclose, assert_almost_equal,
 | 
						|
                           assert_array_equal, assert_array_almost_equal)
 | 
						|
import pytest
 | 
						|
 | 
						|
from matplotlib import scale
 | 
						|
import matplotlib.pyplot as plt
 | 
						|
import matplotlib.patches as mpatches
 | 
						|
import matplotlib.transforms as mtransforms
 | 
						|
from matplotlib.transforms import Affine2D, Bbox, TransformedBbox, _ScaledRotation
 | 
						|
from matplotlib.path import Path
 | 
						|
from matplotlib.testing.decorators import image_comparison, check_figures_equal
 | 
						|
from unittest.mock import MagicMock
 | 
						|
 | 
						|
 | 
						|
class TestAffine2D:
 | 
						|
    single_point = [1.0, 1.0]
 | 
						|
    multiple_points = [[0.0, 2.0], [3.0, 3.0], [4.0, 0.0]]
 | 
						|
    pivot = single_point
 | 
						|
 | 
						|
    def test_init(self):
 | 
						|
        Affine2D([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
 | 
						|
        Affine2D(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], int))
 | 
						|
        Affine2D(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], float))
 | 
						|
 | 
						|
    def test_values(self):
 | 
						|
        np.random.seed(19680801)
 | 
						|
        values = np.random.random(6)
 | 
						|
        assert_array_equal(Affine2D.from_values(*values).to_values(), values)
 | 
						|
 | 
						|
    def test_modify_inplace(self):
 | 
						|
        # Some polar transforms require modifying the matrix in place.
 | 
						|
        trans = Affine2D()
 | 
						|
        mtx = trans.get_matrix()
 | 
						|
        mtx[0, 0] = 42
 | 
						|
        assert_array_equal(trans.get_matrix(), [[42, 0, 0], [0, 1, 0], [0, 0, 1]])
 | 
						|
 | 
						|
    def test_clear(self):
 | 
						|
        a = Affine2D(np.random.rand(3, 3) + 5)  # Anything non-identity.
 | 
						|
        a.clear()
 | 
						|
        assert_array_equal(a.get_matrix(), [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
 | 
						|
 | 
						|
    def test_rotate(self):
 | 
						|
        r_pi_2 = Affine2D().rotate(np.pi / 2)
 | 
						|
        r90 = Affine2D().rotate_deg(90)
 | 
						|
        assert_array_equal(r_pi_2.get_matrix(), r90.get_matrix())
 | 
						|
        assert_array_almost_equal(r90.transform(self.single_point), [-1, 1])
 | 
						|
        assert_array_almost_equal(r90.transform(self.multiple_points),
 | 
						|
                                  [[-2, 0], [-3, 3], [0, 4]])
 | 
						|
 | 
						|
        r_pi = Affine2D().rotate(np.pi)
 | 
						|
        r180 = Affine2D().rotate_deg(180)
 | 
						|
        assert_array_equal(r_pi.get_matrix(), r180.get_matrix())
 | 
						|
        assert_array_almost_equal(r180.transform(self.single_point), [-1, -1])
 | 
						|
        assert_array_almost_equal(r180.transform(self.multiple_points),
 | 
						|
                                  [[0, -2], [-3, -3], [-4, 0]])
 | 
						|
 | 
						|
        r_pi_3_2 = Affine2D().rotate(3 * np.pi / 2)
 | 
						|
        r270 = Affine2D().rotate_deg(270)
 | 
						|
        assert_array_equal(r_pi_3_2.get_matrix(), r270.get_matrix())
 | 
						|
        assert_array_almost_equal(r270.transform(self.single_point), [1, -1])
 | 
						|
        assert_array_almost_equal(r270.transform(self.multiple_points),
 | 
						|
                                  [[2, 0], [3, -3], [0, -4]])
 | 
						|
 | 
						|
        assert_array_equal((r90 + r90).get_matrix(), r180.get_matrix())
 | 
						|
        assert_array_equal((r90 + r180).get_matrix(), r270.get_matrix())
 | 
						|
 | 
						|
    def test_rotate_around(self):
 | 
						|
        r_pi_2 = Affine2D().rotate_around(*self.pivot, np.pi / 2)
 | 
						|
        r90 = Affine2D().rotate_deg_around(*self.pivot, 90)
 | 
						|
        assert_array_equal(r_pi_2.get_matrix(), r90.get_matrix())
 | 
						|
        assert_array_almost_equal(r90.transform(self.single_point), [1, 1])
 | 
						|
        assert_array_almost_equal(r90.transform(self.multiple_points),
 | 
						|
                                  [[0, 0], [-1, 3], [2, 4]])
 | 
						|
 | 
						|
        r_pi = Affine2D().rotate_around(*self.pivot, np.pi)
 | 
						|
        r180 = Affine2D().rotate_deg_around(*self.pivot, 180)
 | 
						|
        assert_array_equal(r_pi.get_matrix(), r180.get_matrix())
 | 
						|
        assert_array_almost_equal(r180.transform(self.single_point), [1, 1])
 | 
						|
        assert_array_almost_equal(r180.transform(self.multiple_points),
 | 
						|
                                  [[2, 0], [-1, -1], [-2, 2]])
 | 
						|
 | 
						|
        r_pi_3_2 = Affine2D().rotate_around(*self.pivot, 3 * np.pi / 2)
 | 
						|
        r270 = Affine2D().rotate_deg_around(*self.pivot, 270)
 | 
						|
        assert_array_equal(r_pi_3_2.get_matrix(), r270.get_matrix())
 | 
						|
        assert_array_almost_equal(r270.transform(self.single_point), [1, 1])
 | 
						|
        assert_array_almost_equal(r270.transform(self.multiple_points),
 | 
						|
                                  [[2, 2], [3, -1], [0, -2]])
 | 
						|
 | 
						|
        assert_array_almost_equal((r90 + r90).get_matrix(), r180.get_matrix())
 | 
						|
        assert_array_almost_equal((r90 + r180).get_matrix(), r270.get_matrix())
 | 
						|
 | 
						|
    def test_scale(self):
 | 
						|
        sx = Affine2D().scale(3, 1)
 | 
						|
        sy = Affine2D().scale(1, -2)
 | 
						|
        trans = Affine2D().scale(3, -2)
 | 
						|
        assert_array_equal((sx + sy).get_matrix(), trans.get_matrix())
 | 
						|
        assert_array_equal(trans.transform(self.single_point), [3, -2])
 | 
						|
        assert_array_equal(trans.transform(self.multiple_points),
 | 
						|
                           [[0, -4], [9, -6], [12, 0]])
 | 
						|
 | 
						|
    def test_skew(self):
 | 
						|
        trans_rad = Affine2D().skew(np.pi / 8, np.pi / 12)
 | 
						|
        trans_deg = Affine2D().skew_deg(22.5, 15)
 | 
						|
        assert_array_equal(trans_rad.get_matrix(), trans_deg.get_matrix())
 | 
						|
        # Using ~atan(0.5), ~atan(0.25) produces roundish numbers on output.
 | 
						|
        trans = Affine2D().skew_deg(26.5650512, 14.0362435)
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [1.5, 1.25])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[1, 2], [4.5, 3.75], [4, 1]])
 | 
						|
 | 
						|
    def test_translate(self):
 | 
						|
        tx = Affine2D().translate(23, 0)
 | 
						|
        ty = Affine2D().translate(0, 42)
 | 
						|
        trans = Affine2D().translate(23, 42)
 | 
						|
        assert_array_equal((tx + ty).get_matrix(), trans.get_matrix())
 | 
						|
        assert_array_equal(trans.transform(self.single_point), [24, 43])
 | 
						|
        assert_array_equal(trans.transform(self.multiple_points),
 | 
						|
                           [[23, 44], [26, 45], [27, 42]])
 | 
						|
 | 
						|
    def test_rotate_plus_other(self):
 | 
						|
        trans = Affine2D().rotate_deg(90).rotate_deg_around(*self.pivot, 180)
 | 
						|
        trans_added = (Affine2D().rotate_deg(90) +
 | 
						|
                       Affine2D().rotate_deg_around(*self.pivot, 180))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [3, 1])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[4, 2], [5, -1], [2, -2]])
 | 
						|
 | 
						|
        trans = Affine2D().rotate_deg(90).scale(3, -2)
 | 
						|
        trans_added = Affine2D().rotate_deg(90) + Affine2D().scale(3, -2)
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [-3, -2])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[-6, -0], [-9, -6], [0, -8]])
 | 
						|
 | 
						|
        trans = (Affine2D().rotate_deg(90)
 | 
						|
                 .skew_deg(26.5650512, 14.0362435))  # ~atan(0.5), ~atan(0.25)
 | 
						|
        trans_added = (Affine2D().rotate_deg(90) +
 | 
						|
                       Affine2D().skew_deg(26.5650512, 14.0362435))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [-0.5, 0.75])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[-2, -0.5], [-1.5, 2.25], [2, 4]])
 | 
						|
 | 
						|
        trans = Affine2D().rotate_deg(90).translate(23, 42)
 | 
						|
        trans_added = Affine2D().rotate_deg(90) + Affine2D().translate(23, 42)
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [22, 43])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[21, 42], [20, 45], [23, 46]])
 | 
						|
 | 
						|
    def test_rotate_around_plus_other(self):
 | 
						|
        trans = Affine2D().rotate_deg_around(*self.pivot, 90).rotate_deg(180)
 | 
						|
        trans_added = (Affine2D().rotate_deg_around(*self.pivot, 90) +
 | 
						|
                       Affine2D().rotate_deg(180))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [-1, -1])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[0, 0], [1, -3], [-2, -4]])
 | 
						|
 | 
						|
        trans = Affine2D().rotate_deg_around(*self.pivot, 90).scale(3, -2)
 | 
						|
        trans_added = (Affine2D().rotate_deg_around(*self.pivot, 90) +
 | 
						|
                       Affine2D().scale(3, -2))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [3, -2])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[0, 0], [-3, -6], [6, -8]])
 | 
						|
 | 
						|
        trans = (Affine2D().rotate_deg_around(*self.pivot, 90)
 | 
						|
                 .skew_deg(26.5650512, 14.0362435))  # ~atan(0.5), ~atan(0.25)
 | 
						|
        trans_added = (Affine2D().rotate_deg_around(*self.pivot, 90) +
 | 
						|
                       Affine2D().skew_deg(26.5650512, 14.0362435))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [1.5, 1.25])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[0, 0], [0.5, 2.75], [4, 4.5]])
 | 
						|
 | 
						|
        trans = Affine2D().rotate_deg_around(*self.pivot, 90).translate(23, 42)
 | 
						|
        trans_added = (Affine2D().rotate_deg_around(*self.pivot, 90) +
 | 
						|
                       Affine2D().translate(23, 42))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [24, 43])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[23, 42], [22, 45], [25, 46]])
 | 
						|
 | 
						|
    def test_scale_plus_other(self):
 | 
						|
        trans = Affine2D().scale(3, -2).rotate_deg(90)
 | 
						|
        trans_added = Affine2D().scale(3, -2) + Affine2D().rotate_deg(90)
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_equal(trans.transform(self.single_point), [2, 3])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[4, 0], [6, 9], [0, 12]])
 | 
						|
 | 
						|
        trans = Affine2D().scale(3, -2).rotate_deg_around(*self.pivot, 90)
 | 
						|
        trans_added = (Affine2D().scale(3, -2) +
 | 
						|
                       Affine2D().rotate_deg_around(*self.pivot, 90))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_equal(trans.transform(self.single_point), [4, 3])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[6, 0], [8, 9], [2, 12]])
 | 
						|
 | 
						|
        trans = (Affine2D().scale(3, -2)
 | 
						|
                 .skew_deg(26.5650512, 14.0362435))  # ~atan(0.5), ~atan(0.25)
 | 
						|
        trans_added = (Affine2D().scale(3, -2) +
 | 
						|
                       Affine2D().skew_deg(26.5650512, 14.0362435))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [2, -1.25])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[-2, -4], [6, -3.75], [12, 3]])
 | 
						|
 | 
						|
        trans = Affine2D().scale(3, -2).translate(23, 42)
 | 
						|
        trans_added = Affine2D().scale(3, -2) + Affine2D().translate(23, 42)
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_equal(trans.transform(self.single_point), [26, 40])
 | 
						|
        assert_array_equal(trans.transform(self.multiple_points),
 | 
						|
                           [[23, 38], [32, 36], [35, 42]])
 | 
						|
 | 
						|
    def test_skew_plus_other(self):
 | 
						|
        # Using ~atan(0.5), ~atan(0.25) produces roundish numbers on output.
 | 
						|
        trans = Affine2D().skew_deg(26.5650512, 14.0362435).rotate_deg(90)
 | 
						|
        trans_added = (Affine2D().skew_deg(26.5650512, 14.0362435) +
 | 
						|
                       Affine2D().rotate_deg(90))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [-1.25, 1.5])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[-2, 1], [-3.75, 4.5], [-1, 4]])
 | 
						|
 | 
						|
        trans = (Affine2D().skew_deg(26.5650512, 14.0362435)
 | 
						|
                 .rotate_deg_around(*self.pivot, 90))
 | 
						|
        trans_added = (Affine2D().skew_deg(26.5650512, 14.0362435) +
 | 
						|
                       Affine2D().rotate_deg_around(*self.pivot, 90))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [0.75, 1.5])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[0, 1], [-1.75, 4.5], [1, 4]])
 | 
						|
 | 
						|
        trans = Affine2D().skew_deg(26.5650512, 14.0362435).scale(3, -2)
 | 
						|
        trans_added = (Affine2D().skew_deg(26.5650512, 14.0362435) +
 | 
						|
                       Affine2D().scale(3, -2))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [4.5, -2.5])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[3, -4], [13.5, -7.5], [12, -2]])
 | 
						|
 | 
						|
        trans = Affine2D().skew_deg(26.5650512, 14.0362435).translate(23, 42)
 | 
						|
        trans_added = (Affine2D().skew_deg(26.5650512, 14.0362435) +
 | 
						|
                       Affine2D().translate(23, 42))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [24.5, 43.25])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[24, 44], [27.5, 45.75], [27, 43]])
 | 
						|
 | 
						|
    def test_translate_plus_other(self):
 | 
						|
        trans = Affine2D().translate(23, 42).rotate_deg(90)
 | 
						|
        trans_added = Affine2D().translate(23, 42) + Affine2D().rotate_deg(90)
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [-43, 24])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[-44, 23], [-45, 26], [-42, 27]])
 | 
						|
 | 
						|
        trans = Affine2D().translate(23, 42).rotate_deg_around(*self.pivot, 90)
 | 
						|
        trans_added = (Affine2D().translate(23, 42) +
 | 
						|
                       Affine2D().rotate_deg_around(*self.pivot, 90))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [-41, 24])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[-42, 23], [-43, 26], [-40, 27]])
 | 
						|
 | 
						|
        trans = Affine2D().translate(23, 42).scale(3, -2)
 | 
						|
        trans_added = Affine2D().translate(23, 42) + Affine2D().scale(3, -2)
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [72, -86])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[69, -88], [78, -90], [81, -84]])
 | 
						|
 | 
						|
        trans = (Affine2D().translate(23, 42)
 | 
						|
                 .skew_deg(26.5650512, 14.0362435))  # ~atan(0.5), ~atan(0.25)
 | 
						|
        trans_added = (Affine2D().translate(23, 42) +
 | 
						|
                       Affine2D().skew_deg(26.5650512, 14.0362435))
 | 
						|
        assert_array_equal(trans.get_matrix(), trans_added.get_matrix())
 | 
						|
        assert_array_almost_equal(trans.transform(self.single_point), [45.5, 49])
 | 
						|
        assert_array_almost_equal(trans.transform(self.multiple_points),
 | 
						|
                                  [[45, 49.75], [48.5, 51.5], [48, 48.75]])
 | 
						|
 | 
						|
    def test_invalid_transform(self):
 | 
						|
        t = mtransforms.Affine2D()
 | 
						|
        # There are two different exceptions, since the wrong number of
 | 
						|
        # dimensions is caught when constructing an array_view, and that
 | 
						|
        # raises a ValueError, and a wrong shape with a possible number
 | 
						|
        # of dimensions is caught by our CALL_CPP macro, which always
 | 
						|
        # raises the less precise RuntimeError.
 | 
						|
        with pytest.raises(ValueError):
 | 
						|
            t.transform(1)
 | 
						|
        with pytest.raises(ValueError):
 | 
						|
            t.transform([[[1]]])
 | 
						|
        with pytest.raises(RuntimeError):
 | 
						|
            t.transform([])
 | 
						|
        with pytest.raises(RuntimeError):
 | 
						|
            t.transform([1])
 | 
						|
        with pytest.raises(ValueError):
 | 
						|
            t.transform([[1]])
 | 
						|
        with pytest.raises(ValueError):
 | 
						|
            t.transform([[1, 2, 3]])
 | 
						|
 | 
						|
    def test_copy(self):
 | 
						|
        a = mtransforms.Affine2D()
 | 
						|
        b = mtransforms.Affine2D()
 | 
						|
        s = a + b
 | 
						|
        # Updating a dependee should invalidate a copy of the dependent.
 | 
						|
        s.get_matrix()  # resolve it.
 | 
						|
        s1 = copy.copy(s)
 | 
						|
        assert not s._invalid and not s1._invalid
 | 
						|
        a.translate(1, 2)
 | 
						|
        assert s._invalid and s1._invalid
 | 
						|
        assert (s1.get_matrix() == a.get_matrix()).all()
 | 
						|
        # Updating a copy of a dependee shouldn't invalidate a dependent.
 | 
						|
        s.get_matrix()  # resolve it.
 | 
						|
        b1 = copy.copy(b)
 | 
						|
        b1.translate(3, 4)
 | 
						|
        assert not s._invalid
 | 
						|
        assert_array_equal(s.get_matrix(), a.get_matrix())
 | 
						|
 | 
						|
    def test_deepcopy(self):
 | 
						|
        a = mtransforms.Affine2D()
 | 
						|
        b = mtransforms.Affine2D()
 | 
						|
        s = a + b
 | 
						|
        # Updating a dependee shouldn't invalidate a deepcopy of the dependent.
 | 
						|
        s.get_matrix()  # resolve it.
 | 
						|
        s1 = copy.deepcopy(s)
 | 
						|
        assert not s._invalid and not s1._invalid
 | 
						|
        a.translate(1, 2)
 | 
						|
        assert s._invalid and not s1._invalid
 | 
						|
        assert_array_equal(s1.get_matrix(), mtransforms.Affine2D().get_matrix())
 | 
						|
        # Updating a deepcopy of a dependee shouldn't invalidate a dependent.
 | 
						|
        s.get_matrix()  # resolve it.
 | 
						|
        b1 = copy.deepcopy(b)
 | 
						|
        b1.translate(3, 4)
 | 
						|
        assert not s._invalid
 | 
						|
        assert_array_equal(s.get_matrix(), a.get_matrix())
 | 
						|
 | 
						|
 | 
						|
class TestAffineDeltaTransform:
 | 
						|
    def test_invalidate(self):
 | 
						|
        before = np.array([[1.0, 4.0, 0.0],
 | 
						|
                           [5.0, 1.0, 0.0],
 | 
						|
                           [0.0, 0.0, 1.0]])
 | 
						|
        after = np.array([[1.0, 3.0, 0.0],
 | 
						|
                          [5.0, 1.0, 0.0],
 | 
						|
                          [0.0, 0.0, 1.0]])
 | 
						|
 | 
						|
        # Translation and skew present
 | 
						|
        base = mtransforms.Affine2D.from_values(1, 5, 4, 1, 2, 3)
 | 
						|
        t = mtransforms.AffineDeltaTransform(base)
 | 
						|
        assert_array_equal(t.get_matrix(), before)
 | 
						|
 | 
						|
        # Mess with the internal structure of `base` without invalidating
 | 
						|
        # This should not affect this transform because it's a passthrough:
 | 
						|
        # it's always invalid
 | 
						|
        base.get_matrix()[0, 1:] = 3
 | 
						|
        assert_array_equal(t.get_matrix(), after)
 | 
						|
 | 
						|
        # Invalidate the base
 | 
						|
        base.invalidate()
 | 
						|
        assert_array_equal(t.get_matrix(), after)
 | 
						|
 | 
						|
 | 
						|
def test_non_affine_caching():
 | 
						|
    class AssertingNonAffineTransform(mtransforms.Transform):
 | 
						|
        """
 | 
						|
        This transform raises an assertion error when called when it
 | 
						|
        shouldn't be and ``self.raise_on_transform`` is True.
 | 
						|
 | 
						|
        """
 | 
						|
        input_dims = output_dims = 2
 | 
						|
        is_affine = False
 | 
						|
 | 
						|
        def __init__(self, *args, **kwargs):
 | 
						|
            super().__init__(*args, **kwargs)
 | 
						|
            self.raise_on_transform = False
 | 
						|
            self.underlying_transform = mtransforms.Affine2D().scale(10, 10)
 | 
						|
 | 
						|
        def transform_path_non_affine(self, path):
 | 
						|
            assert not self.raise_on_transform, \
 | 
						|
                'Invalidated affine part of transform unnecessarily.'
 | 
						|
            return self.underlying_transform.transform_path(path)
 | 
						|
        transform_path = transform_path_non_affine
 | 
						|
 | 
						|
        def transform_non_affine(self, path):
 | 
						|
            assert not self.raise_on_transform, \
 | 
						|
                'Invalidated affine part of transform unnecessarily.'
 | 
						|
            return self.underlying_transform.transform(path)
 | 
						|
        transform = transform_non_affine
 | 
						|
 | 
						|
    my_trans = AssertingNonAffineTransform()
 | 
						|
    ax = plt.axes()
 | 
						|
    plt.plot(np.arange(10), transform=my_trans + ax.transData)
 | 
						|
    plt.draw()
 | 
						|
    # enable the transform to raise an exception if it's non-affine transform
 | 
						|
    # method is triggered again.
 | 
						|
    my_trans.raise_on_transform = True
 | 
						|
    ax.transAxes.invalidate()
 | 
						|
    plt.draw()
 | 
						|
 | 
						|
 | 
						|
def test_external_transform_api():
 | 
						|
    class ScaledBy:
 | 
						|
        def __init__(self, scale_factor):
 | 
						|
            self._scale_factor = scale_factor
 | 
						|
 | 
						|
        def _as_mpl_transform(self, axes):
 | 
						|
            return (mtransforms.Affine2D().scale(self._scale_factor)
 | 
						|
                    + axes.transData)
 | 
						|
 | 
						|
    ax = plt.axes()
 | 
						|
    line, = plt.plot(np.arange(10), transform=ScaledBy(10))
 | 
						|
    ax.set_xlim(0, 100)
 | 
						|
    ax.set_ylim(0, 100)
 | 
						|
    # assert that the top transform of the line is the scale transform.
 | 
						|
    assert_allclose(line.get_transform()._a.get_matrix(),
 | 
						|
                    mtransforms.Affine2D().scale(10).get_matrix())
 | 
						|
 | 
						|
 | 
						|
@image_comparison(['pre_transform_data'], remove_text=True, style='mpl20',
 | 
						|
                  tol=0.05)
 | 
						|
def test_pre_transform_plotting():
 | 
						|
    # a catch-all for as many as possible plot layouts which handle
 | 
						|
    # pre-transforming the data NOTE: The axis range is important in this
 | 
						|
    # plot. It should be x10 what the data suggests it should be
 | 
						|
 | 
						|
    ax = plt.axes()
 | 
						|
    times10 = mtransforms.Affine2D().scale(10)
 | 
						|
 | 
						|
    ax.contourf(np.arange(48).reshape(6, 8), transform=times10 + ax.transData)
 | 
						|
 | 
						|
    ax.pcolormesh(np.linspace(0, 4, 7),
 | 
						|
                  np.linspace(5.5, 8, 9),
 | 
						|
                  np.arange(48).reshape(8, 6),
 | 
						|
                  transform=times10 + ax.transData)
 | 
						|
 | 
						|
    ax.scatter(np.linspace(0, 10), np.linspace(10, 0),
 | 
						|
               transform=times10 + ax.transData)
 | 
						|
 | 
						|
    x = np.linspace(8, 10, 20)
 | 
						|
    y = np.linspace(1, 5, 20)
 | 
						|
    u = 2*np.sin(x) + np.cos(y[:, np.newaxis])
 | 
						|
    v = np.sin(x) - np.cos(y[:, np.newaxis])
 | 
						|
 | 
						|
    ax.streamplot(x, y, u, v, transform=times10 + ax.transData,
 | 
						|
                  linewidth=np.hypot(u, v))
 | 
						|
 | 
						|
    # reduce the vector data down a bit for barb and quiver plotting
 | 
						|
    x, y = x[::3], y[::3]
 | 
						|
    u, v = u[::3, ::3], v[::3, ::3]
 | 
						|
 | 
						|
    ax.quiver(x, y + 5, u, v, transform=times10 + ax.transData)
 | 
						|
 | 
						|
    ax.barbs(x - 3, y + 5, u**2, v**2, transform=times10 + ax.transData)
 | 
						|
 | 
						|
 | 
						|
def test_contour_pre_transform_limits():
 | 
						|
    ax = plt.axes()
 | 
						|
    xs, ys = np.meshgrid(np.linspace(15, 20, 15), np.linspace(12.4, 12.5, 20))
 | 
						|
    ax.contourf(xs, ys, np.log(xs * ys),
 | 
						|
                transform=mtransforms.Affine2D().scale(0.1) + ax.transData)
 | 
						|
 | 
						|
    expected = np.array([[1.5, 1.24],
 | 
						|
                         [2., 1.25]])
 | 
						|
    assert_almost_equal(expected, ax.dataLim.get_points())
 | 
						|
 | 
						|
 | 
						|
def test_pcolor_pre_transform_limits():
 | 
						|
    # Based on test_contour_pre_transform_limits()
 | 
						|
    ax = plt.axes()
 | 
						|
    xs, ys = np.meshgrid(np.linspace(15, 20, 15), np.linspace(12.4, 12.5, 20))
 | 
						|
    ax.pcolor(xs, ys, np.log(xs * ys)[:-1, :-1],
 | 
						|
              transform=mtransforms.Affine2D().scale(0.1) + ax.transData)
 | 
						|
 | 
						|
    expected = np.array([[1.5, 1.24],
 | 
						|
                         [2., 1.25]])
 | 
						|
    assert_almost_equal(expected, ax.dataLim.get_points())
 | 
						|
 | 
						|
 | 
						|
def test_pcolormesh_pre_transform_limits():
 | 
						|
    # Based on test_contour_pre_transform_limits()
 | 
						|
    ax = plt.axes()
 | 
						|
    xs, ys = np.meshgrid(np.linspace(15, 20, 15), np.linspace(12.4, 12.5, 20))
 | 
						|
    ax.pcolormesh(xs, ys, np.log(xs * ys)[:-1, :-1],
 | 
						|
                  transform=mtransforms.Affine2D().scale(0.1) + ax.transData)
 | 
						|
 | 
						|
    expected = np.array([[1.5, 1.24],
 | 
						|
                         [2., 1.25]])
 | 
						|
    assert_almost_equal(expected, ax.dataLim.get_points())
 | 
						|
 | 
						|
 | 
						|
def test_pcolormesh_gouraud_nans():
 | 
						|
    np.random.seed(19680801)
 | 
						|
 | 
						|
    values = np.linspace(0, 180, 3)
 | 
						|
    radii = np.linspace(100, 1000, 10)
 | 
						|
    z, y = np.meshgrid(values, radii)
 | 
						|
    x = np.radians(np.random.rand(*z.shape) * 100)
 | 
						|
 | 
						|
    fig = plt.figure()
 | 
						|
    ax = fig.add_subplot(111, projection="polar")
 | 
						|
    # Setting the limit to cause clipping of the r values causes NaN to be
 | 
						|
    # introduced; these should not crash but be ignored as in other path
 | 
						|
    # operations.
 | 
						|
    ax.set_rlim(101, 1000)
 | 
						|
    ax.pcolormesh(x, y, z, shading="gouraud")
 | 
						|
 | 
						|
    fig.canvas.draw()
 | 
						|
 | 
						|
 | 
						|
def test_Affine2D_from_values():
 | 
						|
    points = np.array([[0, 0],
 | 
						|
                       [10, 20],
 | 
						|
                       [-1, 0],
 | 
						|
                       ])
 | 
						|
 | 
						|
    t = mtransforms.Affine2D.from_values(1, 0, 0, 0, 0, 0)
 | 
						|
    actual = t.transform(points)
 | 
						|
    expected = np.array([[0, 0], [10, 0], [-1, 0]])
 | 
						|
    assert_almost_equal(actual, expected)
 | 
						|
 | 
						|
    t = mtransforms.Affine2D.from_values(0, 2, 0, 0, 0, 0)
 | 
						|
    actual = t.transform(points)
 | 
						|
    expected = np.array([[0, 0], [0, 20], [0, -2]])
 | 
						|
    assert_almost_equal(actual, expected)
 | 
						|
 | 
						|
    t = mtransforms.Affine2D.from_values(0, 0, 3, 0, 0, 0)
 | 
						|
    actual = t.transform(points)
 | 
						|
    expected = np.array([[0, 0], [60, 0], [0, 0]])
 | 
						|
    assert_almost_equal(actual, expected)
 | 
						|
 | 
						|
    t = mtransforms.Affine2D.from_values(0, 0, 0, 4, 0, 0)
 | 
						|
    actual = t.transform(points)
 | 
						|
    expected = np.array([[0, 0], [0, 80], [0, 0]])
 | 
						|
    assert_almost_equal(actual, expected)
 | 
						|
 | 
						|
    t = mtransforms.Affine2D.from_values(0, 0, 0, 0, 5, 0)
 | 
						|
    actual = t.transform(points)
 | 
						|
    expected = np.array([[5, 0], [5, 0], [5, 0]])
 | 
						|
    assert_almost_equal(actual, expected)
 | 
						|
 | 
						|
    t = mtransforms.Affine2D.from_values(0, 0, 0, 0, 0, 6)
 | 
						|
    actual = t.transform(points)
 | 
						|
    expected = np.array([[0, 6], [0, 6], [0, 6]])
 | 
						|
    assert_almost_equal(actual, expected)
 | 
						|
 | 
						|
 | 
						|
def test_affine_inverted_invalidated():
 | 
						|
    # Ensure that the an affine transform is not declared valid on access
 | 
						|
    point = [1.0, 1.0]
 | 
						|
    t = mtransforms.Affine2D()
 | 
						|
 | 
						|
    assert_almost_equal(point, t.transform(t.inverted().transform(point)))
 | 
						|
    # Change and access the transform
 | 
						|
    t.translate(1.0, 1.0).get_matrix()
 | 
						|
    assert_almost_equal(point, t.transform(t.inverted().transform(point)))
 | 
						|
 | 
						|
 | 
						|
def test_clipping_of_log():
 | 
						|
    # issue 804
 | 
						|
    path = Path._create_closed([(0.2, -99), (0.4, -99), (0.4, 20), (0.2, 20)])
 | 
						|
    # something like this happens in plotting logarithmic histograms
 | 
						|
    trans = mtransforms.BlendedGenericTransform(
 | 
						|
        mtransforms.Affine2D(), scale.LogTransform(10, 'clip'))
 | 
						|
    tpath = trans.transform_path_non_affine(path)
 | 
						|
    result = tpath.iter_segments(trans.get_affine(),
 | 
						|
                                 clip=(0, 0, 100, 100),
 | 
						|
                                 simplify=False)
 | 
						|
    tpoints, tcodes = zip(*result)
 | 
						|
    assert_allclose(tcodes, path.codes[:-1])  # No longer closed.
 | 
						|
 | 
						|
 | 
						|
class NonAffineForTest(mtransforms.Transform):
 | 
						|
    """
 | 
						|
    A class which looks like a non affine transform, but does whatever
 | 
						|
    the given transform does (even if it is affine). This is very useful
 | 
						|
    for testing NonAffine behaviour with a simple Affine transform.
 | 
						|
 | 
						|
    """
 | 
						|
    is_affine = False
 | 
						|
    output_dims = 2
 | 
						|
    input_dims = 2
 | 
						|
 | 
						|
    def __init__(self, real_trans, *args, **kwargs):
 | 
						|
        self.real_trans = real_trans
 | 
						|
        super().__init__(*args, **kwargs)
 | 
						|
 | 
						|
    def transform_non_affine(self, values):
 | 
						|
        return self.real_trans.transform(values)
 | 
						|
 | 
						|
    def transform_path_non_affine(self, path):
 | 
						|
        return self.real_trans.transform_path(path)
 | 
						|
 | 
						|
 | 
						|
class TestBasicTransform:
 | 
						|
    def setup_method(self):
 | 
						|
 | 
						|
        self.ta1 = mtransforms.Affine2D(shorthand_name='ta1').rotate(np.pi / 2)
 | 
						|
        self.ta2 = mtransforms.Affine2D(shorthand_name='ta2').translate(10, 0)
 | 
						|
        self.ta3 = mtransforms.Affine2D(shorthand_name='ta3').scale(1, 2)
 | 
						|
 | 
						|
        self.tn1 = NonAffineForTest(mtransforms.Affine2D().translate(1, 2),
 | 
						|
                                    shorthand_name='tn1')
 | 
						|
        self.tn2 = NonAffineForTest(mtransforms.Affine2D().translate(1, 2),
 | 
						|
                                    shorthand_name='tn2')
 | 
						|
        self.tn3 = NonAffineForTest(mtransforms.Affine2D().translate(1, 2),
 | 
						|
                                    shorthand_name='tn3')
 | 
						|
 | 
						|
        # creates a transform stack which looks like ((A, (N, A)), A)
 | 
						|
        self.stack1 = (self.ta1 + (self.tn1 + self.ta2)) + self.ta3
 | 
						|
        # creates a transform stack which looks like (((A, N), A), A)
 | 
						|
        self.stack2 = self.ta1 + self.tn1 + self.ta2 + self.ta3
 | 
						|
        # creates a transform stack which is a subset of stack2
 | 
						|
        self.stack2_subset = self.tn1 + self.ta2 + self.ta3
 | 
						|
 | 
						|
        # when in debug, the transform stacks can produce dot images:
 | 
						|
#        self.stack1.write_graphviz(file('stack1.dot', 'w'))
 | 
						|
#        self.stack2.write_graphviz(file('stack2.dot', 'w'))
 | 
						|
#        self.stack2_subset.write_graphviz(file('stack2_subset.dot', 'w'))
 | 
						|
 | 
						|
    def test_transform_depth(self):
 | 
						|
        assert self.stack1.depth == 4
 | 
						|
        assert self.stack2.depth == 4
 | 
						|
        assert self.stack2_subset.depth == 3
 | 
						|
 | 
						|
    def test_left_to_right_iteration(self):
 | 
						|
        stack3 = (self.ta1 + (self.tn1 + (self.ta2 + self.tn2))) + self.ta3
 | 
						|
#        stack3.write_graphviz(file('stack3.dot', 'w'))
 | 
						|
 | 
						|
        target_transforms = [stack3,
 | 
						|
                             (self.tn1 + (self.ta2 + self.tn2)) + self.ta3,
 | 
						|
                             (self.ta2 + self.tn2) + self.ta3,
 | 
						|
                             self.tn2 + self.ta3,
 | 
						|
                             self.ta3,
 | 
						|
                             ]
 | 
						|
        r = [rh for _, rh in stack3._iter_break_from_left_to_right()]
 | 
						|
        assert len(r) == len(target_transforms)
 | 
						|
 | 
						|
        for target_stack, stack in zip(target_transforms, r):
 | 
						|
            assert target_stack == stack
 | 
						|
 | 
						|
    def test_transform_shortcuts(self):
 | 
						|
        assert self.stack1 - self.stack2_subset == self.ta1
 | 
						|
        assert self.stack2 - self.stack2_subset == self.ta1
 | 
						|
 | 
						|
        assert self.stack2_subset - self.stack2 == self.ta1.inverted()
 | 
						|
        assert (self.stack2_subset - self.stack2).depth == 1
 | 
						|
 | 
						|
        with pytest.raises(ValueError):
 | 
						|
            self.stack1 - self.stack2
 | 
						|
 | 
						|
        aff1 = self.ta1 + (self.ta2 + self.ta3)
 | 
						|
        aff2 = self.ta2 + self.ta3
 | 
						|
 | 
						|
        assert aff1 - aff2 == self.ta1
 | 
						|
        assert aff1 - self.ta2 == aff1 + self.ta2.inverted()
 | 
						|
 | 
						|
        assert self.stack1 - self.ta3 == self.ta1 + (self.tn1 + self.ta2)
 | 
						|
        assert self.stack2 - self.ta3 == self.ta1 + self.tn1 + self.ta2
 | 
						|
 | 
						|
        assert ((self.ta2 + self.ta3) - self.ta3 + self.ta3 ==
 | 
						|
                self.ta2 + self.ta3)
 | 
						|
 | 
						|
    def test_contains_branch(self):
 | 
						|
        r1 = (self.ta2 + self.ta1)
 | 
						|
        r2 = (self.ta2 + self.ta1)
 | 
						|
        assert r1 == r2
 | 
						|
        assert r1 != self.ta1
 | 
						|
        assert r1.contains_branch(r2)
 | 
						|
        assert r1.contains_branch(self.ta1)
 | 
						|
        assert not r1.contains_branch(self.ta2)
 | 
						|
        assert not r1.contains_branch(self.ta2 + self.ta2)
 | 
						|
 | 
						|
        assert r1 == r2
 | 
						|
 | 
						|
        assert self.stack1.contains_branch(self.ta3)
 | 
						|
        assert self.stack2.contains_branch(self.ta3)
 | 
						|
 | 
						|
        assert self.stack1.contains_branch(self.stack2_subset)
 | 
						|
        assert self.stack2.contains_branch(self.stack2_subset)
 | 
						|
 | 
						|
        assert not self.stack2_subset.contains_branch(self.stack1)
 | 
						|
        assert not self.stack2_subset.contains_branch(self.stack2)
 | 
						|
 | 
						|
        assert self.stack1.contains_branch(self.ta2 + self.ta3)
 | 
						|
        assert self.stack2.contains_branch(self.ta2 + self.ta3)
 | 
						|
 | 
						|
        assert not self.stack1.contains_branch(self.tn1 + self.ta2)
 | 
						|
 | 
						|
        blend = mtransforms.BlendedGenericTransform(self.tn2, self.stack2)
 | 
						|
        x, y = blend.contains_branch_seperately(self.stack2_subset)
 | 
						|
        stack_blend = self.tn3 + blend
 | 
						|
        sx, sy = stack_blend.contains_branch_seperately(self.stack2_subset)
 | 
						|
        assert x is sx is False
 | 
						|
        assert y is sy is True
 | 
						|
 | 
						|
    def test_affine_simplification(self):
 | 
						|
        # tests that a transform stack only calls as much is absolutely
 | 
						|
        # necessary "non-affine" allowing the best possible optimization with
 | 
						|
        # complex transformation stacks.
 | 
						|
        points = np.array([[0, 0], [10, 20], [np.nan, 1], [-1, 0]],
 | 
						|
                          dtype=np.float64)
 | 
						|
        na_pts = self.stack1.transform_non_affine(points)
 | 
						|
        all_pts = self.stack1.transform(points)
 | 
						|
 | 
						|
        na_expected = np.array([[1., 2.], [-19., 12.],
 | 
						|
                                [np.nan, np.nan], [1., 1.]], dtype=np.float64)
 | 
						|
        all_expected = np.array([[11., 4.], [-9., 24.],
 | 
						|
                                 [np.nan, np.nan], [11., 2.]],
 | 
						|
                                dtype=np.float64)
 | 
						|
 | 
						|
        # check we have the expected results from doing the affine part only
 | 
						|
        assert_array_almost_equal(na_pts, na_expected)
 | 
						|
        # check we have the expected results from a full transformation
 | 
						|
        assert_array_almost_equal(all_pts, all_expected)
 | 
						|
        # check we have the expected results from doing the transformation in
 | 
						|
        # two steps
 | 
						|
        assert_array_almost_equal(self.stack1.transform_affine(na_pts),
 | 
						|
                                  all_expected)
 | 
						|
        # check that getting the affine transformation first, then fully
 | 
						|
        # transforming using that yields the same result as before.
 | 
						|
        assert_array_almost_equal(self.stack1.get_affine().transform(na_pts),
 | 
						|
                                  all_expected)
 | 
						|
 | 
						|
        # check that the affine part of stack1 & stack2 are equivalent
 | 
						|
        # (i.e. the optimization is working)
 | 
						|
        expected_result = (self.ta2 + self.ta3).get_matrix()
 | 
						|
        result = self.stack1.get_affine().get_matrix()
 | 
						|
        assert_array_equal(expected_result, result)
 | 
						|
 | 
						|
        result = self.stack2.get_affine().get_matrix()
 | 
						|
        assert_array_equal(expected_result, result)
 | 
						|
 | 
						|
 | 
						|
class TestTransformPlotInterface:
 | 
						|
    def test_line_extent_axes_coords(self):
 | 
						|
        # a simple line in axes coordinates
 | 
						|
        ax = plt.axes()
 | 
						|
        ax.plot([0.1, 1.2, 0.8], [0.9, 0.5, 0.8], transform=ax.transAxes)
 | 
						|
        assert_array_equal(ax.dataLim.get_points(),
 | 
						|
                           np.array([[np.inf, np.inf],
 | 
						|
                                     [-np.inf, -np.inf]]))
 | 
						|
 | 
						|
    def test_line_extent_data_coords(self):
 | 
						|
        # a simple line in data coordinates
 | 
						|
        ax = plt.axes()
 | 
						|
        ax.plot([0.1, 1.2, 0.8], [0.9, 0.5, 0.8], transform=ax.transData)
 | 
						|
        assert_array_equal(ax.dataLim.get_points(),
 | 
						|
                           np.array([[0.1,  0.5], [1.2,  0.9]]))
 | 
						|
 | 
						|
    def test_line_extent_compound_coords1(self):
 | 
						|
        # a simple line in data coordinates in the y component, and in axes
 | 
						|
        # coordinates in the x
 | 
						|
        ax = plt.axes()
 | 
						|
        trans = mtransforms.blended_transform_factory(ax.transAxes,
 | 
						|
                                                      ax.transData)
 | 
						|
        ax.plot([0.1, 1.2, 0.8], [35, -5, 18], transform=trans)
 | 
						|
        assert_array_equal(ax.dataLim.get_points(),
 | 
						|
                           np.array([[np.inf, -5.],
 | 
						|
                                     [-np.inf, 35.]]))
 | 
						|
 | 
						|
    def test_line_extent_predata_transform_coords(self):
 | 
						|
        # a simple line in (offset + data) coordinates
 | 
						|
        ax = plt.axes()
 | 
						|
        trans = mtransforms.Affine2D().scale(10) + ax.transData
 | 
						|
        ax.plot([0.1, 1.2, 0.8], [35, -5, 18], transform=trans)
 | 
						|
        assert_array_equal(ax.dataLim.get_points(),
 | 
						|
                           np.array([[1., -50.], [12., 350.]]))
 | 
						|
 | 
						|
    def test_line_extent_compound_coords2(self):
 | 
						|
        # a simple line in (offset + data) coordinates in the y component, and
 | 
						|
        # in axes coordinates in the x
 | 
						|
        ax = plt.axes()
 | 
						|
        trans = mtransforms.blended_transform_factory(
 | 
						|
            ax.transAxes, mtransforms.Affine2D().scale(10) + ax.transData)
 | 
						|
        ax.plot([0.1, 1.2, 0.8], [35, -5, 18], transform=trans)
 | 
						|
        assert_array_equal(ax.dataLim.get_points(),
 | 
						|
                           np.array([[np.inf, -50.], [-np.inf, 350.]]))
 | 
						|
 | 
						|
    def test_line_extents_affine(self):
 | 
						|
        ax = plt.axes()
 | 
						|
        offset = mtransforms.Affine2D().translate(10, 10)
 | 
						|
        plt.plot(np.arange(10), transform=offset + ax.transData)
 | 
						|
        expected_data_lim = np.array([[0., 0.], [9.,  9.]]) + 10
 | 
						|
        assert_array_almost_equal(ax.dataLim.get_points(), expected_data_lim)
 | 
						|
 | 
						|
    def test_line_extents_non_affine(self):
 | 
						|
        ax = plt.axes()
 | 
						|
        offset = mtransforms.Affine2D().translate(10, 10)
 | 
						|
        na_offset = NonAffineForTest(mtransforms.Affine2D().translate(10, 10))
 | 
						|
        plt.plot(np.arange(10), transform=offset + na_offset + ax.transData)
 | 
						|
        expected_data_lim = np.array([[0., 0.], [9.,  9.]]) + 20
 | 
						|
        assert_array_almost_equal(ax.dataLim.get_points(), expected_data_lim)
 | 
						|
 | 
						|
    def test_pathc_extents_non_affine(self):
 | 
						|
        ax = plt.axes()
 | 
						|
        offset = mtransforms.Affine2D().translate(10, 10)
 | 
						|
        na_offset = NonAffineForTest(mtransforms.Affine2D().translate(10, 10))
 | 
						|
        pth = Path([[0, 0], [0, 10], [10, 10], [10, 0]])
 | 
						|
        patch = mpatches.PathPatch(pth,
 | 
						|
                                   transform=offset + na_offset + ax.transData)
 | 
						|
        ax.add_patch(patch)
 | 
						|
        expected_data_lim = np.array([[0., 0.], [10.,  10.]]) + 20
 | 
						|
        assert_array_almost_equal(ax.dataLim.get_points(), expected_data_lim)
 | 
						|
 | 
						|
    def test_pathc_extents_affine(self):
 | 
						|
        ax = plt.axes()
 | 
						|
        offset = mtransforms.Affine2D().translate(10, 10)
 | 
						|
        pth = Path([[0, 0], [0, 10], [10, 10], [10, 0]])
 | 
						|
        patch = mpatches.PathPatch(pth, transform=offset + ax.transData)
 | 
						|
        ax.add_patch(patch)
 | 
						|
        expected_data_lim = np.array([[0., 0.], [10.,  10.]]) + 10
 | 
						|
        assert_array_almost_equal(ax.dataLim.get_points(), expected_data_lim)
 | 
						|
 | 
						|
    def test_line_extents_for_non_affine_transData(self):
 | 
						|
        ax = plt.axes(projection='polar')
 | 
						|
        # add 10 to the radius of the data
 | 
						|
        offset = mtransforms.Affine2D().translate(0, 10)
 | 
						|
 | 
						|
        plt.plot(np.arange(10), transform=offset + ax.transData)
 | 
						|
        # the data lim of a polar plot is stored in coordinates
 | 
						|
        # before a transData transformation, hence the data limits
 | 
						|
        # are not what is being shown on the actual plot.
 | 
						|
        expected_data_lim = np.array([[0., 0.], [9.,  9.]]) + [0, 10]
 | 
						|
        assert_array_almost_equal(ax.dataLim.get_points(), expected_data_lim)
 | 
						|
 | 
						|
 | 
						|
def assert_bbox_eq(bbox1, bbox2):
 | 
						|
    assert_array_equal(bbox1.bounds, bbox2.bounds)
 | 
						|
 | 
						|
 | 
						|
def test_bbox_frozen_copies_minpos():
 | 
						|
    bbox = mtransforms.Bbox.from_extents(0.0, 0.0, 1.0, 1.0, minpos=1.0)
 | 
						|
    frozen = bbox.frozen()
 | 
						|
    assert_array_equal(frozen.minpos, bbox.minpos)
 | 
						|
 | 
						|
 | 
						|
def test_bbox_intersection():
 | 
						|
    bbox_from_ext = mtransforms.Bbox.from_extents
 | 
						|
    inter = mtransforms.Bbox.intersection
 | 
						|
 | 
						|
    r1 = bbox_from_ext(0, 0, 1, 1)
 | 
						|
    r2 = bbox_from_ext(0.5, 0.5, 1.5, 1.5)
 | 
						|
    r3 = bbox_from_ext(0.5, 0, 0.75, 0.75)
 | 
						|
    r4 = bbox_from_ext(0.5, 1.5, 1, 2.5)
 | 
						|
    r5 = bbox_from_ext(1, 1, 2, 2)
 | 
						|
 | 
						|
    # self intersection -> no change
 | 
						|
    assert_bbox_eq(inter(r1, r1), r1)
 | 
						|
    # simple intersection
 | 
						|
    assert_bbox_eq(inter(r1, r2), bbox_from_ext(0.5, 0.5, 1, 1))
 | 
						|
    # r3 contains r2
 | 
						|
    assert_bbox_eq(inter(r1, r3), r3)
 | 
						|
    # no intersection
 | 
						|
    assert inter(r1, r4) is None
 | 
						|
    # single point
 | 
						|
    assert_bbox_eq(inter(r1, r5), bbox_from_ext(1, 1, 1, 1))
 | 
						|
 | 
						|
 | 
						|
def test_bbox_as_strings():
 | 
						|
    b = mtransforms.Bbox([[.5, 0], [.75, .75]])
 | 
						|
    assert_bbox_eq(b, eval(repr(b), {'Bbox': mtransforms.Bbox}))
 | 
						|
    asdict = eval(str(b), {'Bbox': dict})
 | 
						|
    for k, v in asdict.items():
 | 
						|
        assert getattr(b, k) == v
 | 
						|
    fmt = '.1f'
 | 
						|
    asdict = eval(format(b, fmt), {'Bbox': dict})
 | 
						|
    for k, v in asdict.items():
 | 
						|
        assert eval(format(getattr(b, k), fmt)) == v
 | 
						|
 | 
						|
 | 
						|
def test_str_transform():
 | 
						|
    # The str here should not be considered as "absolutely stable", and may be
 | 
						|
    # reformatted later; this is just a smoketest for __str__.
 | 
						|
    assert str(plt.subplot(projection="polar").transData) == """\
 | 
						|
CompositeGenericTransform(
 | 
						|
    CompositeGenericTransform(
 | 
						|
        CompositeGenericTransform(
 | 
						|
            TransformWrapper(
 | 
						|
                BlendedAffine2D(
 | 
						|
                    IdentityTransform(),
 | 
						|
                    IdentityTransform())),
 | 
						|
            CompositeAffine2D(
 | 
						|
                Affine2D().scale(1.0),
 | 
						|
                Affine2D().scale(1.0))),
 | 
						|
        PolarTransform(
 | 
						|
            PolarAxes(0.125,0.1;0.775x0.8),
 | 
						|
            use_rmin=True,
 | 
						|
            apply_theta_transforms=False)),
 | 
						|
    CompositeGenericTransform(
 | 
						|
        CompositeGenericTransform(
 | 
						|
            PolarAffine(
 | 
						|
                TransformWrapper(
 | 
						|
                    BlendedAffine2D(
 | 
						|
                        IdentityTransform(),
 | 
						|
                        IdentityTransform())),
 | 
						|
                LockableBbox(
 | 
						|
                    Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0),
 | 
						|
                    [[-- --]
 | 
						|
                     [-- --]])),
 | 
						|
            BboxTransformFrom(
 | 
						|
                _WedgeBbox(
 | 
						|
                    (0.5, 0.5),
 | 
						|
                    TransformedBbox(
 | 
						|
                        Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0),
 | 
						|
                        CompositeAffine2D(
 | 
						|
                            Affine2D().scale(1.0),
 | 
						|
                            Affine2D().scale(1.0))),
 | 
						|
                    LockableBbox(
 | 
						|
                        Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0),
 | 
						|
                        [[-- --]
 | 
						|
                         [-- --]])))),
 | 
						|
        BboxTransformTo(
 | 
						|
            TransformedBbox(
 | 
						|
                Bbox(x0=0.125, y0=0.09999999999999998, x1=0.9, y1=0.9),
 | 
						|
                BboxTransformTo(
 | 
						|
                    TransformedBbox(
 | 
						|
                        Bbox(x0=0.0, y0=0.0, x1=8.0, y1=6.0),
 | 
						|
                        Affine2D().scale(80.0)))))))"""
 | 
						|
 | 
						|
 | 
						|
def test_transform_single_point():
 | 
						|
    t = mtransforms.Affine2D()
 | 
						|
    r = t.transform_affine((1, 1))
 | 
						|
    assert r.shape == (2,)
 | 
						|
 | 
						|
 | 
						|
def test_log_transform():
 | 
						|
    # Tests that the last line runs without exception (previously the
 | 
						|
    # transform would fail if one of the axes was logarithmic).
 | 
						|
    fig, ax = plt.subplots()
 | 
						|
    ax.set_yscale('log')
 | 
						|
    ax.transData.transform((1, 1))
 | 
						|
 | 
						|
 | 
						|
def test_nan_overlap():
 | 
						|
    a = mtransforms.Bbox([[0, 0], [1, 1]])
 | 
						|
    b = mtransforms.Bbox([[0, 0], [1, np.nan]])
 | 
						|
    assert not a.overlaps(b)
 | 
						|
 | 
						|
 | 
						|
def test_transform_angles():
 | 
						|
    t = mtransforms.Affine2D()  # Identity transform
 | 
						|
    angles = np.array([20, 45, 60])
 | 
						|
    points = np.array([[0, 0], [1, 1], [2, 2]])
 | 
						|
 | 
						|
    # Identity transform does not change angles
 | 
						|
    new_angles = t.transform_angles(angles, points)
 | 
						|
    assert_array_almost_equal(angles, new_angles)
 | 
						|
 | 
						|
    # points missing a 2nd dimension
 | 
						|
    with pytest.raises(ValueError):
 | 
						|
        t.transform_angles(angles, points[0:2, 0:1])
 | 
						|
 | 
						|
    # Number of angles != Number of points
 | 
						|
    with pytest.raises(ValueError):
 | 
						|
        t.transform_angles(angles, points[0:2, :])
 | 
						|
 | 
						|
 | 
						|
def test_nonsingular():
 | 
						|
    # test for zero-expansion type cases; other cases may be added later
 | 
						|
    zero_expansion = np.array([-0.001, 0.001])
 | 
						|
    cases = [(0, np.nan), (0, 0), (0, 7.9e-317)]
 | 
						|
    for args in cases:
 | 
						|
        out = np.array(mtransforms.nonsingular(*args))
 | 
						|
        assert_array_equal(out, zero_expansion)
 | 
						|
 | 
						|
 | 
						|
def test_transformed_path():
 | 
						|
    points = [(0, 0), (1, 0), (1, 1), (0, 1)]
 | 
						|
    path = Path(points, closed=True)
 | 
						|
 | 
						|
    trans = mtransforms.Affine2D()
 | 
						|
    trans_path = mtransforms.TransformedPath(path, trans)
 | 
						|
    assert_allclose(trans_path.get_fully_transformed_path().vertices, points)
 | 
						|
 | 
						|
    # Changing the transform should change the result.
 | 
						|
    r2 = 1 / np.sqrt(2)
 | 
						|
    trans.rotate(np.pi / 4)
 | 
						|
    assert_allclose(trans_path.get_fully_transformed_path().vertices,
 | 
						|
                    [(0, 0), (r2, r2), (0, 2 * r2), (-r2, r2)],
 | 
						|
                    atol=1e-15)
 | 
						|
 | 
						|
    # Changing the path does not change the result (it's cached).
 | 
						|
    path.points = [(0, 0)] * 4
 | 
						|
    assert_allclose(trans_path.get_fully_transformed_path().vertices,
 | 
						|
                    [(0, 0), (r2, r2), (0, 2 * r2), (-r2, r2)],
 | 
						|
                    atol=1e-15)
 | 
						|
 | 
						|
 | 
						|
def test_transformed_patch_path():
 | 
						|
    trans = mtransforms.Affine2D()
 | 
						|
    patch = mpatches.Wedge((0, 0), 1, 45, 135, transform=trans)
 | 
						|
 | 
						|
    tpatch = mtransforms.TransformedPatchPath(patch)
 | 
						|
    points = tpatch.get_fully_transformed_path().vertices
 | 
						|
 | 
						|
    # Changing the transform should change the result.
 | 
						|
    trans.scale(2)
 | 
						|
    assert_allclose(tpatch.get_fully_transformed_path().vertices, points * 2)
 | 
						|
 | 
						|
    # Changing the path should change the result (and cancel out the scaling
 | 
						|
    # from the transform).
 | 
						|
    patch.set_radius(0.5)
 | 
						|
    assert_allclose(tpatch.get_fully_transformed_path().vertices, points)
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.parametrize('locked_element', ['x0', 'y0', 'x1', 'y1'])
 | 
						|
def test_lockable_bbox(locked_element):
 | 
						|
    other_elements = ['x0', 'y0', 'x1', 'y1']
 | 
						|
    other_elements.remove(locked_element)
 | 
						|
 | 
						|
    orig = mtransforms.Bbox.unit()
 | 
						|
    locked = mtransforms.LockableBbox(orig, **{locked_element: 2})
 | 
						|
 | 
						|
    # LockableBbox should keep its locked element as specified in __init__.
 | 
						|
    assert getattr(locked, locked_element) == 2
 | 
						|
    assert getattr(locked, 'locked_' + locked_element) == 2
 | 
						|
    for elem in other_elements:
 | 
						|
        assert getattr(locked, elem) == getattr(orig, elem)
 | 
						|
 | 
						|
    # Changing underlying Bbox should update everything but locked element.
 | 
						|
    orig.set_points(orig.get_points() + 10)
 | 
						|
    assert getattr(locked, locked_element) == 2
 | 
						|
    assert getattr(locked, 'locked_' + locked_element) == 2
 | 
						|
    for elem in other_elements:
 | 
						|
        assert getattr(locked, elem) == getattr(orig, elem)
 | 
						|
 | 
						|
    # Unlocking element should revert values back to the underlying Bbox.
 | 
						|
    setattr(locked, 'locked_' + locked_element, None)
 | 
						|
    assert getattr(locked, 'locked_' + locked_element) is None
 | 
						|
    assert np.all(orig.get_points() == locked.get_points())
 | 
						|
 | 
						|
    # Relocking an element should change its value, but not others.
 | 
						|
    setattr(locked, 'locked_' + locked_element, 3)
 | 
						|
    assert getattr(locked, locked_element) == 3
 | 
						|
    assert getattr(locked, 'locked_' + locked_element) == 3
 | 
						|
    for elem in other_elements:
 | 
						|
        assert getattr(locked, elem) == getattr(orig, elem)
 | 
						|
 | 
						|
 | 
						|
def test_transformwrapper():
 | 
						|
    t = mtransforms.TransformWrapper(mtransforms.Affine2D())
 | 
						|
    with pytest.raises(ValueError, match=(
 | 
						|
            r"The input and output dims of the new child \(1, 1\) "
 | 
						|
            r"do not match those of current child \(2, 2\)")):
 | 
						|
        t.set(scale.LogTransform(10))
 | 
						|
 | 
						|
 | 
						|
@check_figures_equal(extensions=["png"])
 | 
						|
def test_scale_swapping(fig_test, fig_ref):
 | 
						|
    np.random.seed(19680801)
 | 
						|
    samples = np.random.normal(size=10)
 | 
						|
    x = np.linspace(-5, 5, 10)
 | 
						|
 | 
						|
    for fig, log_state in zip([fig_test, fig_ref], [True, False]):
 | 
						|
        ax = fig.subplots()
 | 
						|
        ax.hist(samples, log=log_state, density=True)
 | 
						|
        ax.plot(x, np.exp(-(x**2) / 2) / np.sqrt(2 * np.pi))
 | 
						|
        fig.canvas.draw()
 | 
						|
        ax.set_yscale('linear')
 | 
						|
 | 
						|
 | 
						|
def test_offset_copy_errors():
 | 
						|
    with pytest.raises(ValueError,
 | 
						|
                       match="'fontsize' is not a valid value for units;"
 | 
						|
                             " supported values are 'dots', 'points', 'inches'"):
 | 
						|
        mtransforms.offset_copy(None, units='fontsize')
 | 
						|
 | 
						|
    with pytest.raises(ValueError,
 | 
						|
                       match='For units of inches or points a fig kwarg is needed'):
 | 
						|
        mtransforms.offset_copy(None, units='inches')
 | 
						|
 | 
						|
 | 
						|
def test_transformedbbox_contains():
 | 
						|
    bb = TransformedBbox(Bbox.unit(), Affine2D().rotate_deg(30))
 | 
						|
    assert bb.contains(.8, .5)
 | 
						|
    assert bb.contains(-.4, .85)
 | 
						|
    assert not bb.contains(.9, .5)
 | 
						|
    bb = TransformedBbox(Bbox.unit(), Affine2D().translate(.25, .5))
 | 
						|
    assert bb.contains(1.25, 1.5)
 | 
						|
    assert not bb.fully_contains(1.25, 1.5)
 | 
						|
    assert not bb.fully_contains(.1, .1)
 | 
						|
 | 
						|
 | 
						|
def test_interval_contains():
 | 
						|
    assert mtransforms.interval_contains((0, 1), 0.5)
 | 
						|
    assert mtransforms.interval_contains((0, 1), 0)
 | 
						|
    assert mtransforms.interval_contains((0, 1), 1)
 | 
						|
    assert not mtransforms.interval_contains((0, 1), -1)
 | 
						|
    assert not mtransforms.interval_contains((0, 1), 2)
 | 
						|
    assert mtransforms.interval_contains((1, 0), 0.5)
 | 
						|
 | 
						|
 | 
						|
def test_interval_contains_open():
 | 
						|
    assert mtransforms.interval_contains_open((0, 1), 0.5)
 | 
						|
    assert not mtransforms.interval_contains_open((0, 1), 0)
 | 
						|
    assert not mtransforms.interval_contains_open((0, 1), 1)
 | 
						|
    assert not mtransforms.interval_contains_open((0, 1), -1)
 | 
						|
    assert not mtransforms.interval_contains_open((0, 1), 2)
 | 
						|
    assert mtransforms.interval_contains_open((1, 0), 0.5)
 | 
						|
 | 
						|
 | 
						|
def test_scaledrotation_initialization():
 | 
						|
    """Test that the ScaledRotation object is initialized correctly."""
 | 
						|
    theta = 1.0  # Arbitrary theta value for testing
 | 
						|
    trans_shift = MagicMock()  # Mock the trans_shift transformation
 | 
						|
    scaled_rot = _ScaledRotation(theta, trans_shift)
 | 
						|
    assert scaled_rot._theta == theta
 | 
						|
    assert scaled_rot._trans_shift == trans_shift
 | 
						|
    assert scaled_rot._mtx is None
 | 
						|
 | 
						|
 | 
						|
def test_scaledrotation_get_matrix_invalid():
 | 
						|
    """Test get_matrix when the matrix is invalid and needs recalculation."""
 | 
						|
    theta = np.pi / 2
 | 
						|
    trans_shift = MagicMock(transform=MagicMock(return_value=[[theta, 0]]))
 | 
						|
    scaled_rot = _ScaledRotation(theta, trans_shift)
 | 
						|
    scaled_rot._invalid = True
 | 
						|
    matrix = scaled_rot.get_matrix()
 | 
						|
    trans_shift.transform.assert_called_once_with([[theta, 0]])
 | 
						|
    expected_rotation = np.array([[0, -1],
 | 
						|
                                  [1,  0]])
 | 
						|
    assert matrix is not None
 | 
						|
    assert_allclose(matrix[:2, :2], expected_rotation, atol=1e-15)
 |