Why is get(gcf, 'children') inconsistent for the same figure handle? Messes up my bode plot when calling my function twice to draw into the same figure.

I have a method that makes a bode plot using bode(sys). It then draws an auxiliary line into the magnitude part of the bode plot by using
childrenHnd = get(gcf, 'children')
magnAxesHnd = childrenHnd(3);
axes(magnAxesHnd);
plot(get(magnAxesHnd, 'XLim'), [0, 0])
which works fine. As you can see, the handle for the magnitude axes is the third element of childrenHnd.
Now I'd like to use the same method to draw another frequency response in the same figure. However, suddenly, when I use the figure handle to get to the magnitude axes handle, it's the second element of childrenHnd. See the following example:
%%plot1
figure(1)
hold on
bode(H1)
childrenHnd = get(gcf, 'children')
magnAxesHnd = childrenHnd(3);
axes(magnAxesHnd);
plot(get(magnAxesHnd, 'XLim'), [0, 0])
hold off
%%plot2
figure(1);
hold on
bode(H2)
childrenHnd = get(gcf, 'children')
magnAxesHnd = childrenHnd(3);
axes(magnAxesHnd);
plot([1 10], [10, 10])
Using this code, my second auxiliary line is drawn in the phase part of the bode plot. Using childrenHnd(2) places the auxiliary line in the intended magnitude part.
Therefore, I can't reuse my method to draw correctly into the same figure. Any good solutions?

4 Comments

"Any good solutions?"
Yes: stop using gcf and looking for children of graphics objects! The much simpler and totally reliable solution: return and use explicit graphics handles for any object that you need to refer to.
All graphics functions that plot/create something return figure/axes/line/patch/... object handles: use them. Almost all graphics functions accept an input argument for specifying the parent object: use it. Done, problem solved by writing better, clearer, and simpler code. Here is a simple example:
fgh = figure(...);
axh = axes(fgh,...);
lnh = plot(axh,...);
Simple stupid commands like gcf and clc are for playing around in the command window. Do not use them in real code that you actually want to work reliably.
@Stephen
Hey, thanks for the tip! In my case, that means I should not be using bode()? Because I think the only way to get the axesHnd for the magnitude part of the bode plot created by bode() is looking for the children of my figure.
@Kai-Jimmy Shen: bode is one of the MATLAB functions that unfortunately does not accept/return useful graphics handles. So you are right: looking at the figure children might be the only way to get the required axes handles. However you should not rely on the order of the handles, instead you should check what features they have and pick the correct one. For example something like:
  1. obtain all figure children that are axes
  2. check their xlabel properties
  3. pick the axes with xlabel starting with 'Frequency'.
I have not checked this, and you will have to find some feature that uniquely identifies the correct axes. It also illustrates why it is so much simpler to obtain/access explicit graphics handles when possible, so you should still avoid gcf and obtain the figure handle directly from figure.
Alternative: if bode is defined in an Mfile then it may be possible for you to copy it and adapt it for your own needs. This might be a simpler option than mucking around with figure children. Ensure that you copy it to your personal working directory and do not alter the original file.
@Stephen
Thanks again for your input! Both your solutions seem to be good, but I think for me and my current Matlab skills, it might be easier just not to rely on bode(). I will look into how to plot a bode diagram without the use of bode().
Cheers

Sign in to comment.

 Accepted Answer

To plot the values bode calculates as normal subplot plots, call bode with output arguments:
[mag,phs,wout] = bode(sys);
Magnitude = squeeze(mag);
Phase = squeeze(phs);
figure(1)
subplot(2,1,1)
plot(wout,20*log10(Magnitude(1,:)))
title('Magnitude (dB)')
grid
subplot(2,1,2)
plot(wout,Phase(1,:))
title('Phase (°)')
grid

2 Comments

Thanks for your reply! Getting the data from bode() and using subplot() works well, leaving me with all the handles.
For anyone interested, I'm using something like this now:
[mag, phase, w] = bode(H, {w_lower w_upper});
f = w/(2*pi);
figure(1)
% Magnitude
filMagAxHnd = subplot(2,1,1);
title('Bode Diagramm')
hold on
grid on
set(filMagAxHnd, 'XScale', 'log')
xlabel('Frequenz (Hz)')
ylabel('Amplitude (dB)')
plot(f, 20*log10(squeeze(mag)))
% Phase
filPhaseHnd = subplot(2,1,2);
hold on
grid on
set(filPhaseHnd, 'XScale', 'log', 'YTick', [-270 -180 -90, 0, 90, 180, 270])
xlabel('Frequenz (Hz)')
ylabel('Phase (°)')
plot(f, squeeze(phase))
Addressing the original question, it seems like if you make any object the current object (e.g. when plotting into the magnitude axis), this object is moved to the the 2nd position of the figure's children, with all other objects moving down one position (also happens when using 'legend'). Therefore, after using bode(), the last current axes was the phase axes, moving it in position 2 of the figure's children. After using the magnitude axes to plot my auxiliary line, the magintude axes is moved to the 2nd position.

Sign in to comment.

More Answers (0)

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!