MATLAB show all 'active' plots, plt.show()? - matlab

hold on
ax = gca;
plot(ax, [1 2 3])
hold off
hold on
ax = gca;
plot(ax, [3 2 1])
hold off
Python's Matplotlib has plt.show() which can be used like
plt.plot([1, 2, 3])
plt.show()
plt.plot([3, 2, 1])
plt.show()
to display two separate figures. I've tried to recreate this behavior with the top block, with no success. Can it be done?
Context
I know this can be accomplished with explicit calls to figure and axes, but the idea is for this to happen after we finish plotting, not before we begin. That is, I define convenience plot functions
function plot1(varargin)
% do stuff
end
function plot2(varargin)
% do stuff
end
and each has a keyword argument show, which is to be used like
plot1(x, show=true)
plot2(x, show=true)
so plot2 should figure out that something's plotted before it without user input.

I tested below to work as intended with calls to variants of plot, scatter, and image. Also, as in Python, show=false for the last executed plot still acts same as show=true.
plot2([1 2 3], show=1)
plot2([3 2 1])
plot2([1 2 3])
plot2([3 2 1])
function plot2(x, C)
arguments
x;
C.show = false;
end
hold on
fig = gcf();
ax = gca();
plot(ax, x);
maybe_show(fig, ax, C.show)
end
function maybe_show(fig, ax, show_)
fig.Visible = true;
if show_
figure('Visible', 'off')
hold off
end
end

Related

Multiple custom graphics object inheriting from ChartContainer

I am trying to write a custom chart (or graphical object, rather), and I would like to plot several of them in a single figure. I am following this guide, but I keep getting:
Error using matlab.graphics.chartcontainer.ChartContainer
Adding TestChart to axes is not supported. Turn hold off.
In my custom class I am combining a line and a surface, but this a minimal class works as an example:
classdef TestChart < matlab.graphics.chartcontainer.ChartContainer
properties (Access = private, Transient, NonCopyable)
% Chart axes.
HandleLine(1,1) % Handle of the line object
end
properties
Axes
XData double {mustBeReal}
YData double {mustBeReal}
ZData double {mustBeReal}
end
methods (Access = protected)
function setup(this)
this.Axes = getAxes(this);
% Create line handle
this.HandleLine = plot3(this.Axes, NaN, NaN, NaN, '-o');
end
function update(this)
this.HandleLine.XData = this.XData;
this.HandleLine.YData = this.YData;
this.HandleLine.ZData = this.ZData;
end
end
end
And then, if I try creating two of them:
a = TestChart('XData', [0 0], 'YData', [0 0], 'ZData', [1 2]);
b = TestChart('XData', [0 0], 'YData', [0 0], 'ZData', [5 8]);
I get the error saying "Adding TestChart to axes is not supported. Turn hold off.".
Is it possible to create custom graphics object that can be plotted several times in the same axex ?
Thanks in advance!

non-homogenous grouped data in MATLAB plotyy()

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.

How do I end a function that is using callbacks in Matlab?

