Adding letters to 3D plot data points in Matlab - matlab

I am currently working on a 3D representation of a hand fingers moving. You can see on the picture below how it looks like, since it would be too complicated to describe otherwise:
It is an animation, so it's moving constantly. There is one dot for each finger, and one dot for the palm. However, I can't keep track of the fingers. I tried to give them different colors, but it doesn't help a lot.
So the question is:
Is there a way to replace the circles, or any other symbol, with an actual letter, or even short word (3-4 letters)?
Alternatively (and it is quite a stretch, but why not ask?), would there be a way to draw lines joining these dots together? This is optional, and I might open another question regarding it if necessary.
Thanks!
Here is the actual code; I know it is far from being elegant coding, and am sorry about it, but it works, which is already a great step for me:
clear all
clc
csv=csvread('pilot6/maindroite.csv',1,0); %read the values from a csv
both = csv(:,2:19);
ax=axes;
set(ax,'NextPlot','replacechildren');
Dt=0.1; %sampling period in secs
k=1;
hp1=plot3(both(k,1),both(k,2),both(k,3),'ok'); %get handle to dot object
hold on;
hp2=plot3(both(k,4),both(k,5),both(k,6),'og');
hp3=plot3(both(k,7),both(k,8),both(k,9),'ob');
hp4=plot3(both(k,10),both(k,11),both(k,12),'oc');
hp5=plot3(both(k,13),both(k,14),both(k,15),'om');
hp6=plot3(both(k,16),both(k,17),both(k,18),'or');
hold off;
t1=timer('TimerFcn','k=doPlot(hp1,hp2,hp3,hp4,hp5,hp6,both,t1,k)','Period', Dt,'ExecutionMode','fixedRate');
start(t1);
and the function used:
function k=doPlot(hp1,hp2,hp3,hp4,hp5,hp6,pos,t1,k)
k=k+1;
if k<5000%length(pos)
set(hp1,'XData',pos(k,1),'YData',pos(k,2),'ZData',pos(k,3));
axis([0 255 0 255 0 255]);
set(hp2,'XData',pos(k,4),'YData',pos(k,5),'ZData',pos(k,6));
set(hp3,'XData',pos(k,7),'YData',pos(k,8),'ZData',pos(k,9));
set(hp4,'XData',pos(k,10),'YData',pos(k,11),'ZData',pos(k,12));
set(hp5,'XData',pos(k,13),'YData',pos(k,14),'ZData',pos(k,15));
set(hp6,'XData',pos(k,16),'YData',pos(k,17),'ZData',pos(k,18));
else
k=1;
set(hp,'XData',pos(k,1),'YData',pos(k,2),'ZData',pos(k,3));
axis([0 255 0 255 0 255]);
end
I just want to mention this is based heavily on Jorge's answer on this question, so thanks to him again

text(x,y,z,'string') instead of plot3 should work in changing the points to text where [x,y,z] is the coordinate of each point you are plotting.
Note: calls to set will need to change from set(hp3,'XData',x,'YData',y,'ZData',z) to set(htext,'pos',[x,y,z]). Where hp3 is the handle to a plot3-handle object and htext is a handle to a text-handle object.
To connect the points with a line use plot3(X,Y,Z) where X=[x_1,x_2,...,x_n], Y=[y_1,y_2,...,y_n] and Z=[z_1,z_2,...,z_n].

Related

How to have diferent markers and line styles while plotting same variable from multiple data files?

