I want to delete a plot and its colorbar ( actually I want to delete everything in a plot, but that seams to be almost impossible, see make axes invisible or delete plot completely)
I do this:
In the plot
hplot = pcolor(xAxis, yAxis, Data2D);
hcb = colorbar;
handles.image.hColorbar = hcb;
handles.image.hplot = hplot;
guidata(handles.output,handles);
later in the gui:
if (isfield(handles,'image') && isfield(handles.image,'hplot'))
if (handles.image.hplot~=0)
delete(handles.image.hplot);
delete(handles.image.hColorbar);
handles.image.hplot = 0;
end
end
It works for delete(handles.image.hplot) but fails for handles.image.hColorbar with invalid handle - why?
This snippet works fine here...
In general, it is advisable to check for ishandle() on both objects, so that you don't have to set handles.image.hplot = 0. Since delete has made the handle invalid, it will never pass the ishandle check until you re-assign a new, valid handle to it.
If the code doesn't pass the ishandle() tests, it means it was deleted already, so no need to delete it again.
Related
I'm refactoring an existing (working) MATLAB code, in particular I'm extracting a new class from a piece of structured code that creates a figure, and when I do that, I get an error caused by axes of the figure getting deleted (my variable now says it contains a handle to deleted axes).
In more detail, the current version of the code does something like this:
Overlay = figure
overlayAxes = subplot(1, 2, 1, 'Parent', Overlay)
... (other stuff)
imshow(... other parameters ..., overlayAxes)
(I'm mentioning "other stuff" and "other parameters" to clarify the imshow line is not directly above the overlayAxes assignment, just in case you think I should look for anything in particular before the call to imshow)
This works fine. My refactor is consists in moving the creation of Overlay to a class (in other words, make it more "OOP-like"). As a first step, I moved it to a class like this:
classdef MyGUI < handle
properties(SetAccess = public)
Overlay
overlayAxes
end
methods
function obj = MyGUI()
obj.Overlay = figure;
obj.overlayAxes = subplot(1, 2, 1, 'Parent', obj.Overlay);
end
end
end
And then I referenced this new class where Overlay was originally created like this:
GUI = MyGUI;
Overlay = GUI.Overlay;
overlayAxes = GUI.overlayAxes;
(I made those two variable assignments so I didn't have to change the rest of the code right now - because it references Overlay not GUI.Overlay - in particular the call to imshow)
So, when I do this, the call to imshow fails saying:
Error using imshow>validateParent (line 375)
HAX must be a valid axes handle.
As it turns out, when I debug and inspect overlayAxes, it says it contains a handle to deleted axes.
I've read some articles explaining that axes get deleted when new figures are created and such, but the only change I'm making is converting the figure creation from a local variable to a class property, so I don't feel like is something related to side-effects of calling plot functions again or anything like that, but maybe something about passing by reference, object lifecycle, or something that I'm missing completely, not really sure.
Why are my axes getting deleted? Thanks!
I read the blog post on assigning transparency to plot markers. I tried the code on a simple example and all was well. Then I tried a tight loop, plotting a single point at a time (doing this to assign a different color to each point in the graph), and invariably within a few loop cycles, when I grab the "plothandle.MarkerHandle", it's empty. In these cases, the class of this empty object is Matlab.graphics.GraphicsPlaceholder
while when the operation is successful, the class is:
matlab.graphics.primitive.world.Marker
The basic loop follows. colormatrix assigns a [r,g,b] color to each data point.
hold on
opacity = 0.5;
for jk = 1:numel(idx
tmph = plot(foox(jk),fooy(jk),'o','color',colormatrix(jk,:) );
tmpk = tmph.MarkerHandle;
tmpk.FaceColorData = uint8(double(tmpk.EdgeColorData).* [1,1,1,opacity]');
tmpk.EdgeColorData = uint8(double(tmpk.EdgeColorData).* [1,1,1,opacity]');
end
I've tried things like clearing variables every loop, putting in a delay timer, and so on, with no luck. I'm using Matlab R2015a.
EDIT: here's a simple example. What I seem to be finding is that if I run the entire script, it always fails. If I break it into two pieces where noted and execute the second section with a separate key stroke (ctrl-enter or selectall/F9 in the IDE editor), everything works. And yes, I'm aware that "undocumented features" are risky , but since MathWorks still hasn't figured out that allowing transparency -- and indexed color assignments -- are good things for the plot function, I'm still looking for a better workaround than using patch to draw each data point.
figure
xfoo = 1:10;
yfoo = 2*xfoo;
tmph = plot(xfoo,yfoo,'p','color',[1,0,1]);
hold on
opacity = 0.7;
% wait a while here.
tmpk = tmph.MarkerHandle;
tmpk.FaceColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
tmpk.EdgeColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
The fact that the script seems to work if you wait a bit between the plot and the retrieval of tmph.MarkerHandle suggests that you have the same issue that was reported on the blog by a user running R2014b. Yair suggested to call drawnow after the plot:
figure
xfoo = 1:10;
yfoo = 2*xfoo;
tmph = plot(xfoo,yfoo,'p','color',[1,0,1]);
hold on
opacity = 0.7;
drawnow;
tmpk = tmph.MarkerHandle;
tmpk.FaceColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
tmpk.EdgeColorData = uint8(double(tmpk.EdgeColorData).*[1,1,1,opacity]');
The workaround didn't work for a user running R2015a, which doesn't sound promising, but the fact that waiting seems to help for you, is encouraging.
I am trying to animate a clock hand's movement using MATLAB. I created 'draw_clock()' program/script in a file named 'draw_clock.m' that goes something like this.
function draw_clock()
set_figure();
draw_clock_hands();
end
function set_figure()
figure;
hold on;
axis off;
title('Clock');
end
Then I have a script file named 'animate_clock.m' that has something like this:
hours = 0:12;
minutes = 0:59;
for i = 1:numel(hours)
for j = 1:numel(minutes)
draw_clock();
pause(0.05);
refresh;
end
end
When I run 'animate_clock.m', new window/clock figure for every frame is opened instead of redrawing on the same canvas/figure. I understand why this is happening because 'set_figure()' is being called every time 'draw_clock()' is called. I'm new to MATLAB, so if there's a way to stop creating new figure with the code skeleton above. I guess if I can detect if there's a figure object already opened, then I can skip calling 'set_figure()' inside 'draw_clock()' next time it is being called?
Thank you in advance for your answers!
So after searching and reading the doc a bit, I think there are a couple of different ways to detect if a matlab figure already exists. One that I found useful (and relatively simple) is to:
- assign the 'Name' property to the figure window
- find if an object with the assigned name exists using 'findobj(...)' method
- if figure already exists, use 'hold on' to reuse the old figure
- else, create a new figure with the name 'figure('Name', 'foo figure')'
For my case, 'set_figure()' method will become something like this:
function set_figure()
fig_name = 'My Clock';
if isempty(findobj('Name', fig_name))
figure('Name', fig_name);
end
hold on;
axis off;
end
Hope someone can come and improve it to become more robust. :)
Today i tried adding a slider below my graph, so different graphs would be drawn when you slide it. Eventually i got all of this to work perfectly fine, however i still have two small issues.
On top of the figure with the slider, the figure toolbar is gone. It can easily be added by clicking view -> figure toolbar at the top in the figure itself. However to do this everytime is a bit tedious. And when i google'd for the problem, the results where are all guides to create custom toolbars. I just want to add the default toolbar back, it was fine. But i do not know how to do that. Typing 'uitoolbar' gives an empty one. But i am not sure how to fill it with the default icons.
And the second problem i ran into;
The main script calls in the end for a function, this function then creates the new graph with the slider. However herefore i needed to transfer the matrix of data to plot from the main script to the function, so i made the matrix a global variable. However as soon as the function is called, matlab gives me this error (once for each global variable):
> In xxxx at 270
Warning: The value of local variables may have been changed to match the globals.
Future versions of MATLAB will require that you declare a variable to be global before you use that variable.
Before i call the function i type
global xL yL zL p
which are the data required to plot. Then the first line in the function file is this same line again. The data seems to be transmitted fine and the graph shows the correct plot.
Is this some error i can just ignore then? Since everything works as it should? Or what does it mean exactly?
Ok here are my 2 cents:
1) From what I understand the simplest way to fetch the toolbar would be using findobj and then make it visible:
hToolBar = findobj('Type','uitoolbar');
set(hToolBar,'Visible','on');
You can also get the toolbar's properties using "get". Here is what it looks like from a simple script I ran:
get(hToolBar)
hToolBar =
0.1890 %// don't worry about that number; it's the handle for the toolbar.
BeingDeleted = off
ButtonDownFcn =
Children = [1.18896]
Clipping = on
CreateFcn =
DeleteFcn =
BusyAction = queue
HandleVisibility = on
HitTest = on
Interruptible = on
Parent = [1]
Selected = off
SelectionHighlight = on
Tag =
Type = uitoolbar
UIContextMenu = []
UserData = []
Visible = off
I don't know why it disappears though.
2) You might get rid of those global variables if you sent your data as inputs to your function is that a possibility?
For example:
function PlotData(xL,yL,zL,p)
%// Your code here
Hope that helps!
I try to remove the Matlab-given units from this plot but I don't find a way:
figure(1)
hold on
set(gcf,'PaperUnits','centimeters',...
'PaperSize',[15 9],...
'PaperPosition',[0 0 15 9]);
pzmap(LB); sgrid; grid on; axis equal;
title('');
xlabel('\sigma [rad/s]')
ylabel('\omega [rad/s]')
hold off
After that commands the xlabel looks like this: \sigma [rad/s] (seconds^-1). The seconds comes with pzmap. How can I remove them?
I found, some strange behavour:
If generate code by the figure plot manager I get this:
% Create xlabel
xlabel('\sigma [rad/s] (seconds^{-1})','Units','pixels');
Why???
Now I get it - without pzmap/pzplot
pol = pole(sys)
figure(1)
plot(real(pol(:)),imag(pol(:)),'x')
title('');
xlabel('\sigma [rad/s]');
ylabel('\omega [rad/s]');
sgrid
pzmap is a high-level convenience function, but it's not the best choice for this (it's also stored in a folder of obsolete functions in R2013a, so it may get marked for official removal in the future). Instead, let's create an example plot using pzplot directly instead of pzmap. This is still a plot function that does a lot under the hood, but it returns a handle, h, to the plot:
sys = rss(3,2,2);
h = pzplot(sys);
sgrid;
axis equal;
We can via the options of a pzplot with getoptions:
p = getoptions(h)
To set the labels and units as you desire, you might try this, using setoptions:
p.Title.String = '';
p.XLabel.String = '\sigma';
p.YLabel.String = '\omega';
setoptions(h,p);
I believe that the units of 'seconds-1' that the plot displays is equivalent to the 'rad/s' that you want to specify. I know that the two look is very different (I prefer being specific about radians myself), but that's a disadvantage of using such a plot function that tries to do everything for you. If you wanted to remove the default string or add another option, you'd likely have to do some low level hacking. An easier way around, might be to use the "Generate Code..." command ("Generate M-File..." in older versions") under the "File" menu in the figure's toolbar and edit the plot labels there (there's also a programmatic option for this on the File Exchange). Or you could output to postscript and edit that.
Alternatively, you can use pzoptions to create a list of options to pass to pzplot or pzmap (undocumented in the latter case):
p = pzoptions;
p.Title.String = '';
p.XLabel.String = '\sigma';
p.YLabel.String = '\omega';
sys = rss(3,2,2);
pzplot(sys,p);
sgrid;
axis equal;
You'll see that that for some reason the text size is much smaller in this case. pzplot and pzmap must set the font size to 10 themselves. You could easily do this.
Fore more on customizing this and related Control toolbox plots, see this article.
After intense low-level digging, there is actually a pretty simple way to override the default behavior.
p = pzplot(sys);
p.AxesGrid.XUnits = 'rad/s';
p.AxesGrid.YUnits = 'rad/s';
Changes appear to take effect immediately. I have even tried setting the value to nothing, i.e.
p.AxesGrid.XUnits = '';
and it effectively removes the annoying parenthesis with the units. Technically, matlab creates a custom-class element they store under the name AxesGrid in the resppack.mpzplot class instance, with some standard LTI-behavior. You can probably work around some stuff by "injecting" a script with the same name as one of the standard library functions, so that it will be called instead, and change things in there, but this is the closest I have come to removing those annoying units in a few lines.
As a side info, the AxesGrid object is initialized in
...\controllib\graphics\#resppack\#pzplot\initialize.m
should you want to check it out.