Why won't this axes object display correctly in MATLAB? - matlab

I am writing two small psychoacoustic testing applications in MATLAB. The first one works without problems but the second one doesn't, and I just can't figure out why.
Here is the problem: the axes object is created, but it is empty.
failed_axis http://dl.getdropbox.com/u/98854/help.png
Here is the code that creates this figure and axes:
hFig = figure('dockcontrols','off','menubar','none', ...
'name','choose the better sounding file', ...
'numbertitle','off','position',[0,0,700,500], ...
'resize','off','toolbar','none','units','normalized', ...
'color',[.8,.8,.8]);
progress_idc = axes('position',[.1,.8,.8,.05],'box','on','parent',hFig,...
'xlim',[-.03,1.03],'xtickmode','manual','xtick',[], ...
'xticklabelmode','manual','xticklabel',[], ...
'ylim',[-1,1],'ytickmode','manual','ytick',[], ...
'yticklabelmode','manual','yticklabel',[], ...
'nextplot','add');
And here is the code that plots in this axes (the function is called regularly by a timer):
function replot(varargin) % this is a nested function
cla;
% plot start_indicator
plot([x_start,x_start],[-.7,.7],'k','linewidth',2);
fill([x_start,x_start-.02,x_start-.02],[0,-.7,.7],[0,0,0]);
% plot stop_indicator
plot([x_stop,x_stop],[-.7,.7],'k','linewidth',2);
fill([x_stop,x_stop+.02,x_stop+.02],[0,-.7,.7],[0,0,0]);
% plot play_position
plot([x_play,x_play],[-1,1],'r');
drawnow;
end
This is what it looks like if it works:
proper_axis http://dl.getdropbox.com/u/98854/help2.png
Do you have any idea what is going wrong here?

I ran the code you included above and got the correct output.
If I had to take a wild guess as to what the problem is, I'd guess that you may be creating other axes in your application that you are not listing above, or that you may have other axes not related to the application open at the time the application is running. When you plot your objects in the function replot, you are by default plotting them to the currently active axes. If you have multiple axes open, the plotting may therefore be going on in the wrong set of axes.
One suggestion I would make is to explicitly specify what the parent axes object should be in your calls to PLOT and FILL. If you add the arguments ...,'Parent',progress_idc); to your plotting calls, it will ensure that the correct axes is always used. I make a habit of always specifying the parent axes object instead of assuming that the currently active axes will always be the one I need it to be.

I finally found the (dumb) answer. The title accidentally had the same position as the plot axis. Due to some rendering-details of Matlab, it obscures the whole axis except for the rightmost and bottommost line of pixels, which makes the axis look "empty".
Oh, what a dumb error.

Related

Why is my axis position data changing when I use copyobj in MATLAB?

I'm creating a plot in Matlab with two axes, and I want to copy the entire figure to a smaller window with a specific size, and then save it (this makes it easier to format plots for display in Word documents). The function I'm using is as follows:
function printStandardFigure(figInput,filename)
dpi = 300;
newFig = copyobj(figInput,groot);
newFig.Units = 'inches';
newFig.InnerPosition = [1,1,6.5/2,6.5/2];
print(filename,'-dpng',['-r',num2str(dpi)]);
close(newFig);
end
In theory, this should create a copy of the figure I've made with all its axes, etc. identical to the original but resized to fit the new window size. What actually happens is that the 'Position' property for one of the axes gets reset to [0, 0, 1, 1], but the other one displays just fine. This still happens even when I set the ActivePositionProperty to 'position', which normally causes the axis to hold the Position property constant.
I've also tried using copyobj to copy just the two axes over to the new figure, but I have similar issues with resizing, and this doesn't import any legends even though they are set as children of the axes.
This code works just fine if I only have one axis, so why does the second axis cause it to screw up? I've tried making the original figure have the same aspect ratio as the new one, and I've tried setting their sizes to be exactly equal using the InnerPosition property. I can't figure out what's going on and Matlab's documentation isn't helping.
Here's the original chart
And here's what the output of my function looks like.
Edit: Cris Luengo in the comments suggested I try the subplot command, which I thought was a good idea, so I tried it out. However, the export process is still causing a problem Here are the original and the exported versions of the plot when I do that. The original figure was created to have the same dimensions as the exported plot, just to make sure that resizing the axes wasn't causing the issue. I also get the same problem when I remove lines 6 and 7 from the export function (where I set the size of the new figure).

Matlab skipping plots (uncertainty)

I have a sequence of finding fits for data (cd to folder, read and fit the data) and subsequently plotting them in a loop.
I observe that few plots are done incorrectly, skipped and added in subsequent plots. A four second pause between each plots seems to solve this issue.
I assume everything is sequential in Matlab, meaning subsequent commands wait until current command is finished. I believe this is not the way happening now. I believe using pause is not the best solution. Can someone provide a fix for this?
A set of subsequent plots without the pause (solid line is a fit of datapoints on the fly):
The same plots with pause of 4 seconds:
subplot, and most other functions that generate graphics objects, provide a handle to the generated graphics object that you can use to address the object explicitly with functions like plot.
If an explicit axis handle is not provided to a plotting function, it will use the current axes, which can very often lead to issues like these. So much so that it's caveated in the documentation:
User interaction can change the current axes or chart. It is better to assign the axes or chart to a variable when you create it instead of relying on gca.
So rather than doing:
axes
plot(1:10)
You should do the following:
ax = axes;
plot(ax, 1:10)

Set figure to not be target for next plot

