pzplots - Yticks and Colorbar Issue - matlab

I am using pzmap to plot system poles and zeros for different values of L. But the plot has additional YTick Labels at the right side which I cannot see in the axes properties. Also, I do not have the handle corresponding to constant damping gridlines whose color and properties I would like to change.
MWE
clear;clc
cb=parula(10);
s=tf('s');
L_array=5:5:50;
figure; hold on;
for i=1:length(L_array)
L=L_array(i);
G=((58.2+11.7*L)*s^2*25^2+(3996.8 + 815.7*L)*s*25+815.7*25^2)/(s^2*(s^2*25^2+126.9*s*25+(3996.8+1.9*25^2)));
CL=feedback(G,1);
pzmap(CL);
end
h = findobj(gca,'type','line');
for jj=2:length(h)
set(h(jj),'MarkerSize',12,'Color',cb(floor(jj/2),:));
end
grid;
colormap(parula);
c=colorbar;
Also the colorbar is inverted i.e. Blue corresponds to larger L and vice versa. I would like to have it inverted! Thanks in advance!

I could not find any handle to the desired objects in the plot. However, I have some additional insights. The grid corresponding to pzmap has, inherently, an sgrid. The handles of this grid do not show up in the gca properties. So you cannot do anything about it. Even the pzoptions does not enable you to modify those settings. Additionally, the additional Y-Ticks correspond to lines of constant natural frequencies.
Alternatively, it is better to use the sgrid command directly. To choose the constant damping lines,
z = [0, 0.25, 0.5, 0.75, 1];
To remove the additional Y-Ticks,
wn = [];
Now, use sgrid and grid command to get whatever you want.
sgrid(z,wn);
grid;
I can't still change any properties of the grid lines associated with sgrid but it still improves the look of the plot. The question is still open to investigation.

Related

How to update a scatter3 plot (in a loop) in Matlab

Quite a simple question but just couldn't find the answer online... I want to visualise a point cloud gathered from a lidar. I can plot the individual frames but wanted to loop them to create a "animation". I know how to do it for normal plots with drawnow but can't get it working with a scatter3. If I simply call scatter3 again like I have done in the commented code then the frame that I am viewing in the scatter plot jumps around with every update (Very uncomfortable). How do i get the scatter3 plot to update to the new points without changing the UI of the scatter ie. Still be able to pan and zoom around the visualised point cloud while it loops through.
EDIT: The file is a rosbag file, I cannot attach it because it is 170MB. The problem doesn't happen when using scatter3 in a loop with a normal array seems to be something with using scatter3 to call a PointCloud2 type file using frame = readMessages(rawBag, i).
EDIT: The problem does not seem to be with the axis limits but rather with the view of the axis within the figure window. When the scatter is initialised it is viewed with the positive x to the right side, positive y out of the screen and positive z upwards, as shown in view 1. Then after a short while it jumps to the second view, where the axis have changed, positive x is now out of the screen, positive y to the right and positive z upwards (both views shown in figures). This makes it not possible to view in a loop as it is constantly switching. So basically how to update the plot without calling scatter3(pointCloudData)?
rawBag = rosbag('jackwalking.bag');
frame = readMessages(rawBag, 1);
scatter3(frame{1});
hold on
for i = 1:length(readMessages(rawBag))
disp(i)
frame = readMessages(rawBag, i);
% UPDATE the 3D Scatter %
% drawnow does not work?
% Currently using:
scatter3(frame{1})
pause(.01)
end
The trick is to not use functions such as scatter or plot in an animation, but instead modify the data in the plot that is already there. These functions always reset axes properties, which is why you see the view reset. When modifying the existing plot, the axes are not affected.
The function scatter3 (as do all plotting functions) returns a handle to the graphics object that renders the plot. In the case of scatter3, this handle has three properties of interest here: XData, YData, and ZData. You can update these properties to change the location of the points:
N = 100;
data = randn(N,3) * 40;
h = scatter3(data(:,1),data(:,2),data(:,3));
for ii = 1:500
data = data + randn(N,3);
set(h,'XData',data(:,1),'YData',data(:,2),'ZData',data(:,3));
drawnow
pause(1/5)
end
The new data can be totally different too, it doesn't even need to contain the same number of points.
But when modifying these three properties, you will see the XLim, YLim and ZLim properties of the axes change. That is, the axes will rescale to accommodate all the data. If you need to prevent this, set the axes' XLimMode, YLimMode and ZLimMode to 'manual':
set(gca,'XLimMode','manual','YLimMode','manual','ZLimMode','manual')
When manually setting the limits, the limit mode is always set to manual.
As far as I understood what you describe as "plots jumpying around", the reason for this are the automatically adjusted x,y,z limits of the scatter3 plot. You can change the XLimMode, YLimMode, ZLimMode behaviour to manual to force the axis to stay fixed. You have to provide initial axes limits, though.
% Mock data, since you haven't provided a data sample
x = randn(200,50);
y = randn(200,50);
z = randn(200,50);
% Plot first frame before loop
HS = scatter3(x(:,1), y(:,1), z(:,1));
hold on
% Provide initial axes limits (adjust to your data)
xlim([-5,5])
ylim([-5,5])
zlim([-5,5])
% Set 'LimModes' to 'manual' to prevent auto resaling of the plot
set(gca, 'XLimMode', 'manual', 'YLimMode', 'manual', 'ZLimMode', 'manual')
for i=2:len(x,2)
scatter3(x(:,i), y(:,i), z(:,i))
pause(1)
end
This yields an "animation" of plots, where you can pan and zoom into the data while continuous points are added in the loop

