Repository: matplotlib/matplotlib
File: lib/mpl_toolkits/mplot3d/tests/test_axes3d.py (Python)

Code before:
    # Check that offset text is visible and has content
    # The offset text may not be visible on all backends/configurations,
    # so we only test the inclusion when it's actually present
    if (zaxis.offsetText.get_visible() and
        zaxis.offsetText.get_text()):
        offset_bbox = zaxis.offsetText.get_window_extent(renderer)

        # Get the tight bbox - this should include the offset text
        bbox = zaxis.get_tightbbox(renderer)
        assert bbox is not None
        assert offset_bbox is not None

        # The tight bbox should fully contain the offset text bbox
        # Check that offset_bbox is within bbox bounds (with small tolerance for
        # floating point errors)
        assert bbox.x0 <= offset_bbox.x0 + 1e-6, \
            f"bbox.x0 ({bbox.x0}) should be <= offset_bbox.x0 ({offset_bbox.x0})"
        assert bbox.y0 <= offset_bbox.y0 + 1e-6, \
            f"bbox.y0 ({bbox.y0}) should be <= offset_bbox.y0 ({offset_bbox.y0})"
        assert bbox.x1 >= offset_bbox.x1 - 1e-6, \
            f"bbox.x1 ({bbox.x1}) should be >= offset_bbox.x1 ({offset_bbox.x1})"
        assert bbox.y1 >= offset_bbox.y1 - 1e-6, \
            f"bbox.y1 ({bbox.y1}) should be >= offset_bbox.y1 ({offset_bbox.y1})"


class DummyEvent:
    def __init__(self, xdata=None, ydata=None, inaxes=None):
        self.xdata = xdata
        self.ydata = ydata
        self.inaxes = inaxes
        self.x = 0
        self.y = 0
        self.button = 1
        self.key = "control"


def _is_multiple_of_step(val, step):
    return np.isclose(val, step * round(val / step), atol=5e-2)


def test_ctrl_rotation_snaps_to_5deg(monkeypatch):
    fig = plt.figure()
    ax = fig.add_subplot(projection="3d")

    ax.M = np.eye(4)
    ax._pseudo_w = 1
    ax._pseudo_h = 1

    ax.button_pressed = 1
    ax._rotate_btn = [1]
    ax._sx, ax._sy = 0.0, 0.0

Review comment (suggestion):
Can replace this with `MouseEvent` from `matplotlib.backend_bases`, this will let you pass the `key` kwarg.

Code after:
    # Check that offset text is visible and has content
    # The offset text may not be visible on all backends/configurations,
    # so we only test the inclusion when it's actually present
    if (zaxis.offsetText.get_visible() and
        zaxis.offsetText.get_text()):
        offset_bbox = zaxis.offsetText.get_window_extent(renderer)

        # Get the tight bbox - this should include the offset text
        bbox = zaxis.get_tightbbox(renderer)
        assert bbox is not None
        assert offset_bbox is not None

        # The tight bbox should fully contain the offset text bbox
        # Check that offset_bbox is within bbox bounds (with small tolerance for
        # floating point errors)
        assert bbox.x0 <= offset_bbox.x0 + 1e-6, \
            f"bbox.x0 ({bbox.x0}) should be <= offset_bbox.x0 ({offset_bbox.x0})"
        assert bbox.y0 <= offset_bbox.y0 + 1e-6, \
            f"bbox.y0 ({bbox.y0}) should be <= offset_bbox.y0 ({offset_bbox.y0})"
        assert bbox.x1 >= offset_bbox.x1 - 1e-6, \
            f"bbox.x1 ({bbox.x1}) should be >= offset_bbox.x1 ({offset_bbox.x1})"
        assert bbox.y1 >= offset_bbox.y1 - 1e-6, \
            f"bbox.y1 ({bbox.y1}) should be >= offset_bbox.y1 ({offset_bbox.y1})"


def test_ctrl_rotation_snaps_to_5deg():
    fig = plt.figure()
    ax = fig.add_subplot(projection='3d')

    initial = (12.3, 33.7, 2.2)
    ax.view_init(*initial)
    fig.canvas.draw()

    s = 0.25
    step = plt.rcParams["axes3d.snap_rotation"]

    # First rotation without Ctrl
    with mpl.rc_context({'axes3d.mouserotationstyle': 'azel'}):
        MouseEvent._from_ax_coords(
            "button_press_event", ax, (0, 0), MouseButton.LEFT
        )._process()

        MouseEvent._from_ax_coords(
            "motion_notify_event",
            ax,
            (s * ax._pseudo_w, s * ax._pseudo_h),
            MouseButton.LEFT,
        )._process()

    fig.canvas.draw()