function plotforclass( varargin )
%PLOTFORCLASS  Custom plotter for ECE3500
%   PLOTFORCLASS(varargin) Custom MATLAB function to plot signals with
%   specific sizes and options. All inputs are formatted such that one
%   parameter indicates the input variable and the second parameter
%   indicates the parameter. For example, plotforclass('fnc', @stem).
%   Note that this function is still in development.
%
%   INPUT PARAMETERS [all optional]:
%     fnc: The function to use for plotting (typically @plot or @stem)
%       x: The x-values of plotted values
%       y: The y-values of plotted values
%       z: The z-values of plotted values (not active)
%    xlbl: The x-axis label 
%    ylbl: The y-axis label
%    zlbl: The z-axis label (not active)
%    axis: The length-4 vector [xmin xmax ymin ymax]
%   figno: The figure number for the given plot
%    ynum: If true, numbers y-values are displayed over points
%   oaxes: If true (and oaxes is found), plots are displayed using the
%          oaxes function from the Mathworks File Exchange
%  pltopt: Cell of plot options for given plot function (fnc)
% saveimg: If true (and export_fig is found), saves figure using the 
%          export_fig function from the Mathworks File Exchange
%  flname: String of the output file for saving. 
%
%   see also: plot, stem
%


    % SET DEFUALT OPTIONAL ARGUMENTS
    opt.fnc          = @plot;
    opt.x            = [];
    opt.y            = randn(length(opt.x));
    opt.z            = [];
    opt.xlbl         = 't';
    opt.ylbl         = 'x(t)'; 
    opt.zlbl         = '?';
    opt.axis         = [];
    opt.figno        = 0;
    opt.ynum         = false;
    opt.oaxes        = true;
    opt.pltopt       = {'linewidth', 1.5};
    opt.saveimg      = true;
    opt.marker       = {};
    opt.fontsize     = 12;
    opt.markersize   = 3;
    opt.LineStyleOrder = '-';
    opt.flname       = 'my_image.png';
    opt.captionFile  = 'caption.html';
    opt.figwidth     = 3.00;
    opt.hidexticks   = false;
    opt.hideyticks   = false;
    opt.xTickPrefix  = '';
    opt.xTickSuffix  = '';
    opt.yTickPrefix  = '';
    opt.yTickSuffix  = '';
    opt.pzplot       = false;
    opt.pzzplot      = false;
    opt.yTickP       = '';
    opt.roc          = 0;
    opt.xTick        = [];
    opt.yTick        = [];
    opt.figheight    = 2;
    opt.gifIt        = false;
    opt.caption      = [];
    opt.myColorMap   = [ 79 129 189; ... %Blue
                         192  80  70; ... %Red
                         155 187  89; ... %Green
                         128 100 162; ... %Purple
                         247 150  70; ... %Orange
                         75  172 192; ... %Cyan
                       ]/255;
    opt.xticknum     = 0;
    opt.yticknum     = 0;
    opt.gifDelay     = 2;
    opt.textloc      = [];
    opt.textcont     = '';    
    
    % PARSE ARGUMENTS 
    if ~isempty(varargin), [opt, varargin] = parseArgs(opt, varargin{:}); end 
    if strcmp(func2str(opt.fnc),'plot'), opt.ynum = false; end
    if strcmp(func2str(opt.fnc),'stem') && any(strcmp(varargin, 'ynum')), opt.ynum = true; end
    if strcmp(func2str(opt.fnc),'stem') && any(strcmp(varargin, 'hideyticks')), opt.hideyticks = true; end
    if ~iscell(opt.marker), opt.marker = {opt.marker}; end

    
    % --------------------------------------------------------------------
    % PRE-PLOTTING FIGURE SETTINGS ---------------------------------------
    % --------------------------------------------------------------------
    
    % CREATE FIGURE
    if ~opt.figno,
        f = figure();
    else
        % OPEN AND CLOSE AND REOPEN FIGURE TO REMOVE PRIOR CHANGES
        figure(opt.figno); close(opt.figno); figure(opt.figno);
    end
    
    % SET SIZE, LOCATION, AND PROPERTIES OF THE FIGURE
    set(gcf, 'Units', 'inches', 'Position', [1 1 opt.figwidth opt.figheight], 'color', [1 1 1]);
    set(gcf, 'DefaultAxesColorOrder', opt.myColorMap)
    if opt.gifIt, set(gcf, 'DefaultAxesColorOrder', opt.myColorMap(1,:)); end
    
    
    for aa = 1:size(opt.y, 3)
        for bb = 1:size(opt.y, 4)
    
    g(aa,bb) = subplot(size(opt.y, 3),size(opt.y, 4),size(opt.y, 4)*(aa-1)+bb);   % subplot
    set(gca, 'units', 'inches')
    pos = get(gca,'position');                          % Read position [x y z]
    set(gca,'position',pos-[0.2 -0.075 -0.2 0.2])            % Move label to right
    
    if ~opt.pzplot && ~opt.pzzplot
        if all(opt.y(:,:,aa,bb) == 0), h{aa,bb} = plot(opt.y(:,:,aa,bb)+nan); set(gca, 'Visible', 'off'); continue; end
    end
    
    % --------------------------------------------------------------------
    % PLOT DATA -------------------------------------------------------
    % --------------------------------------------------------------------
    
    % DETERMINE MINIMUM AND MAXIMUM OF THE DATA
    maxy = max(opt.y(:)); miny = min(opt.y(:));
    maxx = max(opt.x(:)); minx = min(opt.x(:));
    if ~isempty(opt.axis)
        minx = opt.axis(1); maxx = opt.axis(2); 
        miny = opt.axis(3); maxy = opt.axis(4);
    end
    if miny == maxy, miny = 0; end
    
    
    % DETERMINE RULES IF CREATE ROC CURVES
    h00 = [];
    if opt.roc
        if opt.pzplot
            sigmamin = max(opt.x(opt.roc == 1,1)); % Lower bound
            sigmamax = min(opt.x(opt.roc == -1,1)); % Upper bound
            if isempty(sigmamin), sigmamin = min(opt.x(:,1))-50; end
            if isempty(sigmamax), sigmamax = max(opt.x(:,1))+50; end
            if sigmamin <= sigmamax
                hold on;
                h00(1) = area([sigmamin sigmamax], [miny*2 miny*2], 0, 'facecolor', .8*[1 1 1], 'LineStyle','none');
                h00(2) = area([sigmamin sigmamax], [maxy*2 maxy*2], 0, 'facecolor', .8*[1 1 1], 'LineStyle','none');
            end
        end
        if opt.pzzplot
            sigmamin = max(sqrt(sum([opt.x(opt.roc == 1,1) opt.y(opt.roc == 1,1)].^2,2))); % Lower bound
            sigmamax = min(sqrt(sum([opt.x(opt.roc == -1,1) opt.y(opt.roc == -1,1)].^2,2))); % Lower bound
            if isempty([opt.x(opt.roc == 1,1) opt.y(opt.roc == 1,1)]), sigmamin = 0; end
            if isempty([opt.x(opt.roc == -1,1) opt.y(opt.roc == -1,1)]), sigmamax = max(opt.x(:,1))+5; end
            if sigmamin <= sigmamax
                hold on;
                h00(1) = makewedge(sigmamin, sigmamax, 0, 360+eps, .8*[1 1 1]);
            end
        end
    else
        h00 = [];
    end


    % PLOT DATA
    if isempty(opt.x)
        h{aa,bb} = opt.fnc(opt.y(:,:,aa,bb),        opt.pltopt{:},'MarkerFaceColor','auto', 'MarkerSize', opt.markersize);
        set(gca, 'LineStyleOrder', opt.LineStyleOrder)
    else
        h{aa,bb} = opt.fnc(opt.x, opt.y(:,:,aa,bb), opt.pltopt{:},'MarkerFaceColor','auto', 'MarkerSize', opt.markersize);
        set(gca, 'LineStyleOrder', opt.LineStyleOrder)
    end
    hold off;
    
    % OPTIONAL SETTING
    if ~isempty(opt.marker), set(h{aa,bb}, {'marker'}, opt.marker); end
    if opt.pzplot || opt.pzzplot
       set(h{aa,bb}(1), 'LineStyle', 'none', 'Marker', 'x', 'MarkerFaceColor','none'); 
       if length(h{aa,bb})>1, set(h{aa,bb}(2), 'LineStyle', 'none', 'Marker', 'o', 'MarkerFaceColor','none'); end
       axis equal;
    end

    % ADD NUMERS FOR EACH POINT
    rangey = maxy - miny;
    rangex = maxx - minx;
    if opt.ynum
        if length(opt.y(:)) ~= size(opt.y,2), NN = size(opt.y,2); else NN = 1; opt.y = opt.y(:); end
        for nn = 1:NN
            for ii = 1:length(opt.x)
                text(opt.x(ii), opt.y(ii,nn,aa,bb)+sign(opt.y(ii,nn,aa,bb)+eps)*rangey*0.275, ['  ' opt.yTickPrefix num2str(round(opt.y(ii,nn)*100)/100) opt.yTickSuffix], 'HorizontalAlign', 'Center', 'FontName', 'Calibri'); 
            end
        end
    end
    
    % DISPLAY RESULTS
    set(gca, ...
      'Box'         , 'off'             , ...
      'TickDir'     , 'out'             , ...
      'TickLength'  , [.01 .01]         , ...
      'XMinorTick'  , 'off'             , ...
      'YGrid'       , 'off'             , ...
      'XGrid'       , 'off'             , ...
      'Color'       , [.94 .94 .94]     , ...
      'YColor'      , [1  1  1]*.15     , ...
      'XColor'      , [1  1  1]*.15     , ...
      'FontName'    , 'Calibri' , ...
      'FontSize'    , opt.fontsize        ...
    );
    
  
    % --------------------------------------------------------------------
    % SET COLORS AND PLOT ORDER 
    % --------------------------------------------------------------------
    
    % USE OAXES IF SELECTED AND POSSIBLE
    xaxismin = minx-rangex/1000;
    xaxismax = maxx+rangex/1000;
    xaxisrange = xaxismax - xaxismin;
    
    yaxismin = miny-rangey*.125-rangey*0.25*opt.ynum;
    yaxismax = maxy+rangey*0.125+rangey*0.25*opt.ynum;
    yaxisrange = yaxismax - yaxismin;
    
    axis([xaxismin xaxismax yaxismin yaxismax])
    if opt.pzplot || opt.pzzplot, axis([minx-rangex*.125 maxx+rangex*.125 miny-rangey*.125 maxy+rangey*0.125]); maxx = maxx+rangex*.2; end
    
    
    % --------------------------------------------------------------------
    % DRAW AXES
    % --------------------------------------------------------------------
    
    if ~isempty(opt.xTick), set(gca, 'xtick', opt.xTick); end
    if ~isempty(opt.yTick), set(gca, 'ytick', opt.yTick); end
    
    ytick = get(gca, 'ytick'); %ytick = setdiff(ytick, [min(ytick) max(ytick)]);
    if ~opt.pzplot && ~opt.pzzplot
        hold on;
        p2 = plot([minx maxx], ones(2,1)*ytick(ytick ~= 0), '-w', 'linewidth', 1, 'linestyle', '-'); hold off;
        %set(p2, 'HandleVisibility', 'off')
    else 
        p2 = [];
        circle(0,0,1);
    end
    children = get(gca, 'children');
    middlechildren = setdiff(children, [h{aa,bb}(:); h00(:); p2(:)]);
    set(gca,'children',[h{aa,bb}(:); middlechildren(:); h00(:); p2(:)])
    
    uistack(h{aa,bb}, 'top')   
    set(findall(gcf,'type','text'),'FontName','Calibri')
    set(findall(gcf,'type','text'),'FontSize',opt.fontsize)
    
    
    % --------------------------------------------------------------------
    % SET AXIS
    % --------------------------------------------------------------------
    
    % MOVE AXIS TO THE ORIGIN
    set(gca, 'XAxisLocation', 'origin');
    set(gca, 'YAxisLocation', 'origin');
    
    % GET TICKS  
    if opt.hidexticks
        myxticklbl = [];
        myxtick = [];
    else
        myxticklbl = get(gca, 'XTickLabel');
        myxtick = get(gca, 'XTick');
        myxticklbl = arrayfun(@(x) num2str(round(x*10)/10), myxtick, 'UniformOutput', false).';
        myxticklbl = myxticklbl(myxtick ~= 0);
        myxtick = myxtick(myxtick ~= 0);
    end
    if opt.hideyticks
        myyticklbl = [];
        myytick = [];
    else
        myyticklbl = get(gca, 'YTickLabel');
        myytick = get(gca, 'YTick');
        myytick = myytick(~cellfun(@isempty, myyticklbl));
        myyticklbl = arrayfun(@(x) num2str(round(x*10)/10), myytick, 'UniformOutput', false).';
        myyticklbl = myyticklbl(~cellfun(@isempty, myyticklbl));
    end
    
    
    set(gca, 'XTick', myxtick);
    set(gca, 'YTick', myytick);
    %set(gca,'xticklabel',num2str(tix,'%.1f'))
    %set(gca,'yticklabel',num2str(tix,'%.1f'))
    myxlabel0 = [repmat({opt.xTickPrefix}, size(myxticklbl,1), 1) myxticklbl repmat({opt.xTickSuffix}, size(myxticklbl,1), 1)];
    myxlabel  = arrayfun(@(ii) [myxlabel0{ii,1}  myxlabel0{ii,2} myxlabel0{ii,3}], 1:size(myxlabel0,1), 'uniformoutput', false).';
    myylabel0 = [repmat({opt.yTickPrefix}, size(myyticklbl,1), 1) myyticklbl repmat({opt.yTickSuffix}, size(myyticklbl,1), 1)];
    myylabel  = arrayfun(@(ii) [myylabel0{ii,1}  myylabel0{ii,2} myylabel0{ii,3}], 1:size(myylabel0,1), 'uniformoutput', false).';
    set(gca, 'XTickLabel', myxlabel);
    set(gca, 'YTickLabel', myylabel);
    
    
    
    % PUT AXIS ON TOP
    set(gca, 'Layer', 'top');
    
    % CREATE LABEL
    if iscell(opt.xlbl)
        xlabel([opt.xlbl{1,aa,bb}])
    else
        xlabel([opt.xlbl])
    end
    if iscell(opt.ylbl)
        ylabel([opt.ylbl{1,aa,bb}])
    else
        ylabel([opt.ylbl])
    end
    
    xlabh = get(gca,'XLabel');
    ylabh = get(gca,'YLabel');
    xlabhpos = get(xlabh,'Position');
    ylabhpos = get(ylabh,'Position');
    set(xlabh,'Position', [xaxismax+xaxisrange*1/20 -yaxisrange/7.5 xlabhpos(3)]);
    set(ylabh,'Position', [xaxisrange/20 yaxismax+yaxisrange*1/15 ylabhpos(3)]);
    set(ylabh,'Rotation', 0);
    set(ylabh,'VerticalAlignment', 'baseline')
    set(ylabh,'HorizontalAlignment', 'left')
    set(xlabh,'HorizontalAlignment', 'left')
    
    
    if ~isempty(opt.textloc)
        if iscell(opt.textloc)
            for mm = 1:length(opt.textloc)
                text(opt.textloc{mm}(1), opt.textloc{mm}(2), opt.textcont{mm}, 'FontName','Calibri', 'FontSize',opt.fontsize);
            end
        else
            text(opt.textloc(1), opt.textloc(2), opt.textcont,'FontName','Calibri','FontSize',opt.fontsize);
        end
    end
    
    %maxy+rangey*0.1
    drawnow();
    
    
        end
    end

    % --------------------------------------------------------------------
    % SAVE PLOT 
    % --------------------------------------------------------------------
    if opt.saveimg && exist('export_fig.m', 'file') && ~opt.gifIt
        export_fig(opt.flname, '-m5', '-nocrop')
    end
    
    
    % MAKE ANIMATED GIF
    if opt.gifIt
    
        for ii = 2:size(opt.y,2)
            for aa = 1:size(opt.y,3)
                for bb = 1:size(opt.y,4)
                    set(h{aa,bb}(ii), 'Visible', 'off');
                end
            end
        end
        gif([opt.flname '.gif'],'frame',gcf,'DelayTime',opt.gifDelay,'nodither') 
        
        for ii = 2:size(opt.y,2)
            for aa = 1:size(opt.y,3)
                for bb = 1:size(opt.y,4)
                    if size(opt.xlbl,1) > 1, axes(g(aa,bb)); set(get(gca,'XLabel'),'String',[opt.xlbl{ii,aa,bb}]); end
                    if size(opt.ylbl,1) > 1, axes(g(aa,bb)); set(get(gca,'YLabel'),'String',[opt.ylbl{ii,aa,bb}]); end
                    set(h{aa,bb}(ii-1), 'Visible', 'off'); 
                    set(h{aa,bb}(ii), 'Visible', 'on');     
                end
            end
            gif;
        end
    end
    
    % SAVE CAPTION
    if ~isempty(opt.caption)
        fid = fopen([opt.captionFile],'wt');
        fprintf(fid, '%s', opt.caption);
        fclose(fid);
    end
    
    
