Code covered by the BSD License

# TRIGDEMO

by

### Matt Fig (view profile)

Allows user to see how parameters affect plots of trigonometric functions.

### Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

trigdemo()
```function [] = trigdemo()
%TRIGDEMO Explore how parameters affect plots of trigonometric functions.
% The functions included are:  sine, cosine, tangent, and their reciprocals
% cosecant, secant, cotangent.
% The GUI allows the for manipulation of the parameters A,B,C,D in the
% general equation of the form:
%
%                        y = y(x) = A trig(Bx + C) + D
%
% The parameters are manipulated by means of slider bars.  The user can
% interactively see how changing these parameters changes the plot.  This
% is done dynamically by holding down the arrow on one end of a slider bar
% corresponding to the parameter of interest.  When using the sliders, the
% x and y limits of the axes do not change.  This allows the user to see
% how changing the parameter changes the plot.  Please read the usage notes
% below before use.
%
%
% Usage Notes:
%
% Each slider corresponds to the parameter shown on it's left.
% At the ends of each slider are editboxes for specifying the slider range.
% Clicking on the axes will cause a redraw which changes the y limits only.
% Editboxes are provided to allow the x range of the axes to be changed.
% The figure title shows the current function with symbolic parameters.
% The axes title shows the current function with numerical values.
%
%
% Author:  Matt Fig
% Contact:  popkenai@yahoo.com

%%%%%%%%%%%%%%%%%%%%% Start: build the GUI %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% S is a struct of the handles that the callbacks need.  It will be passed
% when a callback is invoked.  This avoids having to retrieve the handles
% through get(gcbf,'userdata') or using findobj or guihandles.
col = [0.925 0.914 0.847];  % A color for use in the GUI
hf = figure('un','pix','pos',[520 270 560 530],'menub','no','na',...
'trigdemo:   y = A sin(Bx + C) + D','numbert','of','resize',...
'of','color',col);  % The figure
S.ax = axes('un','pix','pos',[110 250 430 250]);
plot(0:.01:6.28,sin(0:.01:6.28),'r','linew',2)
xlim([0 6.28])
xlabel('x','fonts',14,'fontw','b'); % Label the x-axis.
lghtbl = [.9 .9 .92]; % A light blue color.
uicontrol(hf,'sty','fr','pos',[10 10 540 190],'backg',lghtbl); % Frame.
Gs = {'style','edit','units','pixels','position'}; % For the edits below.
S.edP(1) = uicontrol(hf,Gs{:},[40 140 50 20],'str','-1','tag','minA');
S.edP(2) = uicontrol(hf,Gs{:},[40 100 50 20],'str','-10','tag','minB');
S.edP(3) = uicontrol(hf,Gs{:},[40 60 50 20],'str','-20','tag','minC');
S.edP(4) = uicontrol(hf,Gs{:},[40 20 50 20],'str','-1','tag','minD');
S.edP(5) = uicontrol(hf,Gs{:},[490 140 50 20],'str','1','tag','maxA');
S.edP(6) = uicontrol(hf,Gs{:},[490 100 50 20],'str','10','tag','maxB');
S.edP(7) = uicontrol(hf,Gs{:},[490 60 50 20],'str','20','tag','maxC');
S.edP(8) = uicontrol(hf,Gs{:},[490 20 50 20],'str','1','tag','maxD');
S.edX(1) = uicontrol(hf,Gs{:},[110 205 50 20],'too','Min x-val to plot');
S.edX(2) = uicontrol(hf,Gs{:},[490 205 50 20],'too','Max x-val to plot');
Gs{2} = 'slider';  % For the sliders below.
S.sl(1) = uicontrol(hf,Gs{:},[100 140 380 20],'val',1,'min',-1,'max',1);
S.sl(2) = uicontrol(hf,Gs{:},[100 100 380 20],'val',1,'min',-10,'max',10);
S.sl(3) = uicontrol(hf,Gs{:},[100 60 380 20],'val',0,'min',-20,'max',20);
S.sl(4) = uicontrol(hf,Gs{:},[100 20 380 20],'val',0,'min',-1,'max',1);
Gs{2} = 'text'; % For the static text boxes below.
txt(1) = uicontrol(hf,Gs{:},[11 20 20 20],'str','D','fonts',12);
txt(2) = uicontrol(hf,Gs{:},[11 60 20 20],'str','C','fonts',12);
txt(3) = uicontrol(hf,Gs{:},[11 100 20 20],'str','B','fonts',12);
txt(4) = uicontrol(hf,Gs{:},[11 140 20 20],'str','A','fonts',12);
txt(5) = uicontrol(hf,Gs{:},[100 168 380 25],'fonts',15,'str',...
'Parameter Manipulation','fore',[.25 .6 .25]);
S.txtfun = uicontrol(hf,Gs{:},[110 500 430 30],'fonts',16,...
'str','1sin(1x + 0) + 0','backg',col); % Axes label.
S.bg = uibuttongroup('parent',hf,'un','pix','pos',[10 270 70 200 ],...
'title','Function','backg',[.94 .9 .9]);
uicontrol('sty','push','un','pix','pos',[10 500 20 20],'str','?','call',...
'help trigdemo','toolt','Click to print the help to screen.',...
'backg',[.9 .92 .9])% The little help button
rad(1) = uicontrol(S.bg,Gs{:},[5 160 40 20],'str','sin');
rad(2) = uicontrol(S.bg,Gs{:},[5 130 40 20],'str','cos');
rad(3) = uicontrol(S.bg,Gs{:},[5 100 40 20],'str','tan');
rad(4) = uicontrol(S.bg,Gs{:},[5 70 40 20],'str','csc');
rad(5) = uicontrol(S.bg,Gs{:},[5 40 40 20],'str','sec');
rad(6) = uicontrol(S.bg,Gs{:},[5 10 40 20],'str','cot');
% Set some final properties.
set(S.bg,'SelectionC',{@plotter,S}) % When a new radiobutton is selected.
set(rad(:),'backg',get(S.bg,'backg'));  % Make buttons blend with bg.
set(txt(:),'backg',lghtbl,'fontw','b'); % Same for the parameter label.
set(S.edX(:),'backg','w',{'str'},{'0','6.28'}','call',{@plotter,S});
set(S.sl(:),'backg',[0.97 0.97 0.97],'cal',{@plotter,S}); % callback
set(S.edP(:),'call',{@parmcall,S},'backg',[1 1 1]); % callback.
% Might need old value for error correction!  Store in component userdata.
set(S.edX(:),{'userd'},get(S.edX(:),'str')); % See ifs in plotter.
set(S.edP(:),{'userd'},get(S.edP(:),'str'));
% We want to get EZPLOT in memory without the user noticing because it
% takes a lot longer (noticeably) than PLOT to initialize.  If we had used
% EZPLOT above, instead of PLOT, the GUI would take about 5 times longer to
% appear ready.  To get EZPLOT in memory without the user noticing, we can
% do it now before the user has a chance to click on anything.  This way
% the transition to EZPLOT for the rest of the GUI's life will be smoother.
% This is NOT a necessary step, but it is nicer for the user.
drawnow; % Make the GUI appear to the user.
pause(.0001)% Make sure that the GUI is fully drawn.
ax2 = axes('vis','off'); % The user should not notice anything unusual.
ezplot(ax2,@cos);  % This gets EZPLOT in memory.
delete(ax2);  % Now get rid of the extra axes, EZPLOT is now in memory.
%%%%%%%%%%%%%%%%%%%%%%% End: build the GUI %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [] = plotter(h,evnt,S) %#ok mlint doesn't understand callbacks :(
% Callback for the sliders, axes, and radiobuttons.  Takes care of plotting
% and updating the labels and figure title.
str = get(get(S.bg,'selectedo'),'str');  % Which trig function?
v = get(S.sl(:),'val');  % The current values of A,B,C,D.
rng = str2double(get(S.edX(:),{'str','userd'})); % The X-range of plots.
set(gcbf,'na',['trigdemo:   y = A ',str,'(Bx + C) + D']); % Figure title.
sym = '++';  % to make the equation in axes title look good.
sym([v{3} v{4}]< 0) = '-'; % instead of having (5x + -3) for example.
set(S.txtfun,'str',...
sprintf('%.2g%s',v{1},[str,'('],v{2},['x ',sym(1),' '],...
abs(v{3}),[') ',sym(2),' '],abs(v{4})));% Label for the axes title.

if rng(1)>=rng(2) % User wanted to plot on, for example: x = [9,2]
set(S.edX(1),'str',num2str(rng(3))); %Put things back.
set(S.edX(2),'str',num2str(rng(4)));
return % No need to replot.
elseif ~isnan(rng) % User didn't enter an invalid string, like 'pi'
set(S.edX(1),'userd',num2str(rng(1))) % Now this is the old value
set(S.edX(2),'userd',num2str(rng(2)))
else % User did enter an invalid string.
set(S.edX(1),'str',num2str(rng(3))); %Put things back.
set(S.edX(2),'str',num2str(rng(4)));
return % No need to replot.
end

switch str  % Could use eval (we do have a string), but let's not...
case 'sin'
f = @(x) v{1}*sin(v{2}*x + v{3}) + v{4};
c = [1 0 0]; % Red for sine.
case 'cos'
f = @(x) v{1}*cos(v{2}*x + v{3}) + v{4};
c = [0 0 1]; % Blue for cosine.
case 'tan'
f = @(x) v{1}*tan(v{2}*x + v{3}) + v{4};
c = [0 0 0]; % Black for tangent.
case 'csc'
f = @(x) v{1}*csc(v{2}*x + v{3}) + v{4};
c = [.9 .4 .4]; % Grey-red for 1/sine.
case 'sec'
f = @(x) v{1}*sec(v{2}*x + v{3}) + v{4};
c = [.4 .4 .9]; % Grey-blue for 1/cosine.
case 'cot'
f = @(x) v{1}*cot(v{2}*x + v{3}) + v{4};
c = [.4 .4 .4]; % Grey for 1/tangent.
end

typ = get(h,'ty'); % Must get this before replot in case the line called.
ylm = get(S.ax,'ylim'); % In case a slider is the caller.
lh = ezplot(S.ax,f,rng(1),rng(2)); % Get handle to line.
set(lh,'color',c,'linew',2) % Give line the correct color.
xlabel('x','fonts',14,'fontw','b')  % Redo this guy.
set([S.ax,lh],'buttond',{@plotter,S}) % We have to do this every time!?

if strcmp(typ,'uicontrol') && strcmp(get(h,'sty'),'slider')
ylim(ylm); % Only for sliders, user needs to see how these affect curve.
end

function [] = parmcall(h,evnt,S) %#ok mlint doesn't understand callbacks :(
% Callback for the parameter editors, including, indirectly, the sliders.
t = get(h,'tag');  % Get 'min' or 'max', which is also a prop of slider!
val = str2double(get(h,{'str','userd'})); % New and old values in edit.
slidh = S.sl(double(t(4))-64); % The corresponding slider.
cvs = get(slidh,'val');  % The current value of the slider.

if strcmp(t(1:3),'min') % We are setting the minimum value for the slider.
if val(1)<=cvs % The user chose a new minimum < than slider val... ok
set(slidh,t(1:3),str2double(get(h,'str')));
set(h,'userd',num2str(val(1))); % Now this is the old value.
else % The user chose a new minimum > than slider val... not ok
set(h,'str',num2str(val(2))); % Put the old value back.
end
else % Setting the maximum value, the rest is analogous to the above.
if val(1)>=cvs
set(slidh,t(1:3),str2double(get(h,'str')));
set(h,'userd',num2str(val(1)));
else
set(h,'str',num2str(val(2)));
end
end```