pzmap or pzplot color handle for multiple plots

I am plotting a closed loop poles of a systems using pzmap.m or pzplot.m whichever you prefer. I want to see the movement of poles and zeros as I change a variable depicted by L.
The function does not have a direct handle for color. In the example you can just choose the standard colors but cannot give your own color. Since I have to plot multiple times on the same figure, I create a handle for every iteration in a for loop and use findobj to set the color of the curve. To get the colors I want to have a colorbar. So I use jet to get the color distribution for my graph. But the market size stays the same and I have one ugly looking figure.
MWE:
cb=jet(10);
s=tf('s');
L_array=5:5:50;
figure; hold on;
for i=1:length(L_array)
L=L_array(i);
G=((58.2+11.7*L)*s^2*25^2+(3996.8 + 815.7*L)*s*25+815.7*25^2)/(s^2*(s^2*25^2+126.9*s*25+(3996.8+1.9*25^2)));
CL=feedback(G,1);
pzmap(CL);
h = findobj(gcf,'type','point'); set(h,'markers',12,'color',cb(i,:));
clear L G CL h
end
grid;
c=colorbar
c.Label.String = 'L'
If you run it you'll see that the size doesn't change and graph looks crazy with the y axis on either side labelled with ticks. I want a proper colorbar from blue to red and the colors distributed properly but can't get it after multiple tries. If I can get less cluttering that would be helpful too.
The are several problems in your code
h = findobj(gcf,'type','point'); The things drawn in the screen are actually of type 'line'!
Every iteration, you catch all the points, modify them an dimdediately after delete the properties with clear.
Additionally, h = findobj(gcf,'type','line'); will not return a single thing, but a set of them, so you need to index through it to set the properties. My modified code working looks like this:
clear;clc
cb=parula(10);
s=tf('s');
L_array=5:5:50;
figure; hold on;
for i=1:length(L_array)
L=L_array(i);
G=((58.2+11.7*L)*s^2*25^2+(3996.8 + 815.7*L)*s*25+815.7*25^2)/(s^2*(s^2*25^2+126.9*s*25+(3996.8+1.9*25^2)));
CL=feedback(G,1);
pzmap(CL);
end
% lets do this in the end!
% you will have length(L_array)*2 +1 items in h
h = findobj(gca,'type','line');
for jj=2:length(h)
set(h(jj),'MarkerSize',12,'Color',cb(floor(jj/2),:));
end
grid;
colormap(parula); % I am using parula, you can use jet, but I discourage it
c=colorbar;
PD: there are tons of reasons not to use jet!! Use perceptually uniform colormaps please!

Removing scientific notation in plot axis (Matlab) [duplicate]