end


%------------------ 
function hOut = makewedge(rho1, rho2, theta1, theta2, color) 
%MAKEWEDGE Plot a wedge. 
% MAKEWEDGE(rho1, rho2, theta1, theta2, color) plots a polar 
% wedge bounded by the given inputs. The angles are in degrees. 
%
% CODE ORGINATED FROM: 
% http://compgroups.net/comp.soft-sys.matlab/patches-and-polar-plots/798361
% 
% h = MAKEWEDGE(...) returns the patch handle. 

ang = linspace(theta1/180*pi, theta2/180*pi); 
[arc1.x, arc1.y] = pol2cart(ang, rho1); 
[arc2.x, arc2.y] = pol2cart(ang, rho2); 
x = [arc1.x arc2.x(end:-1:1)]; 
y = [arc1.y arc2.y(end:-1:1)]; 
newplot; 
h = patch(x, y, color); 

if ~ishold 
    axis equal tight; 
end
if nargout > 0, 
    hOut = h; 
end
%------------------

end


function gif(varargin)
% gif is the simplest way to make gifs. Simply call
% 
%   gif('myfile.gif') 
% 
% to write the first frame, and then call 
% 
%   gif
% 
% to write each subsequent frame. That's it. 
% 
%% Syntax
% 
%  gif('filename.gif') 
%  gif(...,'DelayTime',DelayTimeValue,...) 
%  gif(...,'LoopCount',LoopCountValue,...) 
%  gif(...,'frame',handle,...) 
%  gif(...,'nodither') 
%  gif 
%  gif('clear') 
% 
%% Description 
% 
% gif('filename.gif') writes the first frame of a new gif file by the name filename.gif. 
% 
% gif(...,'DelayTime',DelayTimeValue,...) specifies a the delay time in seconds between
% frames. Default delay time is 1/15. 
% 
% gif(...,'LoopCount',LoopCountValue,...) specifies the number of times the gif animation 
% will play. Default loop count is Inf. 
% 
% gif(...,'frame',handle,...) uses the frame of the given figure or set of axes. The default 
% frame handle is gca, meaning the current axes. To turn an entire figure window into a gif, 
% use 'frame',gcf to use the current figure. 
% 
% gif(...,'nodither') maps each color in the original image to the closest color in the new 
% without dithering. Dithering is performed by default to achieve better color resolution, 
% albeit at the expense of spatial resolution.
% 
% gif adds a frame to the current gif file. 
% 
% gif('clear') clears the persistent variables associated with the most recent gif. 
% 
%% Example 
% 
%    % Some sample data: 
%    t = sin(linspace(0,2*pi,30)); 
%    [X,Y,Z] = peaks(500); 
% 
%    % Plot the first frame: 
%    h = surf(X,Y,Z*t(1)); 
%    shading interp
%    axis([-3 3 -3 3 -9 9])
% 
%    % Create a new gif file and write the first frame: 
%    gif('myfile.gif') % Or specify options like this: gif('myfile.gif','DelayTime',0.2,'LoopCount',5,'frame',gcf)
% 
%    % Loop through every other frame. 
%    for k = 2:length(t) 
%       set(h,'Zdata',Z*t(k))
%       gif
%    end
% 
%    % View the gif in Matlab if you'd like: 
%    web('myfile.gif') 
% 
%% Author Information 
% This function was written by Chad A. Greene of the University of Texas 
% Institute for Geophysics (UTIG), June 2017. 
% 
% See also: imwrite, getframe, and rgb2ind. 