How can I have diferent markers or line styles when I am plotting same variable from 8 diferent data files in one figure?
I have got my code that reads multiple excel files and it is perfectly fine with plotting the variable I call for from all 8 diferent excel files.
Although I already have the plot with different colors that I have defined. However, somehow, I cannot define any marker or diferent Line Styles. I have attached my plotting codes below; please also see the figure
ax = gca;
grid on;
hold on
plot(Pin_dBm,Pout_Meas_dbm,"LineWidth",2)
%ax.LineStyleOrder={'-o','-+','-*','-x','-s','-d','-v','->'};
ax.ColorOrder=[1 0 0; 1 0 1; 0 1 0; 0.4660 0.6740 0.1880; 0 0 1; 0.3010 0.7450 0.9330; 0.8500 0.3250 0.0980; 0.9290 0.6940 0.1250]
ylabel('Output Power [dBm]','Color','K')
xlabel('Input Power [dBm]')
title('Output Power comparison - ON mode (0V)', 'Color', 'k')
legend('3F50Sa1','3F100Sa1', '5F50Sa1','5F100Sa1','7F50Sa1','7F100Sa1','9F50Sa1','9F100Sa1','location', 'bestoutside')
To change trace (or marker) properties you have to use the plot handle, not the figure handle, to change line properties like LineWidth and Color.
To grab the plot handle you have to plot like this
hf1=figure(1)
ax = gca;
grid on;
hp1=plot(Pin_dBm,Pout_Meas_dbm)
hp1.LineWidth=2
hp1.Color='r' % red
..
hf1 is the figure handle, not the trace or curve or graph handle.
The figure is the frame containing traces.
You don't have to, this is ok
hf1=figure
but it's good practice to number figures figure(n) as soon as generated, it helps reading code if later on someone has to findout what figure handle belongs to what figure.
now you tell the graph container, the figure with handle hf1 not to remove the 1st trace regardless of what you plot next:
hold(ax1,'on')
and now, with a for loop or one by one, or in any other way you choose, you can add more traces onto same figures changing the properties you choose using a different plot handle
hp2=plot(Pin_dBm2,Pout_Meas_dbm2)
hp2.LineWidth=1.5
hp1.Color='b' % blue
..
and as you mention in your question you can send the same variable updated with different input data or file
update_Pin_dBm;
update_Pout_Meas_dbm;
If you do not update Pin_dBm and-or Pout_Meas_dbm the next plot with different properties may be identical or similar and overlap the previous trace.
hp3=plot(Pin_dBm,Pout_Meas_dbm)
hp3.LineWidth=1
hp1.Color=[0 1 1] % cyan
The figure handle hf1 could still be used to change trace properties, because as the container to the plot, has as children property the handle to the plot. But no one uses what is otherwise a rather long Java-like expression
Note: The term marker is generally used, not for the graph line, the plot, but for the pointers on the graph line that scopes and also MATLAB allows to put, to read a particular (x,y).
If you find this answer useful, would you please be so kind to accept it?
Thanks for reading my answer.

Trouble rotating coordinates about origin

