import matplotlib.pyplot as plt
import numpy as np
from cycler import cycler


def arrowhead(ax, x, y, color, size_values, style_value):
    """Add an arrowhead at the end of an already plotted line segment."""
    x = np.asarray(x, dtype=float)
    y = np.asarray(y, dtype=float)
    dx = x[-1] - x[-2]
    dy = y[-1] - y[-2]
    length = np.hypot(dx, dy)
    if length == 0:
        return
    fraction = min(0.18, 0.10 + 0.01 * float(style_value))
    start = (x[-1] - fraction * dx, y[-1] - fraction * dy)
    mutation_scale = 7 + 2.0 * float(style_value)
    ax.annotate(
        "",
        xy=(x[-1], y[-1]),
        xytext=start,
        arrowprops=dict(arrowstyle="-|>", color=color, linewidth=0.8, mutation_scale=mutation_scale),
    )


def fig4_7():
    A = np.zeros((2, 2))
    A[0, 0] = 2
    A[0, 1] = 2
    A[1, 0] = 3
    A[1, 1] = -1
    U, sigma, Vh = np.linalg.svd(A)
    S = np.diag(sigma)
    V = Vh.T
    print("U =")
    print(U)
    print("S =")
    print(S)
    print("V =")
    print(V)
    U = -U
    V = -V

    plt.close("all")
    # get(gcf)
    fig, axes = plt.subplots(1, 2, figsize=(8.67, 4.36))
    fig.subplots_adjust(top=0.97, bottom=0.13, right=0.98, left=0.06, wspace=0.12)
    co = [
        (0, 0, 1),
        (0, 0.5, 0),
        (1, 0, 0),
        (0, 0.75, 0.75),
        (0.75, 0, 0.75),
        (0.75, 0.75, 0),
        (0.25, 0.25, 0.25),
    ]
    for ax in axes:
        ax.set_prop_cycle(cycler(color=co))

    nt = 200
    th = np.linspace(0, 2 * np.pi, nt)

    ax = axes[0]

    print(np.linalg.norm(A, np.inf))
    print(np.linalg.cond(A, np.inf))
    print(np.linalg.cond(A, 2))

    xL = 1.3

    x0 = np.zeros(nt)
    y0 = np.zeros(nt)
    x1 = np.zeros(nt)
    y1 = np.zeros(nt)
    for it in range(nt):
        x0[it] = np.cos(th[it])
        y0[it] = np.sin(th[it])
        x1[it] = A[0, 0] * x0[it] + A[0, 1] * y0[it]
        y1[it] = A[1, 0] * x0[it] + A[1, 1] * y0[it]

    ax.plot(x0, y0, "k", linewidth=2)

    # ax.plot([-xL, xL], [0, 0], 'k', linewidth=0.3)
    # ax.plot([0, 0], [-xL, xL], 'k', linewidth=0.3)

    ax.plot([V[0, 0], -V[0, 0]], [V[1, 0], -V[1, 0]], "--r", linewidth=1.5)
    ax.plot([V[0, 1], -V[0, 1]], [V[1, 1], -V[1, 1]], "--b", linewidth=1.5)

    ax.plot([0, V[0, 0]], [0, V[1, 0]], "r", linewidth=2)
    ax.plot([0, V[0, 1]], [0, V[1, 1]], "b", linewidth=2)
    arrowhead(ax, [0, V[0, 0]], [0, V[1, 0]], "r", [1.4, 2.2], 3)
    arrowhead(ax, [0, V[0, 1]], [0, V[1, 1]], "b", [2.7, 1.1], 3)

    ax.set_aspect("equal", adjustable="box")
    ax.grid(True)
    ax.axis("off")
    ax.axis([-xL, xL, -xL, xL])
    ax.plot([-xL, xL], [0, 0], "k", linewidth=0.3)
    ax.plot([0, 0], [-xL, xL], "k", linewidth=0.3)
    arrowhead(ax, [0, xL], [0, 0], "k", [1, 1.5], 1)
    arrowhead(ax, [0, 0], [0, xL], "k", [1.7, 0.7], 1)

    ax.text(0.6, 0.3, r"$\mathbf{v}_1$", fontsize=20, fontweight="bold")
    ax.text(-0.37, 0.75, r"$\mathbf{v}_2$", fontsize=20, fontweight="bold")

    ax.text(xL - 0.1, -0.18, r"$x_1$", fontsize=28)
    ax.text(-0.35, xL - 0.05, r"$x_2$", fontsize=28)

    ax = axes[1]
    xL = 3.3
    ax.plot(x1, y1, "k", linewidth=2)
    # ax.plot([-xL, xL], [0, 0], 'k', linewidth=0.3)
    # ax.plot([0, 0], [-xL, xL], 'k', linewidth=0.3)

    ax.plot(
        [S[0, 0] * U[0, 0], -S[0, 0] * U[0, 0]],
        [S[0, 0] * U[1, 0], -S[0, 0] * U[1, 0]],
        "--r",
        linewidth=1.5,
    )
    ax.plot(
        [S[1, 1] * U[0, 1], -S[1, 1] * U[0, 1]],
        [S[1, 1] * U[1, 1], -S[1, 1] * U[1, 1]],
        "--b",
        linewidth=1.5,
    )

    ax.plot([0, U[0, 0]], [0, U[1, 0]], "r", linewidth=2.5)
    ax.plot([0, U[0, 1]], [0, U[1, 1]], "b", linewidth=2.5)
    arrowhead(ax, [0, U[0, 0]], [0, U[1, 0]], "r", [1.4, 1.4], 3)
    arrowhead(ax, [0, U[0, 1]], [0, U[1, 1]], "b", [1.6, 1.4], 3)

    ax.text(0.5, 2, r"$\sigma_1$", fontsize=26)
    ax.text(1.2, -0.48, r"$\sigma_2$", fontsize=26)

    xL = xL * 1.08
    ax.set_aspect("equal", adjustable="box")
    ax.axis([-xL, xL, -xL, xL])
    ax.axis("off")
    ax.axis([-xL, xL, -xL, xL])
    ax.plot([-xL, xL], [0, 0], "k", linewidth=0.3)
    ax.plot([0, 0], [-xL, xL], "k", linewidth=0.3)

    arrowhead(ax, [0, xL], [0, 0], "k", [1, 1.5], 1)
    arrowhead(ax, [0, 0], [0, xL], "k", [1.7, 0.7], 1)

    ax.text(-0.32, 1, r"$\mathbf{u}_1$", fontsize=20, fontweight="bold")
    ax.text(0.2, -0.9, r"$\mathbf{u}_2$", fontsize=20, fontweight="bold")

    ax.text(xL - 0.3, -0.5, r"$y_1$", fontsize=28)
    ax.text(-0.85, xL - 0.15, r"$y_2$", fontsize=28)

    # fig.savefig('/Users/mark/Desktop/ellip5.eps')
    # fig.savefig('/Users/holmes/Desktop/ellip5.eps')
    # fig.savefig('/Users/mark/Desktop/ellip5.png', dpi=1200)
    plt.show()


if __name__ == "__main__":
    fig4_7()
