Update plot based on two sliders

71 views (last 30 days)
Logan Perry
Logan Perry on 30 Dec 2017
Commented: Seth Meiselman on 15 Jan 2020
Hello, I am trying to create a figure that can investigate the effect of multiple parameters via sliders. I have found explanations on how to do this for a single parameter/slider, but none for multiple ones. Based on this answer I am trying to make a figure for y=mx+b where m and b each have sliders. I have one slider working at the moment (below and based on this question/answer ), but nothing I try works for the second slider. Any help would be appreciated.
function [] = slider_plot()
% Plot different plots according to slider location.
S.fh = figure('units','pixels',...
'position',[300 300 300 300],...
'menubar','none',...
'name','slider_plot',...
'numbertitle','off',...
'resize','off');
S.x = 0:.01:1; % For plotting.
S.ax = axes('unit','pix',...
'position',[20 80 260 210]);
S.LN = plot(S.x,S.x,'r');
%Slider for slope parameter
S.sl = uicontrol('style','slide',...
'unit','pix',...
'position',[20 10 260 30],...
'min',1,'max',10,'val',1,...
'sliderstep',[1/20 1/20],...
'callback',{@sl_call,S});
function [] = sl_call(varargin)
% Callback for the slider.
[h,S] = varargin{[1,3]}; % calling handle and data structure.
set(S.LN,'ydata',S.x.*get(h,'value'))
  1 Comment
Jan
Jan on 30 Dec 2017
Please post the failing code and explain "does not work" with details, e.g. the error message.

Sign in to comment.

Answers (3)

Jan
Jan on 30 Dec 2017
Edited: Jan on 30 Dec 2017
function [] = slider_plot()
S.fh = figure('units','pixels', 'position',[300 300 300 300],...
'menubar','none',...
'name','slider_plot',...
'numbertitle','off',...
'resize','off');
S.ax = axes('units', 'pixels', 'position',[30 90 260 200]);
S.x = 0:.01:1; % For plotting.
S.fcn = @(x, m, b) m * x + b;
S.m = 1;
S.b = 0;
S.LN = plot(S.x, S.x, 'r');
update(S);
% Slider for slope parameter:
S.mSlider = uicontrol('style','slider',...
'unit','pixels',... % "pix" is not smart, we are not in a hurry
'position',[20 10 260 20],...
'min',1,'max',10,'value', S.m,...
'sliderstep',[1/20 1/20],...
'callback', {@SliderCB, 'm'});
% 2nd Slider:
S.bSlider = uicontrol('style','slide',...
'unit','pixels', 'position',[20 50 260 20],...
'min',-10,'max',10,'value', S.b,...
'sliderstep',[1/20 1/20],...
'callback', {@SliderCB, 'b'});
guidata(S.fh, S); % Store S struct in the figure
end
function SliderCB(mSlider, EventData, Param)
% Callback for both sliders
S = guidata(mSlider); % Get S struct from the figure
S.(Param) = get(mSlider, 'Value'); % Either 'm' or 'b'
update(S);
guidata(mSlider, S); % Store modified S in figure
end
function update(S)
y = S.fcn(S.x, S.m, S.b); % @(x, m, b) m * x + b;
set(S.LN, 'YData', y);
end
It does not look smart to use many abbrevs like "unit", "pix" or "slide". It works, but is less clear than the complete names.
The values and handles are stored in the struct S, which is shared using guidata. The graphics are kept up to date inside update(). Bother sliders use the same callback by specifying the parameter to modify as 3rd input argument.

Image Analyst
Image Analyst on 30 Dec 2017
Assign slider_plot to the callback function for each slider. You might find this easier to do in GUIDE rather than building it all yourself with the complex, detailed commands. So much easier to create your slider on a dialog box editor like GUIDE.
  2 Comments
Andy Lam
Andy Lam on 2 Feb 2018
Hi there. I'm actually doing something similar and using GUIDE. I'm trying to use 2 sliders to change the 2 specific parameters on the 1 plot. The plotting is currently in a separate function and so I've been trying to assign the sliders (in their call back functions) as input arguments to the plot function. But this has been a failure so far. Is something like this possible or do I have to have the plot function in the call back function of each slider? The latter will only allow for changes to the single variable (controlled by the slider) with everything else equal. Thanks in advance!
Image Analyst
Image Analyst on 2 Feb 2018
As long as your function where you call plot() has access to the handles structure, you can get any control's properties. For example to get the slider1 setting:
sliderValue1 = handles.slider1.Value;

Sign in to comment.