I'm having some difficulty getting a simple script to work. The goal is to rotate an array of points about the origin using some angle. However, the code I'm using seems not to maintain the magnitude of the vector.
Im using a array where the first column is x coordinate and the second is y coordinate:
for ii=1:1000
angleRads=rand()*2*pi;
randRotPoints(ii,1)=1*cos(angleRads)-0*sin(angleRads);
randRotPoints(ii,2)=0*cos(angleRads)+1*sin(angleRads);
end
figure;
scatter(randRotPoints(:,1),randRotPoints(:,2));
lengths1=sqrt(randRotPoints(:,1).^2+randRotPoints(:,2).^2);
for ii=1:1000
angleRads=rand()*2*pi;
randRotPoints(ii,1)=randRotPoints(ii,1)*cos(angleRads)-randRotPoints(ii,2)*sin(angleRads);
randRotPoints(ii,2)=randRotPoints(ii,2)*cos(angleRads)+randRotPoints(ii,1)*sin(angleRads);
end
figure;
scatter(randRotPoints(:,1),randRotPoints(:,2));
lengths2=sqrt(randRotPoints(:,1).^2+randRotPoints(:,2).^2);
After the first loop, there is a coordinates of magnitude of 1 and random orientation. This is confirmed via the scatter plot and the lengths1 array is all 1s.
However, the second loop that attempts to rotate those coordinates by a second random angle results in seemingly randomly located coordinates (based on the scatter plot), and the lengths are no longer all 1.
Please help me figure out where I've gone wrong with this rotation code. I know that this isn't the most efficient code in terms of performance or number of lines, if you want to provide a better way to do it in terms of efficiency that is fine, but please also state what would be needed to fix the code in its current format as well.
Thanks.
In your second loop you have
randRotPoints(ii,1)=randRotPoints(ii,1)*cos(angleRads)-randRotPoints(ii,2)*sin(angleRads);
randRotPoints(ii,2)=randRotPoints(ii,2)*cos(angleRads)+randRotPoints(ii,1)*sin(angleRads);
i.e. you use the overwritten (rotated) x coordinate when computing the y. Try saving the randRotPoints(ii,:) vector before rotating it, and using the saved value on the right hand side.
As for making it more efficient:
The more readable solution
You can make the code much more readable by explicitly defining the rotation matrix for each point
for ii=1:1000
angleRads=rand()*2*pi;
rotmat=[cos(angleRads) -sin(angleRads); sin(angleRads) cos(angleRads)];
randRotPoints(ii,:)=rotmat*[1; 0];
%note that this is equivalent to
%randRotPoints(ii,:)=[cos(angleRads); sin(angleRads)];
end
figure;
scatter(randRotPoints(:,1),randRotPoints(:,2));
lengths1=sqrt(randRotPoints(:,1).^2+randRotPoints(:,2).^2);
for ii=1:1000
angleRads=rand()*2*pi;
rotmat=[cos(angleRads) -sin(angleRads); sin(angleRads) cos(angleRads)];
randRotPoints(ii,:)=rotmat*(randRotPoints(ii,:).');
end
figure;
scatter(randRotPoints(:,1),randRotPoints(:,2));
lengths2=sqrt(randRotPoints(:,1).^2+randRotPoints(:,2).^2);
In order to spare some code-duplication you could also define a rotmatfun=#(angleRads) [cos(angleRads) -sin(angleRads); sin(angleRads) cos(angleRads); function, then you can just say rotmat=rotmatfun(angleRads); in the loops.
The more efficient solution
You can do away with your loops entirely by making use of the vectorized notation:
N=1000; %number of points
angleRads=rand(N,1)*2*pi;
randRotPoints=[1*cos(angleRads)-0*sin(angleRads), ...
0*cos(angleRads)+1*sin(angleRads)]; %matrix of size [N,2]
figure;
scatter(randRotPoints(:,1),randRotPoints(:,2));
lengths1=sqrt(randRotPoints(:,1).^2+randRotPoints(:,2).^2);
angleRads=rand(N,1)*2*pi;
randRotPoints=[randRotPoints(:,1).*cos(angleRads)-randRotPoints(:,2).*sin(angleRads), ...
randRotPoints(:,2).*cos(angleRads)+randRotPoints(:,1).*sin(angleRads)];
figure;
scatter(randRotPoints(:,1),randRotPoints(:,2));
lengths2=sqrt(randRotPoints(:,1).^2+randRotPoints(:,2).^2);

Replace pixels with symbols

I am trying to write a function that would take an indexed image as an input and will replace all its pixels by symbols or characters.
An image is worth more than a 1000 words: This is the desired look output. Each of the symbols represent an unique color value of the image.
My problem is that I don't know how to print in the screen the symbols in the correct place. My first approach has been to use the "Wingdings" font and to put text on the places, but does not work as expected. The text changes sizes when zoomed, and does not behave accordingly to the rest of the plot.
I leave here a small piece of code that creates a small grid and uses an example image.
function drawChars (img)
if nargin==0
load mandrill
img=X(1:4:end,1:4:end);
end
chars=randperm(numel(unique(img)));
[h,w]=size(img);
% Form a grid
figure
hold on
for ii=0:h
plot([ii ii],[0 w],'k');
end
for ii=0:w
plot([0 h],[ii ii],'k');
end
axis equal;
axis([0 h 0 w])
%% This does not work as expected
for ii=1:h
for jj=1:w
text(ii, jj, char(chars(img(ii,jj))), 'fontname', 'Wingdings', 'fontsize',10);
end
end
end
Short question: What approach would you use to solve the problem?
NOTE: there is a problem with the choice of chars also, but ignore it for the time being (if char { is chosen does not work nicely)
With figure changed to f=figure
r=size(img).*16;
set(f,'paperunits','points')
set(f,'papersize',r)
set(f,'paperposition',[0 0 r]);
print(f,'example.png','-dpng');
Prints the created figure to a png of sufficient size.

how can i apply exact dct2 on 8x8 blocks and display them in subplots?

I=imread('ft.jpg');
[a b]=size(I);
figure;imshow(I);
j=rgb2ycbcr(I);
[m n]=size(j);
figure;
imshow(j);
ca=mat2cell(j,8*ones(1,size(j,1)/8),8*ones(1,size(j,2)/8),3);
p = 1;
figure;
figure;
X=ones(m,n,8,8);
for c=1:size(ca,1)
for r=1:size(ca,2)
temp=zeros(8,8,'uint8');
temp(:,:)=X(c,r,:,:);
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
imshow(ca{c,r});
p=p+1;
end
end
the error is:
Error using ==> subplot at 309
Illegal plot number.
Error in ==> project at 22
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
That's because you're not calling subplot properly. It needs p as the parameter for the third argument, not temp. p determines which slot you want to place your figure in. You putting in a doublevector as the third parameter makes no sense. Also, ca contains 8 x 8 pixel blocks, and you'd like to show the DCT of each block. Your current code does not do this. Actually, X is what you're trying to find the DCT of, and it's all ones.... doesn't make much sense.
You probably want to show the DCT of each block inside the figure as well, not ca.... and so you need to do this:
for c=1:size(ca,1)
for r=1:size(ca,2)
temp = double(ca{c,r}); %// Change - cast to double for precision
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),p); %// Change
imshow(temp,[]); %// Change here too
p=p+1;
end
end
Note that I did imshow(temp,[]); so that we can contrast stretch the block so that the minimum value gets mapped to black while the maximum value gets mapped to white. Everything else is a shade of gray in between. Be advised that this doesn't change the image itself. It only changes it for display.
Suggestion
You should read up on my post on how subplot works here: How does subplot work and what is the difference between subplot(121) and subplot(1,2,1) in MATLAB?
Once you read through this post, you'll have a better understanding of how each parameter works for subplot, and how you can display graphs / images in a figure.
Minor Note
Looks like you took that code from this post but you didn't copy and paste properly :) That %// Change comment, as well as the variable name ca looked oddly familiar.