% Define persistent variables: 
persistent gif_filename firstframe DelayTime DitherOption LoopCount frame

%% Parse Inputs

if nargin>0 
   
   % The user may want to clear things and start over: 
   if any(strcmpi(varargin,'clear'))
            
      % Clear persistent variables associated with this function: 
      clear gif_filename firstframe DelayTime DitherOption LoopCount frame
   end
   
   % If the first input ends in .gif, assume this is the first frame:
   if strcmpi(varargin{1}(end-3:end),'.gif')
      
      % This is what the user wants to call the new .gif file: 
      gif_filename = varargin{1}; 
      
      % Check for an existing .gif file by the same name: 
      if exist(gif_filename,'file')==2
         
         % Ask the user if (s)he wants to overwrite the existing file: 
         %choice = questdlg(['The file  ',gif_filename,' already exists. Overwrite it?'], ...
         %   'The file already exists.','Overwrite','Cancel','Cancel');
         choice = 'Overwrite';
         
         
         % Overwriting basically means deleting and starting from scratch: 
         if strcmp(choice,'Overwrite')
            delete(gif_filename) 
         else 
            clear gif_filename firstframe DelayTime DitherOption LoopCount frame
            error('The giffing has been canceled.') 
         end
         
      end
      
      firstframe = true; 
      
      % Set defaults: 
      DelayTime = 1/15; 
      DitherOption = 'dither'; 
      LoopCount = Inf; 
      frame = gca; 
   end
   
   tmp = strcmpi(varargin,'DelayTime'); 
   if any(tmp) 
      DelayTime = varargin{find(tmp)+1}; 
      assert(isscalar(DelayTime)==1,'Error: DelayTime must be a scalar value.') 
   end
   
   if any(strcmpi(varargin,'nodither'))
      DitherOption = 'nodither'; 
   end
   
   tmp = strcmpi(varargin,'LoopCount'); 
   if any(tmp) 
      LoopCount = varargin{find(tmp)+1}; 
      assert(isscalar(LoopCount)==1,'Error: LoopCount must be a scalar value.') 
   end
   
   tmp = strcmpi(varargin,'frame'); 
   if any(tmp) 
      frame = varargin{find(tmp)+1}; 
      assert(ishandle(frame)==1,'Error: frame must be a figure handle or axis handle.') 
   end
   
else
   assert(isempty(gif_filename)==0,'Error: The first call of the gif function requires a filename ending in .gif.') 
end

%% Perform work: 

% Get frame: 
f = getframe(frame); 

% Convert the frame to a colormap and corresponding indices: 
[imind,cmap] = rgb2ind(f.cdata,256,DitherOption);    

% Write the file:     
if firstframe
   imwrite(imind,cmap,gif_filename,'gif','LoopCount',LoopCount,'DelayTime',DelayTime)
   firstframe = false;
else
   imwrite(imind,cmap,gif_filename,'gif','WriteMode','append','DelayTime',DelayTime)
end

end


function circle(x,y,r)
    %x and y are the coordinates of the center of the circle
    %r is the radius of the circle
    %0.01 is the angle step, bigger values will draw the circle faster but
    %you might notice imperfections (not very smooth)
    ang=0:0.01:2*pi; 
    xp=r*cos(ang);
    yp=r*sin(ang);
    hold on;
    plot(x+xp,y+yp, '--', 'linewidth', 1, 'color', [1 1 1]*.5);
    hold off;
end