Seth Meiselman
Seth Meiselman on 11 Jan 2018
Jan Simmon' response should be acceptable. I've expanded it here to make clearer the steps with a few more comments for others like myself who would want to use this feature but aren't as familiar with uicontrol. This method can be extended to an arbitrary number of sliders for a function. In the case below I've used just four.
I have not figured out a way to use a vector instead of four independent variables (eg. S.paramblock(1) = S.a) which could possibly allow for a shorter, more general code.
As a further development, a textbox could be associated with the sliders to display the current value. And a move involved development would be to have an input box to adjust the value as well (which could then replace the slider and take up less room in the figure).
function [] = slider_plot()
% Plot different plots according to slider location.
% Junk data for comparison of adjusted curves in this example
datax = 0:pi/12:(23*pi/12);
datay = [0.305; 0.527; 0.759; 0.927; 0.997; 0.942; 0.771; 0.520; 0.309;
0.137; 0.069; 0.143; 0.299; 0.530; 0.767; 0.932; 1.000; 0.943;
0.783; 0.524; 0.309; 0.134; 0.068; 0.133];
% Define figure, normalized position can be adjusted to fit individual
% monitors.
S.fh = figure('units','normalized',...
'Position', [0.515 0.025 0.415 0.87],... %%%%
'name','slider_plot');
% Define axes so that room is available in figure window for sliders
S.ax = axes('unit','normalized',...
'position',[0.1 0.5 0.8 0.45]);
% General cos^2 function
S.cosfunc = @(x,par) par(1)+par(2)*(cos(par(3)*x+par(4)).^2);
% Define inital parameter values for curve
S.a = 0.065;
S.b = 1;
S.c = 1;
S.d = 0;
% Interval 0 to 2*pi for plotting above function
S.theta = 0:0.01:2*pi;
% Plot junk data to adjust curve values to "fit"
S.p1 = scatter(datax,datay,'k');
hold on;
% Plot curve on top of junk data for visual comparison
S.p2 = plot(S.theta,S.cosfunc(S.theta,[S.a,S.b,S.c,S.d]));
hold off;
update(S);
% Slider for slope parameter:
S.aSlider = uicontrol('style','slider',...
'unit','normalized',...
'position',[0.2 0.1 0.7 0.01],...
'min',0,'max',1,'value', S.a,...
'sliderstep',[0.01 0.01],...
'callback', {@SliderCB, 'a'});
% Add a text uicontrol to label the slider.
txta = uicontrol('Style','text',...
'unit','normalized',...
'position',[0.2 0.11 0.7 0.02],...
'String','Fitting Parameter "a"');
% 2nd Slider:
S.bSlider = uicontrol('style','slide',...
'unit','normalized',...
'position',[0.2 0.15 0.7 0.01],...
'min',0,'max',1,'value', S.b,...
'sliderstep',[0.01 0.01],...
'callback', {@SliderCB, 'b'});
% Add a text uicontrol to label the slider.
txtb = uicontrol('Style','text',...
'unit','normalized',...
'position',[0.2 0.16 0.7 0.02],...
'String','Fitting Parameter "b"');
% 3rd Slider:
S.cSlider = uicontrol('style','slide',...
'unit','normalized',...
'position',[0.2 0.2 0.7 0.01],...
'min',0,'max',2,'value', S.c,...
'sliderstep',[0.01 0.01],...
'callback', {@SliderCB, 'c'});
% Add a text uicontrol to label the slider.
txtc = uicontrol('Style','text',...
'unit','normalized',...
'position',[0.2 0.21 0.7 0.02],...
'String','Fitting Parameter "c"');
% 4th Slider:
S.dSlider = uicontrol('style','slide',...
'unit','normalized',...
'position',[0.2 0.25 0.7 0.01],...
'min',-pi,'max',pi,'value', S.d,...
'sliderstep',[0.01 0.01],...
'callback', {@SliderCB, 'd'});
% Add a text uicontrol to label the slider.
txtd = uicontrol('Style','text',...
'unit','normalized',...
'position',[0.2 0.26 0.7 0.02],...
'String','Fitting Parameter "d"');
guidata(S.fh, S); % Store S structure in the figure
end
% Callback for all sliders defined above
function SliderCB(aSlider, EventData, Param)
S = guidata(aSlider); % Get S structure from the figure
S.(Param) = get(aSlider, 'Value'); % Any of the 'a', 'b', etc. defined
update(S); % Update the plot values
guidata(aSlider, S); % Store modified S in figure
end
% Plot update function, creates new y-vector for plot and replaces the plot
% S.p2 with new y-vector
function update(S)
y = S.cosfunc(S.theta,[S.a,S.b,S.c,S.d]); % General cos^2 function
set(S.p2, 'YData', y); % Replace old plot with new plotting values
end
  2 Comments
kangkan Devchoudhury
kangkan Devchoudhury on 2 Jan 2020
Hello.
Thanks for the great explanation. Instead of defining the function anonymously like here, is it possible to call a function defined in another file ?
Thanks
% General cos^2 function
S.cosfunc = @(x,par) par(1)+par(2)*(cos(par(3)*x+par(4)).^2);
Seth Meiselman
Seth Meiselman on 15 Jan 2020
I don't see any reason calling a function file wouldn't work. Can you give an example of the type of file/function you're wanting to call on?

Sign in to comment.

Categories

Find more on Marine and Underwater Vehicles in Help Center and File Exchange

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!