Tick labels for ticks bigger than about 10'000, get formatted to 1x10^4 for example. Whereas the exponential part appears above the corresponding axes. This misbehavior has been well described on on matlab central as well, but without a solution.
Thanks for your help.
The 'quick trick'
set(gca, 'YTickLabel',get(gca,'YTick'))
did not work when applied to bar3, as can be seen on the following figure.
EDIT
According to this technical solution page, the recommended way of formatting the tick labels is this (you can use any of the number formatting functions like NUM2STR, SPRINTF, MAT2STR, or any other..)
y = cool(7);
bar(y(:,1)*1e6)
set(gca, 'YTickMode','manual')
set(gca, 'YTickLabel',num2str(get(gca,'YTick')'))
However there seems to be a bug when it comes to the Z-axis (the labels are correctly formatted, but the exponential multiplier is still showing for some reason!)
y = cool(7);
bar3(y*1e6, 'detached')
set(gca, 'ZTickMode','manual')
set(gca, 'ZTickLabel',num2str(get(gca,'ZTick')'))
Finally, there's another workaround where we replace the tick labels with text objects (see this technical solution page as reference):
y = cool(7);
bar3(y*1e6, 'detached')
offset = 0.25; Xl=get(gca,'XLim'); Yl=get(gca,'YLim'); Zt=get(gca,'ZTick');
t = text(Xl(ones(size(Zt))),Yl(ones(size(Zt)))-offset,Zt, num2str(Zt')); %#'
set(t, 'HorizontalAlignment','right', 'VerticalAlignment','Middle')
set(gca, 'ZTickLabel','')
One other trick you can try is to scale your data before you plot it, then scale the tick labels to make it appear that it is plotted on a different scale. You can use the function LOG10 to help you automatically compute an appropriate scale factor based on your plotted values. Assuming you have your data in variables x and y, you can try this:
scale = 10^floor(log10(max(y))); %# Compute a scaling factor
plot(x,y./scale); %# Plot the scaled data
yTicks = get(gca,'YTick'); %# Get the current tick values
set(gca,'YTickLabel',num2str(scale.*yTicks(:),'%.2f')); %# Change the labels
One way to get better control over tick labels, and to avoid the exponential formatting, is to use TICK2TEXT from the File Exchange.
Here's an example:
y = cool(7); %# define some data
ah = axes; %# create new axes and remember handle
bar3(ah,y*1E6,'detached'); %# create a 3D bar plot
tick2text(ah, 'ztickoffset' ,-1.15,'zformat', '%5.0f', 'axis','z') %# fix the tick labels

How to display slope on a plot in Matlab

I used the regress function to find the slope for some data I plotted. I have managed to plot the data and the fitted line both on the same plot. I know how to make it clear that the fitted line is the slope, but I would also like to add a box in corner of the graph (dont care where) that shows the actual value of the slope (basically shows the value that the regress function returns), and I'm trying to find a way to do this automatically (like if there's a function for that or something). Can anybody help (I hope I explained my question well enough...)?
I didn't try to recreate your slope line but have you considered using an annotation?
Example:
x = [-1:.2:1];
plot(x,x.^2,'-bo');
annotation('textbox', [.4 .4 .1 .1], 'String', ...
['slope at x = 0.6 is: ',num2str(2*.6)]);
Which shows:
Of course you can control how the box is positioned, formatted, and so forth.
Check the help files for more detailed info. In some cases you might also consider using a legend().
The function text adds text to a figure. It requires a position and a string to display. In addition, you can highly customize the appearance of the text. For example:
x = 1:100;
y = randn(size(x)) + 0.3*x;
plot(x,y,'.');
p = polyfit(x,y,1);
hold on;
plot(x, polyval(p,x),'k-');
h = text(min(xlim(gca)), max(ylim(gca)), ...
sprintf('%fx + %f', p(1), p(2)),...
'verticalalignment','top',...
'horizontalalignment','left');
Then, to see the various settinsg you can change, look at:
get(h)
Those properties can almost all be changes at creation (like verticalalignment above) or after creation (e.g. set(h, verticalalignment, 'top')).

How to plot arrow with data coordinates in Matlab?

I know there is a function named annotation can plot arrows or double arrows. But annotation can only plot in normalized unit. For example:
annotation('arrows',[x1 x2],[y1 y2])
Here, [x1, x2] should be a ratio number less than one.
So, my question is how can I plot arrows with a true value rather than a normalized value?
I wonder if there is any other function can approach this or is there any function I can get the axis value of the figure so that I can adjust the true value into a normalized value.
For the positioning of annotations, Matlab offers the function dsxy2figxy to convert data space points to normalized space coordinates. However, for whatever reasons, the function is not included in the Matlab distribution and has to be "created" first.
Copy the following line into the command window and execute it to open the function in your editor.
edit(fullfile(docroot,'techdoc','creating_plots','examples','dsxy2figxy.m'))
To use the function dsxy2figxy save it somewhere in your matlab search path.
Please find the full instructions for the function dsxy2figxy at matlab-central: http://www.mathworks.de/help/techdoc/creating_plots/bquk5ia-1.html
Even though annotation uses normalized as default units, you can associate these objects to the current axes (gca) and use data units for setting X and Y properties.
Here is an example of plotting a single arrow.
plot(1:10);
ha = annotation('arrow'); % store the arrow information in ha
ha.Parent = gca; % associate the arrow the the current axes
ha.X = [5.5 5.5]; % the location in data units
ha.Y = [2 8];
ha.LineWidth = 3; % make the arrow bolder for the picture
ha.HeadWidth = 30;
ha.HeadLength = 30;
For anyone who comes across this topic looking to draw arrows in "data space" rather than in units relative to the figure and/or axes, I highly recommend arrow.m from the file exchange.
I've just discovered this method, since I don't want to have to bother with normalised units. Use the latex interpreter:
figure
plot([1:5],[1:5]*3,'.-')
%// Say I want to put an arrow pointing to the location, [3 9]
text(2.94,8.3,'\uparrow','fontsize',20)
text(2.8,7.8,'point [3,9]')
To make the arrow longer, use a larger fontsize.
Pros
Easier, faster and quicker than using normalised units
Don't need to install any functions (good for us lazy people..)
making use of the LaTeX interpreter, there is a whole range of arrows (up, down, left, right and other angles (see Symbol list)
Cons
Definitely needs trial and error/tweaking to get the correct location of the arrow head relative to the POI.
There is limited control over the length of the arrow
Some latex commands aren't understood by the interpreter (boo).
If I remember correctly you need to calculate the position of the axes in relation to the figure.
it should go like:
%% example plot
clf
plot(rand(5,2)*5)
%% get info specific to the axes you plan to plot into
set(gcf,'Units','normalized')
set(gca,'Units','normalized')
ax = axis;
ap = get(gca,'Position')
%% annotation from 1,2 to 3,4
xo = [1,3];
yo = [2,4];
xp = (xo-ax(1))/(ax(2)-ax(1))*ap(3)+ap(1);
yp = (yo-ax(3))/(ax(4)-ax(3))*ap(4)+ap(2);
ah=annotation('arrow',xp,yp,'Color','r');
Note Fixed offset in original calculation - ap(3),ap(4) are width and height of gca, not corner positions
After creating the annotation object you should set the property Units to an absolute one. Example:
arrowObj = annotation('arrow', [0.1 0.1], [0.5 0.5]);
set(arrowObj, 'Units', 'centimeters');
set(arrowObj, 'Position', [1 1 3 5]);
One approach would be to define an arrowhead in the axis units:
Ax=[0 -0.003 0.003 0]; % (Ax,Ay) form an upward pointing arrowhead.
Ay=[0.01 0.0060 0.0060 0.01];
Ax=Ax-mean(Ax); % center it on zero
Ay=Ay-mean(Ay);
Then at desired arrowhead index in on a curve vv, compute
x1=vv(in,1); y1=vv(in,2);
x2=vv(in+1,1); y2=vv(in+1,2);
u=x2-x1;
v=y2-y1;
th=-pi/2+atan2(v,u);
R=[cos(th) -sin(th); sin(th) cos(th)]; % Rotation matrix for local slope of vv.
A=R*[Ax;Ay]; % Rotate the arrowhead.
patch(x1+A(1,:),y1+A(2,:),'r','LineWidth',0.01) % plot rotated arrowhead at (x1,y1).
plot(x1+A(1,:),y1+A(2,:),'r','LineWidth',0.01) % Kludge to make boundary red too (I'm sure there is a more elegant way).
Worked for me, for my particular circumstances.
You can use the 'arrow' component in the (well-documented) DaVinci Draw toolbox (full disclosure: I wrote/sell the toolbox, though arrows are free).
Example syntax and example output are below.
davinci( 'arrow', 'X', [0 10], 'Y', [0 2], <plus-lots-of-options> )