You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
Adding plots to an existing root locus plot
41 views (last 30 days)
Show older comments
how can I add damping frequency lines constraints to an existing root locus plot
13 Comments
dpb
on 30 Sep 2024
Edited: dpb
on 30 Sep 2024
Be much more likely to get an answer if you would provide your present plot and a sketch of what you would like to add...the rlocusplot in Control System TB appears to be brand new; whether there was something else earlier I don't know, only have Signal Processing TB myself.
figure(1)
sys = tf([2 5 1],[1 2 3]);
rlp = rlocusplot(sys);
The example works; now to seee what happens if we try to add an arbitrary line on top of it???
hF=gcf;
hF.Children % what's the object just for grins...
hold on
hXL=xline(-2,'r'); % try to add a vertical line on existing plot...
hXL.Parent
hL=plot([-2.5 0.5],[-1.5 1.5],'b:');
OK, those show what was asked for, but they don't belong to the rlocusplot object; another axes was created that by default overlaid the previous plot/figure.
Let's see what happens if we try explicitly...
figure(2) % create a new figure to not destroy previous
rlp = rlocusplot(sys); % make a new plot...we'll reuse same handle
hXL=xline(rlp,-2,'r'); % now try to add the vertical line onto the plot explicitly
hXL.Parent % check to see who really is the proud parent...
Well, it doesn't crash and burn like some of the other closed specialty graphs, but it didn't put the line on the actual root locus plot, either, but again created a new axes on top and drew into it.
So, you may be able to make something work that looks like what you would like; you'll probably need to see if there's any chance linkaxes has been extended--according to the documentation, it hasn't, it still expects an array of axes handles...
hold on
hL=plot(rlp,[-2.5 0.5],[-1.5 1.5],'b:'); % one presumes this also will go on another axes
hL.Parent
And, indeed, while plot is generous enough to not crash/reject the handle, it also doesn't add anything onto the existing rlp plot but continues on with the other axes. NOTA BENE: Without the hold on, the existing figure is erased and only the subsequent line shows up...one last interesting Q? would be if hold will accept and actually do something to an rlp object; given the behavior of plotting not erasing the existing one but creating the new axes, it's virtually certain it will have no effect and you won't be able to draw anything else on the plot itself but only draw on top of it as above to simulate having done.
linkaxes(hXL.Parent,rlp) % see if this goes boom...
Ayup...so if you try to resize one, you'll have to have callback functions to handle the other to keep them overlaid, you won't be able to count on MATLAB doing it for you.
If you used some other tool to draw the plot above behavior may be totally different, of course...
Andrew Ouellette
on 31 Oct 2024
Hi dpb,
To clear up some confusion in your post:
The rlocusplot() function is not new within the Control System Toolbox, but in R2024b the output was changed to create a chart object (RLocusPlot). This chart object contains an axes object where the chart data objects are placed. When you superimpose chart data onto a Control System Toolbox chart using "hold on", the chart data objects are parented to the axes object within the chart. No new axes are created. The "linkaxes" function you called fails because that is not valid syntax for that command. The first argument must be an array of axes objects, and the second must be the linking dimensions. However, I would be hesitant to access the internal chart axes object using hXL.Parent as you may run into unexpected behaviors.
dpb
on 2 Nov 2024
Edited: dpb
on 2 Nov 2024
Andrew, Paul's comment above made me realize that was one thing I didn't explore earlier -- indeed, what TMW did expose as Children; I had made the assumption it would be unaccessible to the end user. So, if the conjecture thad 'hold on' did add to the existing axes, then, those two handles should match --
hChild(1)==hAx
ans = logical
1
hAx.Children
ans =
8x1 graphics array:
ConstantLine
Scatter (RootLocusPoleScatter)
Scatter (RootLocusZeroScatter)
Line (RootLocusLocusLines)
Line (RootLocusLocusLines)
ConstantLine
ConstantLine
Rectangle (RootLocusUnitCircle)
and, in fact, they do, even though the parent of the rlp object is converted from the original figure to a TiledLayoutObject by the route of 'hold on'. One could then also just directly plot into that axes by passing the handle in the calls ot any of the drawing routines/primitives.
The "syntax error" was deliberate owing to my having forgotten that zoom works on all axes in a figure (I haven't used it but once or twice in my 30+ yr w/ MATLAB) so that was a red herring, anyway.
This is indeed much improved behavior than the previous types of charts that have arisen in the forum asking for further modifications--TMW is learning as they go along, clearly. One would hope that eventually the early arrivals will also get similar treatment if they already haven't--for certain reasons I've not yet upgraded past R2022b so I can't easily check out some of the newest things locally.
Paul
on 2 Nov 2024
Hi dpb,
The doc page for xline only allows for adding the line to an Axes object. Apparently sending the handle to an RLocusPlot as the first argument to xline doesn't throw an error, but it is undocumented AFAICT. Adding the xline to the Axes that is contained within the RLocusPlot gives the expected result (and is the more natural approach IMO).
sys = tf([2 5 1],[1 2 3]);
rlp = rlocusplot(sys);
The contained Axes is the first child of rlp
rlp.Children
ans =
4x1 graphics array:
Axes
Text
Text
Text
haxRLP = ans(1)
haxRLP =
Axes with properties:
XLim: [-2.5000 0.5000]
YLim: [-1.5000 1.5000]
XScale: 'linear'
YScale: 'linear'
GridLineStyle: '-'
Position: [0.1300 0.1401 0.7750 0.7611]
Units: 'normalized'
Use GET to show all properties
The contained Axes has seven children
haxRLP.Children
ans =
7x1 graphics array:
Scatter (RootLocusPoleScatter)
Scatter (RootLocusZeroScatter)
Line (RootLocusLocusLines)
Line (RootLocusLocusLines)
ConstantLine
ConstantLine
Rectangle (RootLocusUnitCircle)
Add the ConstantLine to the Axes, not the rlp.
hXL = xline(haxRLP,-0.5,'r');

The added ConstantLine is a new child of the contained Axes
haxRLP.Children
ans =
8x1 graphics array:
ConstantLine
Scatter (RootLocusPoleScatter)
Scatter (RootLocusZeroScatter)
Line (RootLocusLocusLines)
Line (RootLocusLocusLines)
ConstantLine
ConstantLine
Rectangle (RootLocusUnitCircle)
The parent of the added ConstantLine
haxXL = hXL.Parent
haxXL =
Axes with properties:
XLim: [-2.5000 0.5000]
YLim: [-1.5000 1.5000]
XScale: 'linear'
YScale: 'linear'
GridLineStyle: '-'
Position: [0.1300 0.1401 0.7750 0.7611]
Units: 'normalized'
Use GET to show all properties
is the contained Axes.
isequal(haxRLP,haxXL)
ans = logical
1
dpb
on 2 Nov 2024
Yes, our additional comments seem to have crossed in the night; I had just noted that your previous comment made me realize I had not actully checked to see about the content of rlp.Children having had a preconceived notion based on some of the earlier chart objects it would be almost completely opaque with only the few properties exposed, and certainly I didn't expect the underlying axes itself. I don't know how much my prior complaints influenced the decision, but this is clearly a quantum change and a great leap forward to allow such. I have just been having another conversation on similar visibility within the bar function where new feature/property was added but not access to the underlying text objects which the new property uses. This appears to be a case where TMW internal review prevails depending upon their assessment of how much exposing the inner object handles will engender supporting issues owing to users being able to make changes that might cause internal errors and implementation difficulties/details.
I was going to comment on your earlier question about @Andrew Ouellette's concern about using the parent handle that I think it's immaterial which way one goes at it, whether the end result ended up as the same axes as it has now been shown to be or another as I was confused into thinking by the change in parents and that I had simply expected the original axes handle to be hidden by TMW deliberately based on prior charts.
If you have a valid handle to an axes, then using it in the graphics primitives is certainly valid; if it turns out ot be the same object found by two different searches; which reference is used is immaterial; either resolves to the same end object. Hence, I think his concern is unfounded...
Paul
on 2 Nov 2024
Regarding this statement in a previous comment:
"the parent of the rlp object is converted from the original figure to a TiledLayoutObject by the route of 'hold on'. "
sys = tf([2 5 1],[1 2 3]);
rlp is a RLocusPlot
rlp = rlocusplot(sys)
rlp =
RLocusPlot with properties:
Responses: [1x1 controllib.chart.response.RootLocusResponse]
TimeUnit: "seconds"
FrequencyUnit: "rad/s"
Visible: on
Use GET to show all properties
Parent of rlp is a figure;
rlp.Parent
ans =
Figure (1) with properties:
Number: 1
Name: ''
Color: [1 1 1]
Position: [1628 1512 583 437]
Units: 'pixels'
Use GET to show all properties
Use hold on
hold on

The parent of the rlp is still a figure, were you seeing otherwise?
rlp.Parent
ans =
Figure (1) with properties:
Number: 1
Name: ''
Color: [1 1 1]
Position: [1628 1512 583 437]
Units: 'pixels'
Use GET to show all properties
However, there does seem to be an inconsistency.
The first child of the rlp is the Axes
haxRLP = rlp.Children(1)
haxRLP =
Axes with properties:
XLim: [-2.5000 0.5000]
YLim: [-1.5000 1.5000]
XScale: 'linear'
YScale: 'linear'
GridLineStyle: '-'
Position: [0.1300 0.1401 0.7750 0.7611]
Units: 'normalized'
Use GET to show all properties
So the parent of the Axes should be the RLocusPlot (rlp). But it's a TiledChartLayout (which is the case even if "hold on" is not executed)
haxRLP.Parent
ans =
TiledChartLayout with properties:
TileArrangement: 'fixed'
GridSize: [1 1]
Padding: 'loose'
TileSpacing: 'compact'
Use GET to show all properties
@Andrew Ouellette, how can the child of a parent have a different parent?
dpb
on 2 Nov 2024
Edited: dpb
on 3 Nov 2024
@Paul, My initial post did make a shortcut presumption without explicit testing that it was executing hold on that triggered the change in parent to show the TiledChartLayout object instead of Figure (1); I didn't actually do the call back without having already done hold on (since I don't have the TB locally and it's rather painful to try to do really detailed exploration in the forum environment).
It's clear that the RLocusPlot object is complex, that the top level parent of the embedded axes resolves to a tiled layout is interesting, indeed, as noted, lacking the TB locally, I presumed it was the "hold on" getting ready to do something more that caused the behavior.
I'm satisfied about the axes itself being the same one, but w/o local access it's too painful to probe even deeper/more carefully. Can you maybe then eventually resolve that the parent of the TiledLayout is the Figure at the very top of the food chain?
ADDENDUM:
Actually, can show that w/o the actual rlp object itself...
h=tiledlayout(1,1)

h =
TiledChartLayout with properties:
TileArrangement: 'fixed'
GridSize: [1 1]
Padding: 'loose'
TileSpacing: 'loose'
Use GET to show all properties
h.Parent
ans =
Figure (1) with properties:
Number: 1
Name: ''
Color: [1 1 1]
Position: [1628 1512 583 437]
Units: 'pixels'
Use GET to show all properties
gcf==h.Parent
ans = logical
1
Paul
on 3 Nov 2024
Here's the best I have, and it's still confusing.
Create the RLocusPlot object
rlp = rlocusplot(tf(1,[1 2 1]));

The figure is a child of the root.
hfig = get(0,'children')
hfig =
Figure (1) with properties:
Number: 1
Name: ''
Color: [1 1 1]
Position: [1628 1512 583 437]
Units: 'pixels'
Use GET to show all properties
The rlp is the only child of the figure.
hfig.Children
ans =
RLocusPlot with properties:
Responses: [1x1 controllib.chart.response.RootLocusResponse]
TimeUnit: "seconds"
FrequencyUnit: "rad/s"
Visible: on
Use GET to show all properties
isequal(rlp,hfig.Children)
ans = logical
1
The rlp has four (apparently) children.
rlp.Children
ans =
4x1 graphics array:
Axes
Text
Text
Text
The axes is the first child of the rlp
hAX = rlp.Children(1)
hAX =
Axes with properties:
XLim: [-1.2000 0.2000]
YLim: [-0.6000 0.6000]
XScale: 'linear'
YScale: 'linear'
GridLineStyle: '-'
Position: [0.1300 0.1401 0.7750 0.7611]
Units: 'normalized'
Use GET to show all properties
Even though the axes is a child of the rlp, it thinks its parent is a TiledChartLayout.
hTL = hAX.Parent
hTL =
TiledChartLayout with properties:
TileArrangement: 'fixed'
GridSize: [1 1]
Padding: 'loose'
TileSpacing: 'compact'
Use GET to show all properties
That parent of the TiledChartLayout is the rlp, even though it wasn't shown above as a child of the rlp.
hTL.Parent
ans =
RLocusPlot with properties:
Responses: [1x1 controllib.chart.response.RootLocusResponse]
TimeUnit: "seconds"
FrequencyUnit: "rad/s"
Visible: on
Use GET to show all properties
And the parent of the parent of the TiledChartLayout is the original figure.
hTL.Parent.Parent
ans =
Figure (1) with properties:
Number: 1
Name: ''
Color: [1 1 1]
Position: [1628 1512 583 437]
Units: 'pixels'
Use GET to show all properties
isequal(hfig,hTL.Parent.Parent)
ans = logical
1
Maybe (likely) there are aspects of the handle graphics system that I don't understand, but this hierarchy doesn't make sense to me.
dpb
on 3 Nov 2024
f=which('-all','rlocusplot');
M=readlines(f{:});
M(contains(M,'chart','ignorecase',1))
ans = 3x1 string array
" % Check to create stepplot using control charts"
" h = controllib.chart.internal.utils.ltiplot("rlocus",hParent,..."
" ax = controllib.chart.internal.utils.getEntryAxesForChart(hParent);"
M(contains(M,'tiledlayout','ignorecase',1))
ans =
0x1 empty string array
The logic involved is pretty complex and uses Mathworks internals routines that are not m-files so that one can't get into the complete internals. The above shows that the m-code doesn't directly call tiledlayout, but clearly somewhere in the bowels it was/is, since it turns out that's what the end object axes turns out to belong to in the end.
I also don't follow why, exactly, the two parents are resolved differently; that's buried somewhere in those hidden pieces.
Andrew Ouellette
on 4 Nov 2024
The short answer is that the Children property of RLocusPlot is not documented, so do not expect any sort of behavior from it- it does not function like the Children property of other graphics objects like figures or axes. The closest thing that RLocusPlot has to the traditional Children property is its Responses property, which allows you to modify the data and styling for the root locus responses contained in the chart.
As for the pitfalls with interacting with the internal axes handle, you will find that many interactions work how you would expect. However, the RLocusPlot object is generally unaware of changes made to its internal axes that it itself did not make. You may find that the object stomps over some of your customizations during its updates, or you could place the chart into an invalid state (e.g. by deleting the axes handle). Additionally, you will find that your customizations will not be reflected in the Live Editor or after loading a saved figure containing a RLocusPlot object.
dpb
on 4 Nov 2024
Edited: dpb
on 4 Nov 2024
There still has to be a defineable reason for the particular behavior, undocumented or not, though, persuing which was the direction of this sidebar conversation.
It simply can't be relied upon to remain that way going forward nor even be assured the code won't do the apocryphal "start WW III" if one mucks around with those undocumented properties--trashing the figure or even crashing MATLAB at the extreme.
But, while the internals are somewhat interesting, it isn't of any real significance to the use of the object and the implementation is far improved over many of the earlier similar canned charts in exposing internals such as the axes handle even if some internal features are unsupported by making other user modfications.
I, personally, commend TMW on the decision to have done so, even though I don't have the particular TB and my days of control systems are far behind me; hopefully, the direction will carry over to new such specialty graphics as they are introduced and also make its way back into earlier ones that weren't so user friendly.
Answers (2)
Andrew Ouellette
on 31 Oct 2024
Hello,
Design requirements (constraints) for damping ratios and natural frequencies in root locus charts is only available within the Control System Designer app currently. You cannot import a root locus chart directly into the app, but you can import the same system you used to generate the root locus and design requirements at that point.
If you are simply looking to see grid lines with constant damping factors and natural frequencies, you have a few options:
1) After creating your root locus chart, you can open a context menu by right clicking on the chart axes. In that menu, you can select the Grid option to turn on the chart's grid.
2) Starting in R2024b, you can turn on the chart's grid via the chart API.
sys = rss(4);
rlp = rlocusplot(sys);
rlp.AxesStyle.GridVisible = true;

3) You can also explore the sgrid() or zgrid() functions to customize the damping factors and natural frequencies shown in the grid.
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)