A few questions regarding 2D data points

I have had some success in the past with seeking help here at SO and have garnered many good hints and tips from you guys. I have run into three problems that I would really like help with.
Firstly here is a picture of the scatter plot I'm using as input:
Scatter plot
Here is the code I've used to generate that exact plot (minus the manual arrows/lines):
Source Code
I would like to know if someone could help me with three questions I have:
How do I programatically draw those lines I have entered manually given the points above? I've tried a LS approach and it produces ok(ish) results and I am uncertain of get 'tighter' straight lines.
There are sometimes outliers in my data that don't exactly conform with the other data in row/column fashion. Is there a way to remove such outliers (as seen in Point A on the Plot)?
Finally is there a way to calculate the 'centres' of each of the 'rectangles' given that the points aren't ordered in a specific order? Could one order these points in a specific order to help? Or is there a smarter way?
Thanks for taking the time to look at my question. I really hope somebody can help me with this - I've been wracking my brain trying to figure out how to do these things and I cannot come up with a solution.
EDIT: Removed the link to my LS approach as it is incorrect in the horizontal direction.
Alright, so I had a little downtime to try to lend a hand here. I think I can at least get you started on programatically drawing the lines and hopefully it will give you some insight into tackling the other two questions you have here.
I pretty much copied the code you had and started from there. What I paste here is what I've added/tweaked after you declared you cx and cy matricies.
Now to explain my thought process and logic. Cy is designed to be the "zipped" matrix of cx and cy but sorted along the Y coordinate value. Cx is the same except sorted along the X coordinate instead. The logic and such should be pretty straight forward there I hope. If not just say so and I'll explain!
Now the diffY and diffX. I took the difference of each coordinate (Xs and Ys seperately) since we know there is a pattern here that causes the XY pairs to form a grid-like shape. I'm essentially banking on the fact that there is a sizeable difference the the Y (or X) value for each line of points (horizontal and vertical). Once I have this difference between adjcent points I look for a difference greater than 2 (this is post-hoc after seeing what the differences were). The -1 is used to give me the actual end of the row instead of the start of the next row since we're going to be starting from item (1,:) in our list (makes more sense if you look at the lines in the code).
(This is of course a HUGE assumption and makes this specific for this particular data set. It can likely be generalized for most grid-like shapes though, but that has to be tested.)
Also a note. I did notice that later on in the list of points I gleaned using the difference my thought process started to break down. You can continue to plot more lines following the pattern I have in the code to see what I mean.
As far as your other two questions. You can likely take the idea that I have here and improve/expand upon it. I'm thinking that you should be able to snag the outlier by simply looking at all the points in a given row (idx[1] -> idx[2]) and making sure they fit along the line. Essentially requiring that they satisfy the general formula for the equation of a line that you can get from using the points that are used to draw the line. You will of course have to have a little error tolerance for that.
Then for the rectangle you can use the ordered group of points to create your rectangles and probably utilize the regionprops function to calculate the centroid (center in a 2D world) of a rectangle specified by the data points you can glean.
Best of luck!
Cy = zeros(length(cy),2);
[Cy(:,2), IX] = sort(cy);
Cy(:,1) = cx(IX)';
diffY = [0; diff(Cy(:,2))]
idx = find(diffY>2)-1
Cy(idx,:) % Last mark in given row, appears to be slight issue further along.
Cx = zeros(length(cx),2);
[Cx(:,1), IX] = sort(cx);
Cx(:,2) = cy(IX)';
diffX = [0; diff(Cx(:,1))]
idx2 = find(diffX>2)-1
Cx(idx2,:) % Last mark in given row, appears to be slightly off later on. (top of grid though)
%%
figure('Position',[0,0,c,r]);
scatter(Cy(:,1),Cy(:,2),'.');
axis([0 c 0 r])
set(gca,'YDir','reverse')
% Horizontal lines
line([Cy(1,1) Cy(idx(1),1)], [Cy(1,2) Cy(idx(1),2)], 'Color', 'red', 'LineWidth', 2)
line([Cy(idx(1)+1,1) Cy(idx(2),1)], [Cy(idx(1)+1,2) Cy(idx(2),2)], 'Color', 'red', 'LineWidth', 2)
line([Cy(idx(2)+1,1) Cy(idx(3),1)], [Cy(idx(2)+1,2) Cy(idx(3),2)], 'Color', 'red', 'LineWidth', 2)
% Vertical lines
line([Cx(1,1) Cx(idx2(1),1)], [Cx(1,2) Cx(idx2(1),2)], 'Color', 'red', 'LineWidth', 2)
line([Cx(idx2(1)+1,1) Cx(idx2(2),1)], [Cx(idx2(1)+1,2) Cx(idx2(2),2)], 'Color', 'red', 'LineWidth', 2)