I am trying to learn how the graphic objects work in MATLAB. I tried to create a plot without using the plot function but I am confused why it is not working.
AFIK, when I use the plot function it creates figure, axis, line objects and then sets the property of each object accordingly. I tried to do so but all I'm getting is a white/blank figure.
I'm trying to plot a sine wave so my X and Y data are:
x = 0:0.1:2*pi;
y = sin(x);
This is my main code:
figH = figure();
axis([-2, 2, -2, 2]);
lineH = findobj(figH, 'type', 'line');
set(lineH, 'XData', x,...
'YData', y,...
'Color', 'r');
The weird thing is that when I type
get(lineH)
I'm not getting anything back. I appreciate tips and comments.
You need to create the line before you can find it and change a property.
e.g.
hLine = line ( x, y, .... );
% Then you can modify the properties, i.e.
set ( hLine, 'XData', x );
% etc...
Edit:
Its a good idea to create and store each of your objects directly (rather than allowing the command to find the appropriate figure, axes etc....)
hFig = figure;
hAx = axes ( 'parent', hFig );
hLine = line ( hAx, x, y, .... );
Related
I'm writing a script that will create 2 suplots, and have either a single slider that scrolls the x axis of both plots, or 2 sliders that individually control each subplots x axis.
I have been using an adapted version of Steven Lords FileExchange scrolling plot demo for my slider.
Right now it will only update the most recent plot (as it is currently using gca in its callback function). I've tried just replacing gca with the axes I want (the variables first_plot or second_plot) but this doesn't seem to work.
My question is then, how should I adapt this function to either control both plots or each plot individually? Here is an example of the script I am writing:
x=0:1e-2:2*pi;
y=sin(x);
dx=2;
first_plot = subplot(2,1,1);
plot(x, y);
scrollplot(dx, x)
%Plot the respiration and probe data with scrolling bar
second_plot = subplot(2,1,2);
plot(x, y);
scrollplot(dx,x)
% dx is the width of the axis 'window'
function scrollplot(dx, x)
a=gca;
% Set appropriate axis limits and settings
set(gcf,'doublebuffer','on');
set(a,'xlim',[0 dx]);
% Generate constants for use in uicontrol initialization
pos=get(a,'position');
Newpos=[pos(1) pos(2)-0.1 pos(3) 0.05];
% This will create a slider which is just underneath the axis
% but still leaves room for the axis labels above the slider
xmax=max(x);
%S= set(gca,'xlim',(get(gcbo,'value')+[0 dx]));
S=['set(gca,''xlim'',get(gcbo,''value'')+[0 ' num2str(dx) '])'];
% Setting up callback string to modify XLim of axis (gca)
% based on the position of the slider (gcbo)
% Creating Uicontrol
h=uicontrol('style','slider',...
'units','normalized','position',Newpos,...
'callback',S,'min',0,'max',xmax-dx);
end
Thanks!
You're almost there, but there's some structural issues from when you modified the code from only one set of axes.
The key thing to do is change the callback function from a string to an actual local function. This makes handling the callback much simpler!
I've adapted your code to work with two (or more) axes. Note we only need to set up the scroll bar once! You were setting it up for each axes (the scroll bars were stacked on top of each other) and both scrollers only operated on gca. Just naming the axes isn't enough to change gca, you have to use those variables! I've assigned the axes to an array for easy manipulation.
Please see the comments for details:
x=0:1e-2:2*pi;
y=sin(x);
% dx is the width of the axis 'window'
dx=2;
% Initialise the figure once, and we only need to set the properties once
fig = figure(1); clf;
set( fig, 'doublebuffer', 'on');
% Create a placeholder for axes objects
ax = gobjects( 2, 1 );
% Create plots, storing them in the axes object
ax(1) = subplot(2,1,1);
plot(x, y);
ax(2) = subplot(2,1,2);
plot(x, y);
% Set up the scroller for the array of axes objects in 'ax'
scrollplot( dx, x, ax)
function scrollplot( dx, x, ax )
% Set appropriate axis limits
for ii = 1:numel(ax)
set( ax(ii), 'xlim', [0 dx] );
end
% Create Uicontrol slider
% The callback is another local function, this gives us more
% flexibility than a character array.
uicontrol('style','slider',...
'units', 'normalized', 'position', [0.1 0.01 0.8 0.05],...
'callback', #(slider, ~) scrollcallback( ax, dx, slider ), ...
'min', 0, 'max', max(x)-dx );
end
function scrollcallback( ax, dx, slider, varargin )
% Scroller callback loops through the axes objects and updates the xlim
val = slider.Value;
for ii = 1:numel(ax)
set( ax(ii), 'xlim', val + [0, dx] );
end
end
I have two axes: one for viewing images and the other for plotting graphs. I get this error when I try to specify which axes I want to plot the data on: Error using plot. A numeric or double convertible argument is expected when trying plot(handles.axis,curve,x,y).
figure
handles.axis = gca;
x = 1:10;
y = 1:10;
curve = fit(x',y','linearinterp');
plot(curve,x,y) % works fine
plot(handles.axis,curve,x,y) % doesn't work
plot(curve,x,y,'Parent',handles.axis) % doesn't work
You can paste this example into Matlab to try it out. How can the code be corrected in order to specify the axes?
plot in the curve fitting toolbox is not the same as MATLAB's base plot. Though there is a documented syntax for specifying the parent axes for sfit objects, there doesn't seem to be one for cfit objects, which would be returned by your fit call in this case.
However, from the documentation we see that:
plot(cfit) plots the cfit object over the domain of the current axes, if any
So if the current axis is set prior to the plot call it should work as desired. This can be done either by modifying the figure's CurrentAxes property or by calling axes with the handle of an axes object as an input.
% Set up GUI
h.f = figure;
h.ax(1) = axes('Parent', h.f, 'Units', 'Normalized', 'Position', [0.07 0.1 0.4 0.85]);
h.ax(2) = axes('Parent', h.f, 'Units', 'Normalized', 'Position', [0.55 0.1 0.4 0.85]);
% Set up curve fit
x = 1:10;
y = 1:10;
curve = fit(x', y', 'linearinterp'); % Returns cfit object
axes(h.ax(2)); % Set right axes as CurrentAxes
% h.f.CurrentAxes = h.ax(2); % Set right axes as CurrentAxes
plot(curve, x, y);
I refine my answer as follows:
It looks that the plot function in matlab does not like a fit object after an axis followed by two vectors. In such case, I would do something like this:
x = 1:10;
y = 1:10;
figure % new figure
ax1 = subplot(2,1,1);
ax2 = subplot(2,1,2);
curve = fit(x',y','linearinterp');
plot(ax1,x,curve(x));
hold on;plot(ax1,x,y,'o') % works fine
plot(ax2,x,curve(x));
hold on;plot(ax2,x,y,'o') % works fine
Actually the trick is to provide x and then curve(x) as two vectors without giving the whole fit-object to the plot function.
I have to plot 1 line plot and 3 grouped scatter plots in a single plot window.
The following is the code I tried,
figure;
t1=0:0.1:10;
X = 2*sin(t1);
ts = 0:1:10;
Y1 = randi([0 1],length(ts),1);
Y2 = randi([0 1],length(ts),1);
Y3 = randi([0 1],length(ts),1);
plotyy(t1,X,[ts',ts',ts'],[Y1,Y2,Y3],'plot','scatter');
%plotyy(t1,X,[ts',ts',ts'],[Y1,Y2,Y3],'plot','plot');
The following are my questions,
The above code works if I replace 'scatter' by 'plot' (see commented out line), but 'scatter' works only for 1 data set and not for 3. Why?
How to individually assign colors to the 3 grouped scatter plots or plots?
Read the error message you're given:
Error using scatter (line 44) X and Y must be vectors of the same
length.
If you look at the documentation for scatter you'll see that the inputs must be vectors and you're attempting to pass arrays.
One option is to stack the vectors:
plotyy(t1,X,[ts';ts';ts'],[Y1;Y2;Y3],'plot','scatter');
But I don't know if this is what you're looking for, it certainly doesn't look like the commented line. You'll have to clarify what you want the final plot to look like.
As for the second question, I would honestly recommend not using plotyy. I may be biased but I've found it far to finicky for my tastes. The method I like to use is to stack multiple axes and plot to each one. This gives me full control over all of my graphics objects and plots.
For example:
t1=0:0.1:10;
X = 2*sin(t1);
ts = 0:1:10;
Y1 = randi([0 1],length(ts),1);
Y2 = randi([0 1],length(ts),1);
Y3 = randi([0 1],length(ts),1);
% Create axes & store handles
h.myfig = figure;
h.ax1 = axes('Parent', h.myfig, 'Box', 'off');
h.ax2 = axes('Parent', h.myfig, 'Position', h.ax1.Position, 'Color', 'none', 'YAxisLocation', 'Right');
% Preserve axes formatting
hold(h.ax1, 'on');
hold(h.ax2, 'on');
% Plot data
h.plot(1) = plot(h.ax1, t1, X);
h.scatter(1) = scatter(h.ax2, ts', Y1);
h.scatter(2) = scatter(h.ax2, ts', Y2);
h.scatter(3) = scatter(h.ax2, ts', Y3);
Gives you:
And now you have full control over all of the axes and line properties. Note that this assumes you have R2014b or newer in order to use the dot notation for accessing the Position property of h.ax1. If you are running an older version you can use get(h.ax1, 'Position') instead.
I'm trying to make a figure of a surface plot, and beneath the surface I wish to show the contour lines, but I want the contour to be at z = -1 instead of at the default value 0. I found a previous post about this problem here, but when I try the solution the contour is still at z = 0. Maybe it has something to do with the version of MATLAB I'm using, which is 2014b?
Any ideas on how to make it work?
The code I tried:
%# plot surface and contour
Z = peaks;
surf(Z), hold on
[~,h] = contourf(Z); %# get handle to contourgroup object
%# change the ZData property of the inner patches
hh = get(h,'Children'); %# get handles to patch objects
for i=1:numel(hh)
zdata = ones(size( get(hh(i),'XData') ));
set(hh(i), 'ZData',-10*zdata)
end
So, I couldn't really figure out to do it as proposed in the example I found and posted, but I found a way that works. What I ended up doing was basically this:
figure
hold on
surf(X,Y,Z+1);
contour(X,Y,Z);
zz = get(gca,'ZTick');
set(gca,'ZTickLabel',sprintf('%3.1f\n',zz-1));
This gets me the surf and contour in the same figure, but yields some problems with color mappings.
I figured out how to solve the problem with color mappings the user Kine faced. Note: I've done the following code on MATLAB R2015b:
offset = 0.5;
plotHandle = surfc(X1, Y1, Z1);
hold on;
% This line moves the surface up from its original location and increases the space between the surface and the contour plot
plotHandle(1).ZData = plotHandle.ZData + offset;
% However in doing so the color mappings are changed. So, the line below restores these mappings
plotHandle(1).CData = plotHandle.CData - offset;
% This line changes fills the contour plot
plotHandle(2).Fill = 'on';
grid on;
% The following lines draw critical areas on the contour line, as it was more readable in my case
axisHandle = gca;
ZHeight = axisHandle.ZLim(1);
plot3(X2, Y2, ZHeight, 'o', 'MarkerSize', 10, 'LineWidth', 1, 'Color', 'k', 'MarkerFaceColor', 'm');
plot3(Y2, X2, ZHeight, 'o', 'MarkerSize', 10, 'LineWidth', 1, 'Color', 'k', 'MarkerFaceColor', 'm');
hold off
I got the same problem.
And finally, I got the contourf on plane Z=-10.
My MATLAB version is
MATLAB Version: 8.5.0.197613 (R2015a)
hope the codes work 4 you
clear all
clc
[X,Y,Z] = peaks;
[~,hContour] = contourf(X,Y,Z,20,'edgecolor','none');
hContour.ContourZLevel = -10; % set the contour's Z position
view(44,30)
colormap(jet)
I have multiple figures open, and I want to update them independently during runtime. The following toy example should clarify my intention:
clf;
figure('name', 'a and b'); % a and b should be plotted to this window
hold on;
ylim([-100, 100]);
figure('name', 'c'); % only c should be plotted to this window
a = 0;
b = [];
for i = 1:100
a = a + 1;
b = [b, -i];
c = b;
xlim([0, i]);
plot(i, a, 'o');
plot(i, b(i), '.r');
drawnow;
end
The problem here is that when I open the second figure, I cannot tell the plot functions to plot to the first one instead of the second (and only c should be plotted to the second).
You can use something like
figure(1)
plot(x,y) % this will go on figure 1
figure(2)
plot(z,w) % this will go on another figure
The command will also set the figure visible and on top of everything.
You can switch back and forth between the figures as necessary by issuing the same figure command. Alternatively, you can use the handle to the figure as well:
h=figure(...)
and then issue figure(h) instead of using numeric indices. With this syntax, you can also prevent the figure from popping up on top by using
set(0,'CurrentFigure',h)
You can specify the axes-object in the plot-command. See here:
http://www.mathworks.de/help/techdoc/ref/plot.html
So, open a figure, insert the axes, save the id of the axes object, and then plot into it:
figure
hAx1 = axes;
plot(hAx1, 1, 1, '*r')
hold on
figure
hAx2 = axes;
plot(hAx2, 2, 1, '*r')
hold on
plot(hAx2, 3, 4, '*b')
plot(hAx1, 3, 3, '*b')
Alternatively, you can use gca instead of creating the axes object yourself (because it's automatically created within the actual figure, when it doesn't exist!)
figure
plot(1,1)
hAx1 = gca;
hold on
figure
plot(2,2)
plot(hAx1, 3, 3)
See the following hierarchy representing the relationship between figures and axes
From http://www.mathworks.de/help/techdoc/learn_matlab/f3-15974.html.