I'm trying to plot a 3D figure(surf plot) inside a figure that I have already created but for some reason my new plot is created in a separate figure.
The code consist of 2 scripts which I will be posting.
The first script initializes the act frame I want to draw in and its callback (from the slider) draws my cylinder which for some reason appears inside a new frame leading to this mess:
Main script that creates the main figure I want to draw in.
%%
clf;
clear;
close all;
clc;
load('myHeatMap.mat','myHeatMap');
filename = ('C:\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\filenames.txt');
%This line simply gives us a table of all filenames in this file.
T = readtable(filename);
tsize = size(T);
tsize2 = size(T, 1);
filename = strcat('\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\', string(T{1,1}));
map100 = getCylinderHeatMap(filename);
%Figure/parent container (uifigure) properties%
App = uifigure('Scrollable','on','Name','Heatmap Plots','NumberTitle','off');
App_Width = 1000; App_Height = 500;
App.Position = [0 0 App_Width App_Height];
%Slider label (uilabel) properties%
Slider_Label = uilabel('Parent',App);
Slider_Label.Text = "Cylinder Number";
Slider_Label.Position = [25 20 200 100];
%Slider (uislider) properties%
Slider = uislider('Parent',App);
Slider.Limits = [1 1000];
Slider.Value = 1;
Slider_Width = App_Width - 500;
Margin = (App_Width - Slider_Width)/2;
Slider.Position = [Margin 50 Slider_Width 3];
Slider.MajorTicks = (1:100:1000);
Slider.FontSize = 6;
Red = 87; Green = 207; Blue = 220;
Slider.FontColor = [Red/255 Green/255 Blue/255];
%Plot (uiaxes) properties%
Heatmap_Cylinder_Plot = uiaxes('Parent',App);
Heatmap_Cylinder_Plot_X_Position = 100;
Heatmap_Cylinder_Plot_Y_Position = 100;
Heatmap_Cylinder_Plot_Height = 350;
Heatmap_Cylinder_Plot_Width = 400;
Heatmap_Cylinder_Plot.Position = [Heatmap_Cylinder_Plot_X_Position Heatmap_Cylinder_Plot_Y_Position Heatmap_Cylinder_Plot_Width Heatmap_Cylinder_Plot_Height];
Heatmap_Cylinder_Plot.GridColor = [0.15 0.15 0.15];
Heatmap_Cylinder_Plot.XGrid = 'on';
Heatmap_Cylinder_Plot.YGrid = 'on';
Heatmap_Cylinder_Plot.ZGrid = 'on';
%Image (uiimage) properties%
Heatmap_Image = uiimage('Parent',App);
Heatmap_X_Position = (App_Width/2) + 50;
Heatmap_Y_Position = 80;
Heatmap_Height = 350;
Heatmap_Width = 400;
Heatmap_Image.Position = [Heatmap_X_Position Heatmap_Y_Position Heatmap_Height Heatmap_Width];
%Callback function as the slider is moved%
Slider.ValueChangedFcn = #(Slider,event) Snap_Slider(Slider,Slider_Label,Heatmap_Cylinder_Plot,Heatmap_Image,T,...
myHeatMap);
%%
%Callback function definition%
function [] = Snap_Slider(Slider,Slider_Label,Heatmap_Cylinder_Plot,Heatmap_Image,T,myHeatMap)
Slider.Value = round(Slider.Value);
filename = strcat('\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\', string(T{Slider.Value,1}));
map100 = getCylinderHeatMap(filename);
splitFileName = strsplit(string(T{Slider.Value,1}),'.');
Slider_Label.Text = "Time Stamp: " + splitFileName{1,1};
%Put plotting code here%
plot(Heatmap_Cylinder_Plot,createSurfCylinder(map100));
%Put image plotting code here%
Heatmap_Image.ImageSource = "";
colormap(myHeatMap);
end
%%
Script for drawing actual Cylinder.
function cylinder = createSurfCylinder(matrix)
%Load heat map.
load('myHeatMap.mat','myHeatMap');
%%
%Cylinder creation
Sample_Range = 255 - 0;
Temperature_Range = 450 - 50;
Multiplier = Temperature_Range/Sample_Range;
map100 = matrix.*Multiplier + 50;
%Setting up the figure%
Radius = 1.5;
Number_Of_Data_Points = 360;
theta = linspace(0,2*pi,Number_Of_Data_Points);
%The xy values according to radius and number of points%
Z_Circle = Radius*cos(theta);
Y_Circle = Radius*sin(theta);
map100 = rot90(map100);
Height = 512;
Z_Circle = repmat(Z_Circle,Height,1);
Y_Circle = repmat(Y_Circle,Height,1);
X_Length = (1:512)';
X_Length = repmat(X_Length,1,Number_Of_Data_Points);
figure('Position', [10 10 800 800])
clf;
close;
cyl = surf(X_Length,Y_Circle,Z_Circle,'Cdata',map100);
title("3D Cylinder Heatmap Plot");
zlabel("Z-Position");
ylabel("Y-Position");
xlabel("Length(Cm)");
set(gca,'Ydir','reverse')
colormap(myHeatMap);
colorbar;
shading interp
Maximum_Value = 450;
Minimum_Value = 50;
caxis([Minimum_Value Maximum_Value]);
%Show the image in the subplot and add custome color coding to it.
% subplot(1,3,3); imshow(rot90(map100));
% colormap(myHeatMap);
% caxis([Minimum_Value Maximum_Value]);
cylinder = cyl;
%%
end
Any one that knows how to make may cylinder appear in my original Uiframe?
Any help would be much appreciated.
There are a few things you may want to note. First the closing-commands.
clf close (current) figure
clear clear all variables in the current workspace (this can the the base workspace in scripts or the workspace of the function, in which the command is called)
close all closes all open figure windows
clc clear command window.
Although these are handy commands, the are meant to be used when working in the command window and one should think twice when using them in scripts and never use them in functions. Why so? You might forget that you have used them and consequently, you code behaves unexpected. In particular if you call multiple functions/scripts, which all manipulate the same windows or output.
The command figure opens a new figure window. So every time this command is issued, a new window pops up and is set to "active", i.e. it is automatically the current figure. It returns its specific figure handle if you assign an output to it: fh = figure('Name','Figure A'). If you later what to activate a specific figure, you can call its handle: figure(fh). The function gcf always returns the handle of the current figure.
Now, let's see for example, in function createSurfCylinder, you are calling
figure('Position', [10 10 800 800])
clf;
close;
This opens a figure, closes the current figure (that is the figure you have just opened) and closes the current figure (which is now the one that was open before you opened & closed the last figure...
The plot()-function draws a line into the current axis (if not existing, it opens an axis). It can take as a first input a specific axis handle. The default is gca, which is a function meaning something like get current axis.
So to have all control over your plots, keep track of the handles. I always go like this:
fh1 = struct(); % create an empty struct
fh1.fig = figure('Name','very important figure'); % open figure & keep its handle
fh1.ax = subplot(1,1,1); % this opens a single axis & I keep the handle
% plot
plot( fh.ax, [1,10],[2,5])
ylabel( fh.ax, 'Amplitude Y / unit')
xlabel( fh.ax, 'Measure of time x / unit')
With the command subplot one can arrange multiple axes in one figure (here you need to be aware of the difference between a figure and an axis, and why there are two different types of handles). For example
fh2 = struct(); % create a new empty struct
fh2.fig = figure('Name','Multiple axes in one figure'); % open figure & keep its handle
fh2.ax = cell(3,1);
fh2.ax{1} = subplot(2,2,1); % this opens a single axis & keeps the handle
fh2.ax{2} = subplot(2,2,2); % this opens a single axis & keeps the handle
fh2.ax{3} = subplot(2,2,3:4); % this opens a single axis & keeps the handle
% do plotting with your axis-handles
(yes, I usually first open all axes and than fill them with graphs/lines)
Related
I'm trying to get a real time plot of data I'm acquiring with a NI USB-6008. I tried doing the same with arduino and got a plot exactly as I wanted (see here https://i.stack.imgur.com/08kzU.jpg), and the x-axis would move in real-time, but I couldn't define the sampling rate. With NI I was able to define the sampling rate I wanted but I can't display the data in a continuous, real-time plot, I can only see 1 sec at a time and I need to be able to have access to all the data acquired since I want to measure a real-time EEG. I'm a new matlab user, so please consider no previous knowledge.
This is the code I've got so far:
clear
close all
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
dq.ScansAvailableFcn = #(src,evt) plotDataAvailable(src, evt);
dq.ScansAvailableFcnCount = 100;
start(dq, "Duration", seconds(5))
while dq.Running
pause(0.5);
end
time = 0;
data = 0;
n = ceil(dq.Rate/10);
%Set up Plot
figure(1)
plotGraph = plot(time,data);
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10); ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
h = animatedline;
function plotDataAvailable(src, ~)
while ishandle(plotGraph) % Loop when Plot is Active will run until plot is closed
data = read(dq,n);
t = datetime('now');
% Add points to animation
addpoints(h,datenum(t),data)
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
end
This was my previous arduino code that showed me the plot I needed (with the wrong sampling rate):
clear
clc
%User Defined Properties
a = arduino('com4','uno'); % Define the Arduino Communication port
plotTitle = 'Arduino Data Log'; % Plot title
%Define Function Variables
time = 0;
data = 0;
%Set up Plot
figure(1)
plotGraph = plot(time,data,'-r' );
title(plotTitle,'FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10); ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
ax.YLim = [0 5]; % Sets y-min and y-max
while ishandle(plotGraph) % Loop when Plot is Active will run until plot is closed
startIteration = tic;
voltagem = readVoltage(a,'A0')
t = datetime('now');
% Add points to animation
addpoints(h,datenum(t),voltagem)
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
I've tried using this while loop on my NI data but it doesn't work.
I would really appreciate your help.
You've got the order of the operations wrong. What your code is doing at the moment is:
initialize the data acquisition
read the data from the hardware while trying to add data to lines that don't exist
initialize the animated lines.
Furthermore, in your addpoints call you're trying to plot t, which is a scalar, and data, which is an array.
What you should do instead is:
clear
close all
% Set up the plot
figure(1)
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10)
ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
% Set up the data acquisition
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
dq.ScansAvailableFcn = {#plotDataAvailable, h, ax}; % pass also the handle to the line and to the axes
dq.ScansAvailableFcnCount = 100;
% Now you start the data acquisition
start(dq, "Duration", seconds(5))
function plotDataAvailable(src, evt, h, ax)
data = read(dq, n);
% maybe your time array should look something like this?
t = datetime(now) - seconds((length(data)-1:-1:0)./src.Rate);
% Add points to animated line
addpoints(h, datenum(t), data)
% Update axes
% ax.XLim = datenum([t-seconds(15) t]); % this line is useless, why would you have a 15s window when your data acquisition is only 5s long?
datetick('x','keeplimits')
drawnow
end
I can't try this at the moment, so it might not work exactly.
So I think I finally got it, because I got the plot like I wanted, with the x-axis moving with real-time. However I still get an error saying "Unrecognized table variable name 'Dev1_ai0'" event tho I checked that's the name of the row that I want. Anyways, this is what my code looks now.
clear
close all
time = 0;
data = 0;
% Set up the plot
figure(1)
plotGraph = plot(time,data,'-r' );
title('DAQ data log','FontSize',15);
xlabel ('Elapsed Time (s)','FontSize',10)
ylabel('Voltage (V)','FontSize',10);
h = animatedline;
ax = gca;
ax.YGrid = 'on';
ax.XGrid = 'on';
% Set up the data acquisition
dq = daq("ni");
ch1 = addinput(dq, "Dev1", "ai0", "Voltage");
dq.Rate = 1000;
% Start the data acquisition
start(dq, "Duration", seconds(10))
n = ceil(dq.Rate/10);
while ishandle(plotGraph)
data = read(dq, n);
voltage = data.Dev1_ai0;
t = datetime('now');
for i = 1:100
% Add points to animated line
if isvalid(h)
addpoints(h, datenum(t), voltage(i))
end
end
% Update axes
ax.XLim = datenum([t-seconds(15) t]);
datetick('x','keeplimits')
drawnow
end
disp('Plot Closed')
I have a 3D figure in Matlab, let's assume it's sphere. What I need, is to get the X, Y, Z values of the point on surface, that I click with the mouse.
r = 10;
[X,Y,Z] = sphere(50);
X2 = X * r;
Y2 = Y * r;
Z2 = Z * r;
figure();
props.FaceColor = 'texture';
props.EdgeColor = 'none';
props.FaceLighting = 'phong';
sphere = surf(X2,Y2,Z2,props);
axis equal
hold on
clicked_point = [?,?,?];
So in this example I want the clicked_point to be equal to [-3.445,-7.32,5.878].
I've tried with such solution:
clear all;
close all;
r = 10;
[X,Y,Z] = sphere(50);
X2 = X * r;
Y2 = Y * r;
Z2 = Z * r;
fig = figure();
props.FaceColor = 'texture';
props.EdgeColor = 'none';
props.FaceLighting = 'phong';
sphere = surf(X2,Y2,Z2,props);
axis equal
dcm_obj = datacursormode(fig);
set(dcm_obj,'DisplayStyle','datatip',...
'SnapToDataVertex','off','Enable','on')
c_info = getCursorInfo(dcm_obj);
while length(c_info) < 1
datacursormode on
c_info = getCursorInfo(dcm_obj);
end
But after that I can't even click on the sphere to display any data on figure. How can I get X, Y, Z in script? If not, how can I detect that the mouse click has already occured in Matlab?
It is not clear whether you want the clicked_point variable to reside in the base workspace or if that is going to be part of a GUI.
I'll give you a solution for the base workspace.
The trick is to just add the bit of code you need to the UpdateFcn of the datacursormode object.
Save a function getClickedPoint.m somewhere visible on your MATLAB path:
function output_txt = getClickedPoint(obj,event_obj)
% Display the position of the data cursor
% obj Currently not used (empty)
% event_obj Handle to event object
% output_txt Data cursor text string (string or cell array of strings).
pos = get(event_obj,'Position');
output_txt = {['X: ',num2str(pos(1),4)],...
['Y: ',num2str(pos(2),4)]};
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
output_txt{end+1} = ['Z: ',num2str(pos(3),4)];
end
assignin('base','clicked_point',pos)
All this code is actually a copy of the default function used by data cursors. The only modifications are:
I changed the name (obviously you want it to be unique)
I added the last line of code
This last line of code use assignin to transfer the position of the cursor into a variable (named clicked_point) in the base workspace.
Armed with that, keep your code which generate the sphere (although I recommend you change the name of the surface object to something else than sphere as this is a built in MATLAB function), and we just have to modify the datacursormode object to instruct it to use our getClickedPoint function:
[X,Y,Z] = sphere(50);
r = 10 ; X2 = X * r; Y2 = Y * r; Z2 = Z * r;
fig = figure ;
hs = surf(X2,Y2,Z2,'FaceColor','texture','EdgeColor','none','FaceLighting','phong');
axis equal
%% Assign custom update function to dcm
dcm_obj = datacursormode(fig);
set(dcm_obj,'SnapToDataVertex','off','Enable','on','UpdateFcn',#getClickedPoint)
Now the first time you click on the sphere, the variable clicked_point will be created in the workspace with the coordinates of the point. And every time you click again on the sphere the variable will be updated:
If this is to be applied with a GUI, use the same technique but instead of assignin, I would recommend to use the setappdata function. (you can read Share Data Among Callbacks to have details about how this works.)
For some reason, the following code only displays the masked image with roi at 10,10 with height and width 100,100. These are the initial values. It seems the image does not update even after the getPosition function. Could anyone explain this issue?
`I = imread('/Users/imageuser/Documents/PT300.tif');
h = imshow(I);
% define circular roi by square bounding box
x = 10;
y = 10;
d1 = 100;
d2 = 100;
e = imellipse(gca, [x y d1 d2]);
% roi can be interactively moved/adjusted
% do not close figure window before createMask is called
%%% these lines are only needed if you move or resize the roi
pos = getPosition(e);
x = pos(1);
y = pos(2);
d1 = pos(3);
d2 = pos(4);
%%%
BW = createMask(e,h);
pause;
imshow(BW);`
You need to put those lines (note I inverted their order):
pause;
BW = createMask(e,h);
before calling getPosition, otherwise the new position is not updated.
Whole code:
clear
clc
close all
I = imread('coins.png');
h = imshow(I);
% define circular roi by square bounding box
x = 10;
y = 10;
d1 = 100;
d2 = 100;
e = imellipse(gca, [x y d1 d2]);
pause;
BW = createMask(e,h);
% roi can be interactively moved/adjusted
% do not close figure window before createMask is called
%%% these lines are only needed if you move or resize the roi
pos = getPosition(e)
x = pos(1);
y = pos(2);
d1 = pos(3);
d2 = pos(4);
%%%
figure
imshow(BW);
sample output after dragging the ROI:
Yay!
Note: As mentioned by juicestain, instead of using pause to halt execution of the program while the user is done creating the GUI, you can use wait to wait until the user double-clicks on the ROI object instead of having to press a key as with the pause command.
Therefore, you could replace the call to pause with a call to wait(e).
I have to create some draggable points on an axes. However, this seems to be a very slow process, on my machine taking a bit more than a second when done like so:
x = rand(100,1);
y = rand(100,1);
tic;
for i = 1:100
h(i) = impoint(gca, x(i), y(i));
end
toc;
Any ideas on speed up would be highly appreciated.
The idea is simply to provide the user with the possibility to correct positions in a figure that have been previously calculated by Matlab, here exemplified by the random numbers.
You can use the the ginput cursor within a while loop to mark all points you want to edit. Afterwards just click outside the axes to leave the loop, move the points and accept with any key.
f = figure(1);
scatter(x,y);
ax = gca;
i = 1;
while 1
[u,v] = ginput(1);
if ~inpolygon(u,v,ax.XLim,ax.YLim); break; end;
[~, ind] = min(hypot(x-u,y-v));
h(i).handle = impoint(gca, x(ind), y(ind));
h(i).index = ind;
i = i + 1;
end
Depending on how you're updating your plot you can gain a general speedup by using functions like clf (clear figure) and cla (clear axes) instead of always opening a new figure window as explained in this answer are may useful.
Alternatively the following is a very rough idea of what I meant in the comments. It throws various errors and I don't have the time to debug it right now. But maybe it helps as a starting point.
1) Conventional plotting of data and activating of datacursormode
x = rand(100,1);
y = rand(100,1);
xlim([0 1]); ylim([0 1])
f = figure(1)
scatter(x,y)
datacursormode on
dcm = datacursormode(f);
set(dcm,'DisplayStyle','datatip','Enable','on','UpdateFcn',#customUpdateFunction)
2) Custom update function evaluating the chosen datatip and creating an impoint
function txt = customUpdateFunction(empt,event_obj)
pos = get(event_obj,'Position');
ax = get(event_obj.Target,'parent');
sc = get(ax,'children');
x = sc.XData;
y = sc.YData;
mask = x == pos(1) & y == pos(2);
x(mask) = NaN;
y(mask) = NaN;
set(sc, 'XData', x, 'YData', y);
set(datacursormode(gcf),'Enable','off')
impoint(ax, pos(1),pos(2));
delete(findall(ax,'Type','hggroup','HandleVisibility','off'));
txt = {};
It works for the, if you'd just want to move one point. Reactivating the datacursormode and setting a second point fails:
Maybe you can find the error.
I have a 576x576x150 matrix. Each 576x576 set represents an image. When I want to plot one frame I do it by using the plot command:
figure(1);
imshow(B(:,:,45),[]) % plots frame 45
title('45') % tells frame number
However I would like to add a slider to the plot, so I can move from 1-150 frame within the figure.I've seen examples of people using uicontrol but I don't know how to code it. In addition to that, I would like to have a title on top of the figure telling me the frame number.
Here is how I do it. I like to keep a single function that does the plotting so you don't recycle commands elsewhere. You could replace the first two lines by function test(B) to use you own B matrix. This code is pretty easy to extend. You will also want to play with the layout to suit your purpose.
function test
B=rand(576,576,150);
fig=figure(100);
set(fig,'Name','Image','Toolbar','figure',...
'NumberTitle','off')
% Create an axes to plot in
axes('Position',[.15 .05 .7 .9]);
% sliders for epsilon and lambda
slider1_handle=uicontrol(fig,'Style','slider','Max',150,'Min',1,...
'Value',2,'SliderStep',[1/(150-1) 10/(150-1)],...
'Units','normalized','Position',[.02 .02 .14 .05]);
uicontrol(fig,'Style','text','Units','normalized','Position',[.02 .07 .14 .04],...
'String','Choose frame');
% Set up callbacks
vars=struct('slider1_handle',slider1_handle,'B',B);
set(slider1_handle,'Callback',{#slider1_callback,vars});
plotterfcn(vars)
% End of main file
% Callback subfunctions to support UI actions
function slider1_callback(~,~,vars)
% Run slider1 which controls value of epsilon
plotterfcn(vars)
function plotterfcn(vars)
% Plots the image
imshow(vars.B(:,:,get(vars.slider1_handle,'Value')));
title(num2str(get(vars.slider1_handle,'Value')));
The idea is to use uicontrol() to enable sliding/scrolling.
The following code is for scrolling (created by Evan Brooks, you can modify it to sliding):
function scrollfigdemo
% create new figure window
f = figure;
set(f,'doublebuffer', 'on', 'resize', 'off')
% set columns of plots
cols = 2;
% create 5 data sets to plot
x=0:1e-2:2*pi;
y{1}=sin(x);
y{2}=cos(x);
y{3}=tan(x);
y{4}=x.^2;
y{5}=x.^3;
% determine required rows of plots
rows = ceil(length(y)/cols);
% increase figure width for additional axes
fpos = get(gcf, 'position');
scrnsz = get(0, 'screensize');
fwidth = min([fpos(3)*cols, scrnsz(3)-20]);
fheight = fwidth/cols*.75; % maintain aspect ratio
set(gcf, 'position', [10 fpos(2) fwidth fheight])
% setup all axes
buf = .15/cols; % buffer between axes & between left edge of figure and axes
awidth = (1-buf*cols-.08/cols)/cols; % width of all axes
aidx = 1;
rowidx = 0;
while aidx <= length(y)
for i = 0:cols-1
if aidx+i <= length(y)
start = buf + buf*i + awidth*i;
apos{aidx+i} = [start 1-rowidx-.92 awidth .85];
a{aidx+i} = axes('position', apos{aidx+i});
end
end
rowidx = rowidx + 1; % increment row
aidx = aidx + cols; % increment index of axes
end
% make plots
axes(a{1}), plot(x,y{1}), title('sine'), xlabel('x'), ylabel('sin(x)')
axes(a{2}), plot(x,y{2}), title('cosine'), xlabel('x'), ylabel('cos(x)')
axes(a{3}), plot(x,y{3}), title('tangent'), xlabel('x'), ylabel('tan(x)')
axes(a{4}), plot(x,y{4}), title('x^2'), xlabel('x'), ylabel('x^2')
axes(a{5}), plot(x,y{5}), title('x^3'), xlabel('x'), ylabel('x^3')
% determine the position of the scrollbar & its limits
swidth = max([.03/cols, 16/scrnsz(3)]);
ypos = [1-swidth 0 swidth 1];
ymax = 0;
ymin = -1*(rows-1);
% build the callback that will be executed on scrolling
clbk = '';
for i = 1:length(a)
line = ['set(',num2str(a{i},'%.13f'),',''position'',[', ...
num2str(apos{i}(1)),' ',num2str(apos{i}(2)),'-get(gcbo,''value'') ', num2str(apos{i}(3)), ...
' ', num2str(apos{i}(4)),'])'];
if i ~= length(a)
line = [line,','];
end
clbk = [clbk,line];
end
% create the slider
uicontrol('style','slider', ...
'units','normalized','position',ypos, ...
'callback',clbk,'min',ymin,'max',ymax,'value',0);