I am trying to write some code that allow me to 'drag and drop' some lines over a figure so that I can obtain a particular coordinate: 'pt'. I am adapting some code from the internet that uses call backs, which is doing what I want it to do. However, I am unable to end the function or transfer the coordinate 'pt' to another function. I have attempted to use 'return', but it doesn't seem to work. I also tried to use 'while', but it caused Matlab to crash.
I am new to programming, so detailed suggestions would be appreciated.
function [pt] = movelines
global pt;
f=figure;
aH=axes('Xlim',[0, 1],'YLim', [0 1]);
key=0;
H=line([0 1], [0.5 0.5], ... %from [x1 x2] to [y1 y2]
'color', 'yellow',...
'linewidth', 3);
V=line([0.5 0.5], [0 1], ... %This line sets the length of the line. From [x1 x2] to [y1 y2]
'color', 'red', ...
'linewidth',3,...
'ButtonDownFcn', #startDragFcn);
set(f, 'WindowButtonUpFcn',#stopDragFcn);
mov_cancel = uicontrol(f,'Style','pushbutton',...
'Position',[30,130,110,30],...
'String','(cancel)',...
'BusyAction','cancel',...
'TooltipString','BusyAction = cancel',...
'Callback',#funct_cancel);
function startDragFcn (gcbo,eventdata,handles)
set(f,'WindowButtonMotionFcn',#draggingFcn)
end
function draggingFcn (gcbo,eventdata,handles)
pt=get(aH,'CurrentPoint');
set(V,'Xdata',pt(1)*[1 1]);
set(H,'Ydata',pt(1,2)*[1 1])
end
function stopDragFcn (gcbo,eventdata,handles)
set(f,'WindowButtonMotionFcn','');
end
function funct_cancel (gcbo,eventdata,handles)
key=key+1
return
end
end
To use the code, click and hold the vertical line. The function is supposed to end when the cancel button is clicked.
You can use the Matlab function waitfor to wait for a uicontrol object to close. I've also added functionality to stop allowing the user to drag the lines around after you cancel.
function [pt] = movelines()
f=figure;
enabled = 1;
aH=axes('Xlim',[0, 1],'YLim', [0 1]);
key=0;
H=line([0 1], [0.5 0.5], ... %from [x1 x2] to [y1 y2]
'color', 'yellow',...
'linewidth', 3);
V=line([0.5 0.5], [0 1], ... %This line sets the length of the line. From [x1 x2] to [y1 y2]
'color', 'red', ...
'linewidth',3,...
'ButtonDownFcn', #startDragFcn);
set(f, 'WindowButtonUpFcn',#stopDragFcn);
mov_cancel = uicontrol(f,'Style','pushbutton',...
'Position',[30,130,110,30],...
'String','(cancel)',...
'BusyAction','cancel',...
'TooltipString','BusyAction = cancel',...
'Callback',#funct_cancel);
function startDragFcn (gcbo,eventdata,handles)
if enabled
set(f,'WindowButtonMotionFcn',#draggingFcn)
end
end
function draggingFcn (gcbo,eventdata,handles)
pt=get(aH,'CurrentPoint');
set(V,'Xdata',pt(1)*[1 1]);
set(H,'Ydata',pt(1,2)*[1 1])
end
function stopDragFcn (gcbo,eventdata,handles)
set(f,'WindowButtonMotionFcn','');
end
function funct_cancel (gcbo,eventdata,handles)
key=key+1
enabled=0;
delete(mov_cancel);
end
waitfor(mov_cancel);
end
So I assume there is a reason that you aren't using ginput. If you haven't considered it then you should, see: http://uk.mathworks.com/help/matlab/ref/ginput.html
So assuming you want to proceed with your current approach:
Your code at the moment seems to terminate fine, do you mean that you want to close the figure. If so you can do this using delete(gcf) within your callback function.
In terms of returning the current point you could declare pt as a global variable. You can then use it anywhere you want. Remember to declare a global variable at the beginning of each function you use it in.
function draggingFcn (gcbo,eventdata,handles)
global pt;
pt=get(aH,'CurrentPoint');
set(V,'Xdata',pt(1)*[1 1]);
set(H,'Ydata',pt(1,2)*[1 1])
end
Hope I've answered your questions there. If you can though I would seriously consider ginput

Set equal limits for y-axis for two figures

How can I make the vertical axes of two plots equal?
For example:
a = [1 2 3; 21 1 3; 4 2 3; 4 5 6]
After plotting plot(a(1, :)) I get the following figure:
I have done some simple operations:
[U E V] = svd(a);
figure(2);
plot(U(1,:))
And get another figure:
How do I make the y-axis limits of both plots equal? Is it with the axes equal command?
UPDATE:
I've used the following commands:
figure (1)
ylim([0 3])
plot(a(1,:))
figure (2);
ylim([0 3])
plot(U(1,:))
But get the same result...
You can use ylim to force limits on the y-axis. For example:
figure(1)
%// Some plotting...
ylim([0 3])
figure(2)
%// Some more plotting
ylim([0 3])
This ensures that the y-axis is limited to the range [0, 3] in both plots. You can do the same for the limits of the x-axis with the command xlim.
Also note that if you want to set the limits for both axes at once, instead of using xlim and ylim (two commands), you can use axis (one command).
you can use the ylim or xlim functions.
You can clone the limits of one plot to another plot in this fashion:
h1 = figure;
% do first plot...
h2 = figure;
%do second plot...
% set first figure as active
figure(h1);
%get limits properties of the axes that are drawn in Figure 1
xL = get(gca, 'XLim');
yL = get(gca, 'YLim');
%switch to second figure and set it as active
figure(h2);
%set axis limit properties of Figure 2 to be the same as in Figure 1
set(gca, 'XLim', xL);
set(gca, 'YLim', yL);

How can I specify to which figure a plot should go?

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.