function svd_gui
    
    % Choose image file name
    image_name = 'bird.jpg';                       
    
    % Choose image density
    image_density = .3;
    
    % Load image as grayscale matrix 'A'
    image = imread(image_name);
    image = imresize(image, image_density);
    A = im2double(rgb2gray(image));    
    % Get matrix size (height:I, width:J)
    I = size(A, 1);
    J = size(A, 2);
        
    % Get max possible singular values
    N = min(I,J);
    
    % Set current singular values = max possible sv's
    n = N;
    
    % Define 'velocity' variable for updating n
    n_vel = 0;
    
    % Run singular value decomposition
    [U,S,V] = svd(A);
    % Define figure
    fig = figure(...
        'menubar', 'none', ...
        'numbertitle', 'off', ...
        'name', 'press keyboard up or down', ...
        'color', [.2,.2,.2], ...
        'keypressfcn', @key_down, ...
        'keyreleasefcn', @key_up, ...
        'closerequestfcn', @close_fcn);
   
    % Init axes ( u,s,v,a each get axes )
    colormap gray;
    u_ax = ax_make(fig, [.02,.7, .3, .24], [0,N], [0,I]);
    s_ax = ax_make(fig, [.34,.7, .3, .24], [0,N], [0,N]);
    v_ax = ax_make(fig, [.66,.7, .32,.24], [0,J], [0,N]);
    a_ax = ax_make(fig, [.02,.02,.96,.66], [0,J], [0,I]);
    % Label u,s,v,a axes
    
    text_box([.02,.93,.3,.07], 'U');
    text_box([.34,.93,.3,.07], 'S');
    text_box([.66,.93,.3,.07], 'V^{T}');
    
    text_box([.02,.57, .5,.1], sprintf('A[%d,%d] = U*S*V^{T}',I,J));  
    n_text_box = text_box([.02,.47, .5,.1], '');
    n_text_box.Color = [.8,.8,.5];
    
    % Init image textures ( each texture within image )
    
    u_img = imagesc(u_ax);
    s_img = imagesc(s_ax);
    v_img = imagesc(v_ax);
    a_img = imagesc(a_ax);
      
    % 'main' Loop
    program_on  = true;
    program_new = true;
       
    while program_on
         
        if n_vel ~= 0 || program_new
            
            % Update how many sv's to use
            n = n + n_vel;
            % If n < N, remove N-n small SV's
            if n < N + 1                                            
                u = U(:,1:n);                                           
                s = S(1:n,1:n);
                v = V(:,1:n);
                fig.Color = [.5,.5,.8];
            
            % It n > N, remove n-N big SV's
            else                                        
                u = U(:,n-N:N);
                s = S(n-N:N,n-N:N);
                v = V(:,n-N:N);
                fig.Color = [.8,.5,.5];
            end
        
            % Update Texture data
            u_img.CData = u < 1e-4;
            s_img.CData = s < 1e-4;
            v_img.CData = v'< 1e-4;
            a_img.CData = u*s*v';
            
            n_text_box.String = sprintf('sv: %d/%d', N-abs(N-n),N);
        end
        
       % turn 'fresh' variable off
       if program_new == true && n_vel ~= 0
            fig.Name = 'svd gui';
            program_new = false;
       end
        
        % Refresh figure/axes
        drawnow;
    end
    
    % Delete figure if exited loop
    delete(gcf);
    
    % Functions 
    
    % Text box generator convenience fn
    function t = text_box(pos, text)
        t = annotation( 'textbox', ...
            'position', pos, ...
            'color', [1,1,1], ...
            'fontweight', 'bold', ...
            'edgecolor', 'none',...
            'string', text);
    end
    % Axes generator convenience fn
    function ax = ax_make(fig, pos, xlim, ylim)
        ax = axes( ...
            'parent', fig, ...
            'units', 'normalized', ...
            'xlim', xlim, 'ylim', ylim, ...
            'visible', 'off', ...
            'ydir', 'reverse', ...
            'position', pos);
    end
    
    % Keyboard up/down fn's
    function key_down(~,e)
        switch e.Key
            case 'downarrow', n_vel = -1;
            case 'uparrow',   n_vel =  1;
        end
    end
    function key_up(~,~)
        n_vel =  0;
    end
    % Close request ( runs when press 'x' to close figure)
    function close_fcn(~,~)
        program_on = false;
    end
end