I'm working on a custom progress monitor with some graphs. I've noticed that Matlab's waitbar creates a figure with some special properties so that if you do
plot(rand(100,1));
wb = waitbar(0);
plot(rand(100,1));
the second plot ends up replacing the first plot and not in wb. Is there a property I can set so that when I create my progress monitor and then plot something afterwards, the graph doesn't end up in my figure?
To be clear, I'm trying to have
plot(rand(100,1));
temp = MyProgressBar();
plot(rand(100,1));
create a figure for the first plot, create a different figure in the second line, then plot a new graph in the third line.
To protect your progress bar figure against subsequent plotting operations, I would set the 'HandleVisibility' property of its axes to 'off'. That should prevent it ever becoming the current axes, thus keeping subsequent plotting commands from modifying or adding to it. It's a good practice for stand-alone figures/GUIs in general that you turn off the handle visibility of all objects (figure, uicontrols, etc.) in this way to insulate them against being modified by outside code. This is almost certainly what is done in the code for waitbar.
As an additional aside, it's good practice to target your plots to a given axes by passing the axes handle as the first argument. You also have to make sure that, if you want new plots to be added to existing plots, you use things like the hold command first. Here's how I'd rework your example, assuming you want the two plots to appear on the same axes:
plot(rand(100,1)); % Creates new figure and axes
hAxes = gca; % Get the axes handle
hold on; % Allow subsequent plots to be added
temp = MyProgressBar();
plot(hAxes, rand(100,1)); % Will be added to the first plot axes

Unable to plot multiple data sets in GUIDE

I'm using GUIDE to display a plot within an axis that contains two data sets: the original signal and the average of the signal, but for some reason it seems to only plot one.
The axis is designated as m_graph and the data sets are avg and signal, which both share time.
plot(handles.m_graph, time,signal)
hold on
plot(handles.m_graph, time, avg)
When I compile the program, only the average is plotted. It seems to skip over the original signal or reset the axis. I've tried plotting just the signal so I know the data is fine.
I feel like I am missing something, maybe the set function?
Sorry my reasoning was a bit wrong; it applies to the current selected axes (it does not parent to the Figure).
However, using axes(h) followed by hold on or just hold(h,'on') will either switch the focus to the axes then turn hold on or turn hold on for a specified axes, respectively.

Matlab: How to obtain all the axes handles in a figure handle?

How do I obtain all the axes handles in a figure handle?
Given the figure handle hf, I found that get(hf, 'children') may return the handles of all axes. However, the Matlab Help suggests that it may return more than just the axes handles:
Children of the figure. A vector containing the handles of all axes, user-interface objects displayed within the figure. You can change the order of the handles and thereby change the stacking of the objects on the display.
Is there any way to obtain only the axes handle in the figure handle? Or how do I know if the handle returned by get(hf, 'children') is an axe handle?
Thanks!
Use FINDALL:
allAxesInFigure = findall(figureHandle,'type','axes');
If you want to get all axes handles anywhere in Matlab, you could do the following:
allAxes = findall(0,'type','axes');
EDIT
To answer the second part of your question: You can test for whether a list of handles are axes by getting the handles type property:
isAxes = strcmp('axes',get(listOfHandles,'type'));
isAxes will be true for every handle that is of type axes.
EDIT2
To select only axes handles that are not legends, you need to cleanup the list of axes (ax handles by removing all handles whose tag is not 'legend' or 'Colorbar':
axNoLegendsOrColorbars= ax(~ismember(get(ax,'Tag'),{'legend','Colobar'}))
Jonas' solution didn't work for me, because there were some handles referring to legends. Surprisingly, legends seem to be implemented as axes, at least in Matlab 2010a.
Here is a solution if you only want the axes, not any legends or other stuff.
axesHandles = get(fig, 'Children');
classHandles = handle(axesHandles);
count = length(axesHandles);
isNotInstanceOfSubtype = false(1, count);
for i = 1:count
isNotInstanceOfSubtype(i) = strcmp(class(classHandles(i)), 'axes') == 1;
end
axesHandles = axesHandles(isNotInstanceOfSubtype);
The script works by sorting out handles which reveal to be of a sub-type of type axes, for example scribe.legend.
A warning for those trying to improve the above code snippet: using something like
classHandles = cellfun(#(x) handle(x), axesHandles)
might not work as intended:
??? Error using ==> cellfun
scribe.legend type is not currently implemented.
"Jonas" and "tm1" have answers that work for some. However, as tm1 pointed the issue, there are several items inside type 'axes'.
To exactly refer to the legend or axes itself (there may exist other items), you need to differentiate them, using their characteristic properties.
In my example, I opened "property editor" and looked for differing properties for axes and legend (since they both belong to "type, axes"). I was trying to copy my axes and its legend:
copied_axes = findobj(temp_fig,'type','axes','Tag','');
copied_legend = findobj(temp_fig,'type','axes','Tag','legend');
Instead of 'Tag' property, I also could use an other property from the "Property Inspector". The thing is, they must differ. Most of their properties are the same.
The solution by #tm1 is excellent. Mine is a little less complicated (if you're ok with functional programming):
% initialize `fig` somehow, i.e., "fig=gcf()" for the current figure or
% "fig=get(0,'children')" for all open figures; can be vector or scalar.
ax = findall(fig, 'type', 'axes');
ax = ax(arrayfun(#(i) strcmp(class(handle(i)), 'axes'), ax));
ax will contain only plot axes. This works because the class of a legend or colorbar object is different from axes.
Edit #Jonas points out a potential improvement to filter the results of findall, because at least legends and colorbars seem to have non-empty Tag properties: replace the last line in the above code snippet with
ax = ax(strcmp('', get(ax, 'Tag')))
Both these techniques are kludgy and may break in the future (a comparison against ggplot2 or Bokeh might be interesting).