I have a vector of 1000 random numbers biased towards the bounds of 540 and 600. I need to plot this data as a wriggly circular path between two concentric circles of radii 540 and 600 respectively. How do I do this?
Presently, I'm able to plot the concentric circles of given radii, but if I try to plot the given random data which is between the bounds 540 and 600, it is plotted along the width between the two concentric circles. I want it to be plotted as a noisy circular curve between the concentric circles.
I hope I'm able to explain my point
If anyone can tell me, how do I do that. Thanks
Here is the link to my previous post, wherein I had to generate random numbers biased towards the two well defined bounds
Generating random numbers in matlab biased towards the boundaries
Now I need to plot the same data, as explained above.
This is the image I get:
What you actually want is a circular plot, so the first idea that comes to my mind is to use polar coordinate.
First we get your sample of around 1000 random datas biased to the bounds of your [540 600] interval following that.
Note that this algorithm will not always get you exactly 1000 values as the out of bound values are removed.
So we'll do something like this :
%Get the size of the sample
P=length(X);
% Generate P Angles uniformly distributed between 0 and 2*pi*(P-1)/P
% Note generating an angle equal to 0 and an angle equal to 2*pi would
% mean that we have 2 points with the same angle, and that s something
% you generally want to avoid
Angles=(0:P-1)*(2*pi/P);
% Plot your points with the markers (polar coordinates) in '-+',
% - means that you want a line to be drawn between the points and
% + means that you want a + marker on every point
plot(X.*cos(Angles),X.*sin(Angles),'-+');
%tell matlab to wait so you can add the circles
hold on
% add circle of 540 radius
plot(540*cos(Angles),540*sin(Angles),'-r');
%add circle of 600 radius
plot(600*cos(Angles),600*sin(Angles),'-r');
For the final result of :
Update : About getting the angles randomly distibuted
We'll have to define our Angles diffrently. We still need a vector of length P, but randomly distributed. This can be achieved by taking P random numbers between 0 and 1, and then multiply this vector by 2*pi in order to get randomly distributed values between 0 and 2*pi.
Last step is to order this vector in order to keep the ordering of your data.
Temp=rand(1,P)*2*pi;
Angles=sort(Temp);
For a final result of :
Another lead woult be to take a sample of 1000 gaussian random numbers and use them modulo 2*pi :
Angles=sort(mod(randn(1,P)*2*pi,2*pi));
Related
I have an array of different length measurements to the walls of an arbitrarily shaped box from a point. They are taken during a 360 degree rotation and I also have a degree measurement.
Distance(1:k); % distance to wall of arbitrarily shaped box during a rotation
Degree(1:k); % degrees rotated from first measurement
Time(1:k); % time passed since first measurement
How can I used distance and Time/Distance to plot a shape that would look like the shape of the box? I tried the convhull function, wondering if there are better options.
Would this do the trick?
Rads=Degrees*(2*pi/360);
X=Distance.*cos(Rads);
Y=Distance.*sin(Rads);
plot(X,Y);
I have a matrix consisting of three rows: gene 1, gene 2, Distance.
I want to create a network where each gene is a node and the connecting line is scaled by the distance between the two genes.
How can I do this without using the bioinformatics or neural network toolboxes?
Thanks!
Some Information
It is almost impossible to draw a graph with edge length proportional to edge weight, atleast its very unlikely that the weights allow a graph to be drawn this way, most will be impossible...
See:
P. Eades and N. C. Wormald. Fixed edge-length graph drawing is
NP-hard. Discrete Applied Mathematics, 28(2):111–134, 1990]
or to quote:
"Drawing planar graphs with edge weights as standard node-link
diagram, where edge lengths are proportional to the edge weights, is
an NP-hard problem"
M. Nollenburg, R. Prutkin and I. Rutter, Edge-weighted contact
representations of planar
graphs.
Journal of Graph Algorithms and Applications, 17(4):441–473, 2013
Consider the simple example of the 3 vertices joined as such, in your data format:
[1,2,1;
1,3,1;
2,3,10;]
it's should be immediately obvious that such a graph is impossible to draw with edge length proportional to weight (with straight lines). As such alternatives in MATLAB include using color or line width to represent Weight.
Sorry for the length of this answer but to implement this is not trivial, the process used below for drawing the graph can also be found here (in debth), here (most simple) and in a similar problem here. However these do not address weighted graphs...
So on with implementing line width and color proportional to weight:
Code
Due to the length the code is available without description here
Firstly some test data, consisting of 30 edges randomly assigned between 20 vertices with random weights between 0 and 10.
clear
%% generate testing data
[X,Y] = ndgrid(1:20); testdata = [X(:) Y(:)]; %// all possible edges
data(data(:,1)==data(:,2),:)=[]; %// delete self loops
data=data(randperm(size(data,1),20),:); %// take random sample of edges
data(:,3)=rand(size(data,1),1)*10; %// assign random weights in range 0-10
First some processing of the data to get it into required format;
edges=data(:,1:2);
[Verticies,~,indEdges]=unique(edges); %// get labels & locations of vertices
indEdges=reshape(indEdges,[],2);
weights=data(:,3);
normalisedWeights=weights/max(weights); %// normalise weights (range 0-1)
numeEdge=numel(weights);
numVertex=numel(Verticies);
Now x and y coordinates for each vertex are created on a unit circle:
theta=linspace(0,2*pi,numVertex+1);
theta=theta(1:end-1);
[x,y]=pol2cart(theta,1); % create x,y coordinates for each vertex
As lines in MATLAB plots inherit their color from the axis color order we create a RGB array which corresponds to a colormap, with a entry for each line giving the RGB values for the color assigned to that weight.
The autumn colormap is simple to manually implement as R=1,B=0 for all values and G ranges from 0-1 linearly, so we can make the Cmap variable which is used as the axis color order as follows:
clear Cmap %// to avoid errors due to the way it is created
Cmap(:,2)=normalisedWeights;
Cmap(:,1)=1;
Cmap(:,3)=0;
Now we create a figure, set the colormap to autumn (for the color bar), put hold on so the plot command doesn't reset the color order, and apply the color order
figure
colormap('autumn')
hold on
set(gca,'colororder',Cmap) %// set axis colororder to Cmap
how we plot the edges using the edge indexes generated earlier at locations given by x & y. The handles of the lines (Hline) is stored for later use.
Hline=plot(x(indEdges).',y(indEdges).'); %// plot edges
Now we set the axis to square so the circle of points is displayed properly and turn the axis off to hide them (as they bear no relevance to the plotted graph). The axis color limits (Clim) is then set to match the range of weights and add a colorbar is added.
axis square off
set(gca,'Clim',[0 max(weights)])
colorbar
The final step for plotting the edges, setting the line width to be proportional to weight, The normalised weights are scaled to be in the range 0-5. The linewidths are then set to scalefactor*normalisedWeights..
scalefactor=5; %// scale factor (width of highest weight line)
set(hline, {'LineWidth'}, num2cell(normalisedWeights*scalefactor));
The vertices are now plotted at the x and y coordinates (as black squares here).
The axis limits are increased to allow vertex labels to fit. Finally the vertices are labelled with the values from the original matrix, the labels are placed on a slightly larger circle than the vertices
plot(x,y,'ks')
xlim([-1.1,1.1]) % expand axis to fix labels
ylim([-1.1,1.1])
text(x(:)*1.1, y(:)*1.1, num2str(Verticies),...
'FontSize',8,'HorizontalAlignment','center'); %// add Vertex labels
Results
I want to assign vector to a contourf graph, in order to show the direction and magnitude of wind.
For this I am using contourf(A) and quiver(x,y), where as A is a matrix 151x401 and x,y are matrices with the same sizes (151x401) with magnitude and direction respectively.
When I am using large maps i get the position of the arrows but they are to densily placed and that makes the graph look bad.
The final graph has the arrows as desired, but they are to many of them and too close, I would like them to be more scarce and distributed with more gap between them, so as to be able to increase their length and at the same time have the components of the contour map visible.
Can anyone help , any pointers would be helpful
i know its been a long time since the question was asked, but i think i found a way to make it work.
I attach the code in case someone encounters the same issues
[nx,ny]= size(A) % A is the matrix used as base
xx=1:1:ny; % set the x-axis to be equal to the y
yy=1:1:nx; % set the y-axis to be equal to the x
contourf(xx,yy,A)
hold on, delta = 8; %delta is the distance between arrows)
quiver(xx(1:delta:end),yy(1:delta:end),B(1:delta:end,1:delta:end),C(1:delta:end,1:delta:end),1) % the 1 at the end is the size of the arrows
set(gca,'fontsize',12);, hold off
A,B,C are the corresponding matrices ones want to use
I am looking for help for my particular problem.
I have a contour plot created from XYZ data. This plot contains 2 broad peaks with one more intense than the other.
When the most intense peak is aligned with the Y axis, I can perform a fitting of every YZ curve at each X values. I usually do a gaussian fit to plot the peak center on the same graph.
In some cases I need to perform the same fitting but no along the Y axis direction (in this case I just plot YZ scan at every different X values) but along another arbitrary direction.
For the moment the only way I found is the following:
-plot the contour plot and find for the position of the most intense peak
-if the position is not aligned with the Y axis, then rotate all the datas and plot again the contour
-perform the YZ gaussian fit for every X value
- Rotate the resulting XY position to go back to the original plot
-plot the XY position as a line on the original contour plot
this is quite long and requires a lot of memory. i would like ot know if there is a more elegant/faster way.
Thanks for your help
David
I take it you want to extract data from the (x,y,z) data along some arbitrary line in order to make a fit. A contour plot will show only part of the data, the full z(x,y) data can be shown with imagesc etc. Say you want the data along line defined by two points (x1,y1) -> (x2,y2). According to the eq of the line, the line y=a*x+b the slope a is (y2-y1)/(x2-x1) and b=y1-a*x1. For example, I'll select (x,y) coordinates in the following contour:
Create data and end points:
m=peaks(100);
x1=11 ; x2=97;
y1=66; y2=40;
Thus the line parameters are:
a=(y2-y1)/(x2-x1);
b=y1-a*x1;
and the line is:
x=x1:x2;
y=round(a*x+b);
select the proper (x,y) elements using linear indexing:
ind=sub2ind(size(m),y,x)
plot:
subplot(2,1,1)
contour(m,10); hold on
line([x1 x2],[y1 y2],'Color',[1 0 0]);
subplot(2,1,2)
plot(m(ind))
You can now use vec=m(ind) to fit your function.
If I explain why, this might make more sense
I have a logical matrix (103x3488) output of a photo of a measuring staff having been run through edge detect (1=edge, 0=noedge). Aim- to calculate the distance in pixels between the graduations on the staff. Problem, staff sags in the middle.
Idea: User inputs co-ordinates (using ginput or something) of each end of staff and the midpoint of the sag, then if the edges between these points can be extracted into arrays I can easily find the locations of the edges.
Any way of extracting an array from a matrix in this manner?
Also open to other ideas, only been using matlab for a month, so most functions are unknown to me.
edit:
Link to image
It shows a small area of the matrix, so in this example 1 and 2 are the points I want to sample between, and I'd want to return the points that occur along the red line.
Cheers
Try this
dat=imread('83zlP.png');
figure(1)
pcolor(double(dat))
shading flat
axis equal
% get the line ends
gi=floor(ginput(2))
x=gi(:,1);
y=gi(:,2);
xl=min(x):max(x); % line pixel x coords
yl=floor(interp1(x,y,xl)); % line pixel y coords
pdat=nan(length(xl),1);
for i=1:length(xl)
pdat(i)=dat(yl(i),xl(i));
end
figure(2)
plot(1:length(xl),pdat)
peaks=find(pdat>40); % threshhold for peak detection
bigpeak=peaks(diff(peaks)>10); % threshold for selecting only edge of peak
hold all
plot(xl(bigpeak),pdat(bigpeak),'x')
meanspacex=mean(diff(xl(bigpeak)));
meanspacey=mean(diff(yl(bigpeak)));
meanspace=sqrt(meanspacex^2+meanspacey^2);
The matrix pdat gives the pixels along the line you have selected. The meanspace is edge spacing in pixel units. The thresholds might need fiddling with, depending on the image.
After seeing the image, I'm not sure where the "sagging" you're referring to is taking place. The image is rotated, but you can fix that using imrotate. The degree to which it needs to be rotated should be easy enough; just input the coordinates A and B and use the inverse tangent to find the angle offset from 0 degrees.
Regarding the points, once it's aligned straight, all you need to do is specify a row in the image matrix (it would be a 1 x 3448 vector) and use find to get non-zero vector indexes. As the rotate function may have interpolated the pixels somewhat, you may get more than one index per "line", but they'll be identifiable as being consecutive numbers, and you can just average them to get an approximate value.