Graphics Incompatibilities in Control System Toolbox between R2024a and R2024b

5 views (last 30 days)
A1 = 1; wp1 = 10;
A2 = -2; wp2 = 20;
s = tf('s');
H1 = A1 / (1 + s/wp1); H2 = A2 / (1 + s/wp2);
H = H1 + H2;
figure;
bp = bodeplot(H, H1, H2);
hLines = findobj(gcf, Type='line');
set(hLines, LineWidth=2); % not working in R2024b?
set(hLines(6), LineWidth=6, DisplayName='H2'); % not working in R2024b?
set(hLines(3), LineWidth=6, DisplayName='H2'); % not working in R2024b?
set(findall(gcf, 'Type', 'axes'), LineWidth=1.5, Box="off", fontsize=12); % not working in R2024b?
% Any correct/equivalent/recommended practice in R2024b?
figure;
pzmap(H, H1, H2);
set(gca, YTick=[], Box="off", LineWidth=1.5, XAxisLocation='origin', YAxisLocation='origin');
% get an R2024b Error using controllib.chart.PZPlot/set Unrecognized property YTick for class PZPlot.
% Any correct/equivalent/recommended practice in R2024b?
R2024a:
R2024b:
The "Version History" of "BodePlot" and "PZPlot" does point out changes in "gca", but for the "Chart Object" mentioned in it, I Googled it and couldn't find the relevant documentation, so I don't know how to get axes from Chart Object. Since the R2024b version is too new, I don't know where to find the information.
  4 Comments
Rarity Brown
Rarity Brown on 27 Sep 2024
Edited: Rarity Brown on 27 Sep 2024
I apologize for the imprecise wording and unclear code in my previous comment.
The support's original statement was, "It appears to be a bug with the Live Editor. I will report this to our development team for a fix in future releases. In the meantime, please use a .m script as a workaround, which should allow you to change figure properties without issues."
I have provided another similar code snippet for testing purposes, along with screenshots of the results when running the code in a .m file and in the Live Editor (.mlx). Therefore, I believe this can be considered a bug? Or perhaps the old API wasn't completely removed, resulting in two different behaviors?
A1 = 1; wp1 = 10;
A2 = -2; wp2 = 20;
s = tf('s');
H1 = A1 / (1 + s/wp1); H2 = A2 / (1 + s/wp2);
H = H1 + H2;
figure;
bp = bodeplot(H, H1, H2);
hLines = findobj(gcf, Type='line');
set(hLines, LineWidth=2); % not working in R2024b?
set(hLines(6), LineWidth=6, DisplayName='H'); % not working in R2024b?
set(hLines(3), LineWidth=6, DisplayName='H'); % not working in R2024b?
set(findall(gcf, 'Type', 'axes'), LineWidth=1.5, Box="off", fontsize=12); % not working in R2024b?
.m running in R2024b:
.mlx:
Andrew Ouellette
Andrew Ouellette on 27 Sep 2024
Unforunately, this is a result of control plots being more permissive of undocumented behaviors before R2024b. Workflows including "findobj" and "findall" happened to work with the plots before R2024b, but this behavior was never documented. With the switch to charts in R2024b, many workflows including "findobj" and "findall" still work for standalone charts; however, these workflows cannot be serialized by charts, and are therefore lost during save/load operations and while using the Live Editor.

Sign in to comment.

Accepted Answer

Andrew Ouellette
Andrew Ouellette on 13 Sep 2024
Hello,
You can achieve most of this behavior by interacting with the new chart API.
Give the following a go:
A1 = 1; wp1 = 10;
A2 = -2; wp2 = 20;
s = tf('s');
H1 = A1 / (1 + s/wp1); H2 = A2 / (1 + s/wp2);
H = H1 + H2;
figure;
bp = bodeplot(H, H1, H2);
bp.Responses(1).LineWidth = 2;
bp.Responses(2).LineWidth = 2;
bp.Responses(3).LineWidth = 6; %Name is already H2!
bp.AxesStyle.Box = 'off';
bp.AxesStyle.FontSize = 12;
%You cannot set LineWidth through API currently, here is a workaround
ax = findall(bp,'Type','axes'); %Undocumented, may change in a future release
set(ax,LineWidth=1.5);
figure;
pp = pzplot(H, H1, H2);
pp.AxesStyle.Box = 'off';
%You cannot set the rest through API currently, here is a workaround
ax = findall(pp,'Type','axes') ;%Undocumented, may change in a future release
set(ax,YTick=[], LineWidth=1.5, XAxisLocation='origin', YAxisLocation='origin');
  3 Comments
