Close Menu
    Facebook LinkedIn YouTube WhatsApp X (Twitter) Pinterest
    Trending
    • Enhancing Customer Support with AI Text-to-Speech Tools
    • Kamingo 5-lb plug-and-play electric bike drive system
    • German FinTech startup NaroIQ raises €5.8 million to establish European fund infrastructure
    • Amazon Rebuilt Alexa Using a ‘Staggering’ Amount of AI Tools
    • I’m Talking Back to Google’s New Search Live Mode for AI Convos About Big Events
    • Texas Instruments to make ‘historic’ $60bn US chip investment
    • A Multi-Agent SQL Assistant You Can Trust with Human-in-Loop Checkpoint & LLM Cost Control
    • Helpful helmet packs crank-charged removable bike lights
    Facebook LinkedIn WhatsApp
    Times FeaturedTimes Featured
    Thursday, June 19
    • Home
    • Founders
    • Startups
    • Technology
    • Profiles
    • Entrepreneurs
    • Leaders
    • Students
    • VC Funds
    • More
      • AI
      • Robotics
      • Industries
      • Global
    Times FeaturedTimes Featured
    Home»Artificial Intelligence»Animating Linear Transformations with Quiver
    Artificial Intelligence

    Animating Linear Transformations with Quiver

    Editor Times FeaturedBy Editor Times FeaturedJune 18, 2025No Comments9 Mins Read
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr WhatsApp Email
    Share
    Facebook Twitter LinkedIn Pinterest Telegram Email WhatsApp Copy Link


    scientist inevitably means engaged on a number of layers of abstraction, foremost abstractions of code and math. That is nice, as a result of this lets you get astonishing outcomes rapidly. However typically it’s well-advised to pause for a second and ponder what really occurs behind a neat interface. This means of pondering is usually assisted by visualizations. On this article, I need to current how animated quiver plots will help to ponder about linear transformations, which frequently toil away reliably within the obscurity of machine studying algorithms and related interfaces. In the long run, we can visualize ideas like Singular Worth Decomposition with our quiver plot.

    Plotting Static Quiver Plots

    A quiver plot from the matplotlib python bundle permits us to plot arrows (which in our case symbolize vectors). Let’s first check out a static quiver plot:

    Picture by Writer

    We are able to instantly derive the transformation matrix from the picture by wanting on the goal positions of the 2 base vectors. The primary base vector is beginning at place (1, 0) and touchdown on (1, 1), whereas the second base vector travels from (0, 1) to (-1, 1). Due to this fact the matrix, that describes this transformation is:

    [
    begin{pmatrix}
    1 & -1
    1 & 1
    end{pmatrix}
    ]

    Visually this corresponds to an anti-clockwise rotation by 45 levels (or (pi/4) in radian) and a slight stretch (by the issue (sqrt{2})).

    With this data, let’s take a look at how that is carried out with quiver (Observe that I omit some boilerplate code like scaling of axis):

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib import cm
    
    def quiver_plot_base_vectors(transformation_matrix: np.ndarray):
        # Outline vectors
        basis_i = np.array([1, 0])
        basis_j = np.array([0, 1])
        i_transformed = transformation_matrix[:, 0]
        j_transformed = transformation_matrix[:, 1]
        
        # plot vectors with quiver-function
        cmap = cm.inferno
        fig, ax = plt.subplots()
        ax.quiver(0, 0, basis_i[0], basis_i[1], 
            shade=cmap(0.2), 
            scale=1, 
            angles="xy", 
            scale_units="xy", 
            label="i", 
            alpha=0.3)
        ax.quiver(0, 0, i_transformed[0], i_transformed[1], 
            shade=cmap(0.2), 
            scale=1,   
            angles="xy",  
            scale_units="xy", 
            label="i_transformed")
        ax.quiver(0, 0, basis_j[0], basis_j[1], 
            shade=cmap(0.5), 
            scale=1, 
            angles="xy", 
            scale_units="xy", 
            label="j", 
            alpha=0.3)
        ax.quiver(0, 0, j_transformed[0], j_transformed[1], 
            shade=cmap(0.5), 
            scale=1, 
            angles="xy", 
            scale_units="xy", 
            label="j_transformed")
    
    if __name__ == "__main__":
        matrix = np.array([
            [1, -1],
            [1, 1]  
        ])
        quiver_plot_base_vectors(matrix)

    As you may see we outlined one quiver plot per vector. That is only for illustrative functions. If we take a look at the signature of the quiver operate – quiver([X, Y], U, V, [C], /, **kwargs) – we will observe that U and V take numpy arrays as enter, which is best than offering scalar values. Let’s refactor this operate to utilizing just one quiver invocation. Moreover, let’s add a vector v = (1.5, -0.5) to see the transformation utilized on it.

    def quiver_plot(transformation_matrix: np.ndarray, vector: np.ndarray):
        # Outline vectors
        basis_i = np.array([1, 0])
        basis_j = np.array([0, 1])
        i_transformed = transformation_matrix[:, 0]
        j_transformed = transformation_matrix[:, 1]
        vector_transformed = transformation_matrix @ vector
        U, V = np.stack(
            [
                basis_i, i_transformed,
                basis_j, j_transformed,
                vector, vector_transformed,
            ],
            axis=1)
    
        # Draw vectors
        shade = np.array([.2, .2, .5, .5, .8, .8])
        alpha = np.array([.3, 1.0, .3, 1.0, .3, 1.0])
        cmap = cm.inferno
        fig, ax = plt.subplots()
        ax.quiver(np.zeros(6), np.zeros(6), U, V,
            shade=cmap(shade),
            alpha=alpha,
            scale=1,
            angles="xy",
            scale_units="xy",
        )
    
    if __name__ == "__main__":
        matrix = np.sqrt(2) * np.array([
            [np.cos(np.pi / 4), np.cos(3 * np.pi / 4)],
            [np.sin(np.pi / 4), np.sin(3 * np.pi / 4)]
        ])
        vector = np.array([1.5, -0.5])
        quiver_plot(matrix, vector)

    That is a lot shorter and handy than the primary instance. What we did right here was to stack every vector horizontally producing the next array:

    The primary row corresponds to the U-parameter of quiver and the second to V. Whereas the columns maintain our vectors, the place (vec{i}) is the primary base vector, (vec{j}) is the second and (vec{v}) is our customized vector. The indices, b and a, stand for earlier than and after (i.e. whether or not the linear transformation is utilized or not). Let’s take a look at the output:

    Linear Transformation of base vectors and (vec{v})
    Picture by Writer

    Taking a second take a look at the code it may be complicated what occurred to our neat and easy transformation matrix, which was restated to:

    [
    {scriptsize
    M=begin{pmatrix}
    {1}&{-1}
    {1}&{1}
    end{pmatrix}={sqrt{2}}
    begin{pmatrix}
    {cosleft(frac{1}{4}piright)}&{cosleft(frac{3}{4}piright)}
    {sinleft(frac{1}{4}piright)}&{sinleft(frac{3}{4}piright)}
    end{pmatrix}
    }
    ]

    The reason being, as we transfer on by including animations, this illustration will come in useful. The scalar multiplication by the sq. root of two represents how a lot our vectors get stretched, whereas the weather of the matrix are rewritten in trigonometric notation to depict the rotation within the unit circle.

    Let’s animate

    Causes so as to add animations might embody cleaner plots as we will do away with the ghost vectors and create a extra partaking expertise for displays. So as to improve our plot with animations we will keep within the matplotlib ecosystem by using the FuncAnimation() operate from matplotlib.animation. The operate takes the next arguments:

    • a matplotlib.determine.Determine object
    • an replace operate
    • the variety of frames

    For every body the replace operate will get invoked producing an up to date model of the preliminary quiver plot. For extra particulars test the official documentation from matplotlib.

    With this data in thoughts our activity is to outline the logic to implement within the replace operate. Let’s begin easy with solely three frames and our base vectors. On body 0 we’re within the preliminary state. Whereas on the final body (body 2) we have to arrive on the restated matrix M. Due to this fact we’d anticipate to be half means there on body 1. As a result of the arguments of (cos) and (sin) in M present the radians (i.e. how far we now have traveled on the unit circle), we will divide them by two so as to get our desired rotation. (The second vector will get a destructive (cos) , as a result of we at the moment are within the second quadrant). Equally we have to account for the stretch, represented by the scalar issue. We do that by computing the change in magnitude, which is (sqrt{2}-1), and including half of that change to the preliminary scaling.

    [
    {scriptsize
    begin{aligned}
    text{Frame 0:} quad &
    begin{pmatrix}
    cos(0) & cosleft(frac{pi}{2}right)
    sin(0) & sinleft(frac{pi}{2}right)
    end{pmatrix}
    [1em]
    textual content{Body 1:} quad &
    s cdot start{pmatrix}
    cosleft(frac{1}{2} cdot frac{pi}{4}proper) & -cosleft(frac{1}{2} cdot frac{3pi}{4}proper)
    sinleft(frac{1}{2} cdot frac{pi}{4}proper) & sinleft(frac{1}{2} cdot frac{3pi}{4}proper)
    finish{pmatrix}, quad textual content{with } s = 1 + frac{sqrt{2} – 1}{2}
    [1em]
    textual content{Body 2:} quad &
    sqrt{2} cdot start{pmatrix}
    cosleft(frac{pi}{4}proper) & cosleft(frac{3pi}{4}proper)
    sinleft(frac{pi}{4}proper) & sinleft(frac{3pi}{4}proper)
    finish{pmatrix}
    finish{aligned}
    }
    ]

    The matrices describe the place the 2 base vectors land on every body
    GIF by Writer

    One Caveat to the reason above: It serves the aim to offer instinct to the implementation thought and holds true for the bottom vectors. Nonetheless the precise implementation accommodates some extra steps, e.g. some transformations with (arctan) to get the specified habits for all vectors within the two-dimensional house.

    So let’s examine the principle components of the implementation. The total code will be discovered on my github.

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib import animation
    from matplotlib import cm
    
    class AnimationPlotter:
    [...]
    def animate(self, filename='output/mat_transform.gif'):
            self.initialize_plot()
            anim = animation.FuncAnimation(
                self.fig,
                self.update_quiver,
                frames=self.frames + 1,
                init_func=self.init_quiver,
                blit=True,
            )
            anim.save(filename, author='ffmpeg', fps=self.frames/2)
            plt.shut()
       
    if __name__ == "__main__":
        matrix = np.sqrt(2) * np.array([
            [np.cos(np.pi / 4), np.cos(3 * np.pi / 4)],
            [np.sin(np.pi / 4), np.sin(3 * np.pi / 4)]
           
        ])
        vector = np.array([1.5, -0.5]).reshape(2, 1)
        transformer = Transformer(matrix)
        animation_plotter = AnimationPlotter(transformer, vector)
        animation_plotter.animate()

    The animate() technique belongs to a customized class, which is named AnimationPlotter. It does what we already discovered with the inputs as supplied above. The second class on the scene is a customized class Transformer, which takes care of computing the linear transformations and intermediate vectors for every body. The primary logic lies throughout the AnimationPlotter.update_quiver() and Transformer.get_intermediate_vectors() strategies, and appears as follows.

    class AnimationPlotter:
        [...]
        def update_quiver(self, body: int):
            incremented_vectors = self.transformer.get_intermediate_vectors(
                body, self.frames
            )
            u = incremented_vectors[0]
            v = incremented_vectors[1]
            self.quiver_base.set_UVC(u, v)
            return self.quiver_base,
    
    class Transformer:
        [...]
        def get_intermediate_vectors(self, body: int, total_frames: int) -> np.ndarray:
             change_in_direction = self.transformed_directions - self.start_directions
             change_in_direction = np.arctan2(np.sin(change_in_direction), np.cos(change_in_direction))
             increment_direction = self.start_directions + change_in_direction * body / total_frames
             increment_magnitude = self.start_magnitudes + (self.transformed_magnitudes - self.start_magnitudes) * body / total_frames
             incremented_vectors = np.vstack([np.cos(increment_direction), np.sin(increment_direction)]) @ np.diag(increment_magnitude)
             return incremented_vectors

    What occurs right here is that for every body the intermediate vectors get computed. That is accomplished by taking the distinction between the tip and begin instructions (which symbolize vector angles). The change in route/angle is then normalized to the vary ([-pi, pi]) and added to the preliminary route by a ratio. The ratio is set by the present and whole frames. The magnitude is set as already described. Lastly, the incremented vector will get computed based mostly on the route and magnitude and that is what we see at every body within the animation. Rising the frames to say 30 or 60 makes the animation clean.

    Animating Singular Worth Decomposition (SVD)

    Lastly I need to showcase how the introductory animation was created. It exhibits how 4 vectors (every for each quadrant) get reworked consecutively thrice. Certainly, the three transformations utilized correspond to our in the meantime well-known transformation matrix M from above, however decomposed through Singular Worth Decomposition (SVD). You possibly can achieve or refresh your information about SVD in this nice and intuitive tds article. Or have a look here should you want a extra math-focused learn. Nonetheless, with numpy.linalg.svd() it’s simple to compute the SVD of our matrix M. Doing so ends in the next decomposition:

    [
    {scriptsize
    begin{align}
    A vec{v} &= USigma V^Tvec{v} [1em]
    sqrt{2} cdot start{pmatrix}
    cosleft(frac{pi}{4}proper) & cosleft(frac{3pi}{4}proper)
    sinleft(frac{pi}{4}proper) & sinleft(frac{3pi}{4}proper)
    finish{pmatrix} vec{v} &=
    start{pmatrix}
    cosleft(frac{3pi}{4}proper) & cosleft(frac{3pi}{4}proper)
    sinleft(frac{-pi}{4}proper) & sinleft(frac{pi}{4}proper)
    finish{pmatrix}
    start{pmatrix}
    sqrt{2} & 0
    0 & sqrt{2}
    finish{pmatrix}
    start{pmatrix}
    -1 & 0
    0 & 1
    finish{pmatrix} vec{v}
    finish{align}
    }
    ]

    Observe how the stretching by the sq. root will get distilled by the center matrix. The next animation exhibits how this appears to be like in motion (or movement) for v = (1.5, -0.5).

    Transformation with Decomposition (left) and Transformation with matrix M (proper) GIF by Writer

    In the long run the purple vector (vec{v}) arrives at its decided place in each circumstances.

    Conclusion

    To wrap it up, we will use quiver() to show vectors in 2D house and, with the assistance of matplotlib.animation.FuncAnimation(), add interesting animations on prime. This ends in clear visualizations of linear transformations that you should utilize, as an illustration, to exhibit the underlying mechanics of your machine studying algorithms. Be at liberty to fork my repository and implement your personal visualizations. I hope you loved the learn!



    Source link

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Editor Times Featured
    • Website

    Related Posts

    Enhancing Customer Support with AI Text-to-Speech Tools

    June 19, 2025

    A Multi-Agent SQL Assistant You Can Trust with Human-in-Loop Checkpoint & LLM Cost Control

    June 19, 2025

    Can We Use Chess to Predict Soccer?

    June 18, 2025

    Agents, APIs, and the Next Layer of the Internet

    June 18, 2025

    I Won $10,000 in a Machine Learning Competition — Here’s My Complete Strategy

    June 18, 2025

    Apply Sphinx’s Functionality to Create Documentation for Your Next Data Science Project

    June 18, 2025
    Leave A Reply Cancel Reply

    Editors Picks

    Enhancing Customer Support with AI Text-to-Speech Tools

    June 19, 2025

    Kamingo 5-lb plug-and-play electric bike drive system

    June 19, 2025

    German FinTech startup NaroIQ raises €5.8 million to establish European fund infrastructure

    June 19, 2025

    Amazon Rebuilt Alexa Using a ‘Staggering’ Amount of AI Tools

    June 19, 2025
    Categories
    • Founders
    • Startups
    • Technology
    • Profiles
    • Entrepreneurs
    • Leaders
    • Students
    • VC Funds
    About Us
    About Us

    Welcome to Times Featured, an AI-driven entrepreneurship growth engine that is transforming the future of work, bridging the digital divide and encouraging younger community inclusion in the 4th Industrial Revolution, and nurturing new market leaders.

    Empowering the growth of profiles, leaders, entrepreneurs businesses, and startups on international landscape.

    Asia-Middle East-Europe-North America-Australia-Africa

    Facebook LinkedIn WhatsApp
    Featured Picks

    Ongoing attacks on Ivanti VPNs install a ton of sneaky, well-written malware

    January 16, 2025

    iOS and Android juice jacking defenses have been trivial to bypass for years

    April 28, 2025

    Data Scientist: From School to Work, Part I

    February 19, 2025
    Categories
    • Founders
    • Startups
    • Technology
    • Profiles
    • Entrepreneurs
    • Leaders
    • Students
    • VC Funds
    Copyright © 2024 Timesfeatured.com IP Limited. All Rights.
    • Privacy Policy
    • Disclaimer
    • Terms and Conditions
    • About us
    • Contact us

    Type above and press Enter to search. Press Esc to cancel.