Andrew Ouellette
Andrew Ouellette on 30 Sep 2024
For the first point, your interpretation is correct- the API expects one style per response, and therefore doesn't give you the flexibility to set different marker sizes for poles and zeros. There are a couple workarounds here:
1) You can use "findall" in the following manner, but again, this will not work in the Live Editor or after saving & loading.
% common part:
A1 = 1; wp1 = 10;
A2 = -2; wp2 = 20;
s = tf('s');
H1 = A1 / (1 + s/wp1);
H2 = A2 / (1 + s/wp2);
H = H1 + H2;
figure;
pzp = pzplot(H);
pzp.Responses(1).LineWidth = 8;
pzp.Responses(1).MarkerSize = 20;
poleScatter = findall(pzp,'Marker','x'); %Undocumented, may change in a future release
poleScatter.SizeData = 30^2;
2) You can create two responses and give them each different marker sizes. This will cause duplicate entries to appear in the chart's context menu (unavoidable) and legend (avoidable).
% common part:
A1 = 1; wp1 = 10;
A2 = -2; wp2 = 20;
s = tf('s');
H1 = A1 / (1 + s/wp1);
H2 = A2 / (1 + s/wp2);
H = H1 + H2;
Hz = zpk(zero(H),[],1);
Hp = zpk([],pole(H),1);
figure;
pzp = pzplot(Hz,Hp);
pzp.Responses(1).Name = "H";
pzp.Responses(1).LineWidth = 8;
pzp.Responses(1).MarkerSize = 20;
pzp.Responses(2).Name = "H"; %same name
pzp.Responses(2).LegendDisplay = false; %hide duplicate entry on legend
pzp.Responses(2).Color = pzp.Responses(1).Color; %blue
pzp.Responses(2).LineWidth = 8;
pzp.Responses(2).MarkerSize = 30;
For the second point, you should use the "stepplot" function. The "plot" functions in Control System Toolbox allow for much more customization than the no output syntax of their non-"plot" equivalents.
A1 = 1; wp1 = 10;
A2 = -2; wp2 = 20;
s = tf('s');
H1 = A1 / (1 + s/wp1);
H2 = A2 / (1 + s/wp2);
H = H1 + H2;
figure;
sp = stepplot(H, H1, H2);
sp.Responses(1).LineWidth = 2;
sp.Responses(2).LineWidth = 2;
sp.Responses(3).LineWidth = 6;
sp.AxesStyle.Box = 'off';
sp.AxesStyle.FontSize = 12;
ax = findall(sp,'Type','axes'); %Undocumented, may change in a future release
set(ax,LineWidth=1.5,XTick=[]);
Rarity Brown
Rarity Brown on 30 Sep 2024
Thanks for the info! Can't wait for MATLAB to support more fine-tuned API control over charts!

Sign in to comment.

More Answers (2)

Walter Roberson
Walter Roberson on 12 Sep 2024
The hack for R2024b is:
yticks(gca().NodeChildren.Children, [])
  1 Comment
Rarity Brown
Rarity Brown on 12 Sep 2024
Thank you for your response. Now the both graphs have the same problem, i.e. the code doesn't report any errors, but it doesn't have any effect either.
A1 = 1; wp1 = 10;
A2 = -2; wp2 = 20;
s = tf('s');
H1 = A1 / (1 + s/wp1); H2 = A2 / (1 + s/wp2);
H = H1 + H2;
figure;
bp = bodeplot(H, H1, H2);
hLines = findobj(gcf, Type='line');
set(hLines, LineWidth=2); % not working in R2024b?
set(hLines(6), LineWidth=6, DisplayName='H'); % not working in R2024b?
set(hLines(3), LineWidth=6, DisplayName='H'); % not working in R2024b?
set(findall(gcf, 'Type', 'axes'), LineWidth=1.5, Box="off", fontsize=12); % not working in R2024b?
figure;
pzmap(H, H1, H2);
set(gca().NodeChildren.Children, YTick=[], Box="off", LineWidth=1.5, XAxisLocation='origin', YAxisLocation='origin')
% not working in R2024b?
% or using yticks(gca().NodeChildren.Children, [])
R2024b:
R2024a (expected behavior):

Sign in to comment.


Madheswaran
Madheswaran on 13 Sep 2024
Edited: Madheswaran on 13 Sep 2024
Hi,
As you can notice, while running in MATLAB R2024b, the `findobj` function returns only six lines: three with the tag `BodeMagnitudeLine` and three with the tag `BodePhaseLine`. So, to change the ‘LineWidth’ and ‘DisplayName’ of the desired line, you can change the indexing used in ‘hLines’ array as shown below:
% ... existing code
figure;
bp = bodeplot(H, H1, H2);
hLines = findobj(gcf, Type='line');
set(hLines, LineWidth=2);
set(hLines(1), LineWidth=6, DisplayName='H');
set(hLines(4), LineWidth=6, DisplayName='H');
set(findall(gcf, 'Type', 'axes'), LineWidth=1.5, Box="off", fontsize=12);
Similarly, in the context of `pzmap`, the `gca` function now returns a `PZPlot` chart object instead of an axes object within the plot. Since 'YTick' is not a property of 'PZPlot', the error appears. You can access the axes by indexing the children of 'PZPlot' object as demosntrated below:
figure;
pzmap(H, H1, H2);
set(gca().Children(1), YTick=[], Box="off", LineWidth=1.5, XAxisLocation='origin', YAxisLocation='origin')
Using MATLAB R2024b, the code above will produce the expected plot as shown below:
Please refer to the following MathWorks documentations on the following topics:
  1. pzmap - https://mathworks.com/help/control/ref/lti.pzmap.html
  2. bodeplot - https://mathworks.com/help/ident/ref/controllib.chart.bodeplot.html
  3. PZPlot - https://mathworks.com/help/control/ref/controllib.chart.pzplot.html
Hope this helps!

Categories

Find more on Axes Appearance in Help Center and File Exchange

Products


Release

R2024a

Community Treasure Hunt

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

Start Hunting!