How plot a messy random-size circles in MATLAB? [closed] - matlab

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am going to draw a figure such as below picture in the MATLAB R2014b: .
This figure consists of many circles with different (random) colors and random sizes.
How is it possible to plot such this figure in MATLAB R2014b?

Without spelling out the code:
Pick initial circle, e.g. Position [0,0] and radius 1.
Initialise list for positions and radii.
Pick random position and radius r.
If circle is not in big one (I.e. sqrt(pos(1)^2+pos(2)^2) + r > 1) continue with 3.
If overlap with other circles (distance between positions > sum of radii), continue with 3
Add circle to list, continue with 3
Update: Example
Alright, so I just wanted to try this. I'm sure this is not the best implementation, but:
% set number of circles to plot
n = 200;
radii = zeros(n, 1);
pos = zeros(n, 2);
allColours = lines(n);
% main loop
for idx = 1:n
is_good = false;
% generate random positions and radii until we have a hit
while ~is_good
pos(idx, :) = rand(1, 2)*2 - 1;
radii(idx) = rand * (1 - max(radii));
if ((sqrt(sum(pos(idx, :).^2)) + radii(idx) ) < 1) ... % ensure we're inside the big circle
&& ((idx == 1) || ... % and either it's the first circle, or
all(sqrt(sum((pos(1:(idx-1), :) - repmat(pos(idx, :), idx-1, 1)).^2, 2)) > radii(1:(idx-1))+radii(idx))) % all distances are bigger than sum of radii of existing circles
is_good = true;
end
end
end
%% plot
figure(2);
clf;
hold on
set(gca, 'visible', 'off')
daspect([1, 1, 1])
rectangle(...
'Position',[-1 -1 2 2],...
'Curvature', [1 1],...
'FaceColor', 'none',...
'EdgeColor', [ 0, 0, 0]);
for idx = 1:n
rectangle(...
'Position',[pos(idx, 1) - radii(idx), pos(idx, 2) - radii(idx), 2*radii(idx), 2*radii(idx)],...
'Curvature', [1 1],...
'EdgeColor','none',...
'FaceColor', allColours(idx,:));
end

The general idea is below. You'll need to modify it to ensure the circle centers and colors are chosen to suit your particular purpose.
% Define parameters
maxAxis = 100;
maxRadius = 10;
nCircles = 20;
% Random centres
xLoc = randi(maxAxis,nCircles);
yLoc = randi(maxAxis,nCircles);
% Random radii
radius = randi(maxRadius,nCircles);
% Random colours
allColours = rand(nCircles,3);
% Transform the data into position = [left bottom width height]
pos = [xLoc(:)-radius(:) yLoc(:)-radius(:) 2*radius(:)*[1 1]];
% Create and format the axes
ha = axes;
hold on;
axis equal;
box on;
set(ha,'XTickLabel',[],'YTickLabel',[]);
% Create the circles (must be done in loop)
for idx = 1:nCircles
rectangle(...
'Position',pos(idx,:),...
'Curvature',[1 1],...
'FaceColor',allColours(idx,:),...
'EdgeColor','none');
end
See
>> doc retangle
for more info.

Related

Create 3D effect of 2D line plot matlab [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Question, I have a line data. However I wanted to be plotted with a 3D effect, which you can also choose as an option, for instance, within Office Excel/Powerpoint.
Currently I have the code below which kind of mimmics the effect (simply putting a lot of plots after each other):
Excel:
Matlab:
Matlab code:
x = 1:10;
y = rand(1, 10);
z = rand(1, 10);
figure;
hold on;
for i = 1:20
hFill = fill3(i*0.01*ones(1, 12), x([1 1:end end]), [0 y 0], 'b', 'FaceAlpha', 0.5);
hFill = fill3((i*0.01*(ones(1, 12)))+2, x([1 1:end end]), [0 z 0], 'g', 'FaceAlpha', 0.5);
end
grid on;
xlim([0 10]);
view(3);
You could probably construct a closed surface in one single graphic object to represent your 3D curve, however I don't have time to work that out completely so I'll go the lazy way:
Instead of stacking multiple fill objects to give a 3d feeling, I build each curve with 3 objects:
A top surface, with the desired thickness
2 patch objects to close the sides
Here goes:
%% Sample data
rng(12)
x = 1:10;
y = rand(1, 10) + .5 ;
z = rand(1, 10) + .5 ;
%% Parameters
alphaTop = .5 ; % alpha value of the top of the surface
alphaSide = .5 ; % alpha value of the sides
thickness = .5 ; % thickness of each curve
separation = 1 ; % separation of each curve
colors = {'b';'r'} ; % color for each curve
%% prepare patch coordinates
xp = x([1 1:end end 1]) ;
yp1 = [0 y 0 0] ;
yp2 = [0 z 0 0] ;
zp1 = zeros(size(yp1)) ;
zp2 = zeros(size(yp2)) + 1 ;
%% Prepare surface coordinates
xs = [ xp; xp] ;
ys1 = [yp1;yp1] ;
ys2 = [yp2;yp2] ;
zs1 = zeros(size(xs)) ;
zs1(2,:) = zs1(2,:) + thickness ;
zs2 = zs1 + separation ;
%% Display
figure
hold on
% plot the sides (one patch on each side of each curve)
hp11 = patch(zp1 ,xp,yp1, colors{1} , 'FaceAlpha', alphaSide) ;
hp12 = patch(zp1+thickness,xp,yp1, colors{1} , 'FaceAlpha', alphaSide) ;
hp21 = patch(zp2 ,xp,yp2, colors{2} , 'FaceAlpha', alphaSide) ;
hp22 = patch(zp2+thickness,xp,yp2, colors{2} , 'FaceAlpha', alphaSide) ;
% plot the top surfaces
hs1 = surf(zs1,xs,ys1, 'FaceColor',colors{1},'FaceAlpha',alphaTop) ;
hs2 = surf(zs2,xs,ys2, 'FaceColor',colors{2},'FaceAlpha',alphaTop) ;
% refine plot
xlim([0 10]);ylim([0 10]); view(3);
xlabel('X') ; ylabel('Y') ; zlabel('Z') ;
Which yields:
Once this is built, you can regroup the graphic handles to group common properties assignments. For example:
%% Optional (modify common properties in group)
% regroup graphic handles for easy common property assignment
hg1 = [hp11;hp12;hs1] ;
hg2 = [hp21;hp22;hs2] ;
% set properties in group
set(hg1,'EdgeColor',colors{1},'FaceAlpha',0.2) ;
set(hg2,'EdgeColor',colors{2},'FaceAlpha',0.2) ;
To give your curves a nice transparent mesh style:
Ultimately, if you plan to apply this method to many curves, you should either package it in a function, or at least build your curves with a loop. It should be easy to convert as long as the parameters for each curve are in an array you can index into (like I did for the colors).

MATLAB legend does not work for plotting 2 circles

close all; clc; clear all;
A0 = 1.5; % meters
lambda = 100 % meters
k = (2*pi)/lambda;
T = 3600 % Period in seconds
ome = 2*pi/T; % omega
x = 0; z = 0;
t = linspace(0,7200,100); % 2 periods, 100 data
zz=0;
for z = 0:20:20;
zz = zz+1;
% multiplied by 100, unit in cm/s
u= 100.*ome*A0*exp(-k*z)*sin(k*x - ome*t);
w = 100.*-ome*A0*exp(-k*z)*cos(k*x - ome*t);
uu(zz,:) = u; % size(uu) 2 100
ww(zz,:) = w; % size(ww) 2 100
end
figure(1)
color = -0.8;
for zz = 1:2
color = color + 0.8;
for i=1:3:49; % plot circle for one period
plot([uu(zz,i) uu(zz,i+3)],[ww(zz,i) ww(zz,i+3)], 'color',([color+0.2 0 0]), 'linewidth', 2)
hold on
end
end
title('Plot of lines from (0,0) to (u(i), v(i). Radius or amplitude in cm/s')
axis equal;
grid on;
legend('radius at surface','radius at depth 20')%
This script plots 2 circles: the small one is red, another is black. But the legend is not consistence with these circles.
this is because you create many line objects in your axes (each loop iteration when you do plot) and the legend function addresses these line objects. sp line1 and line2 are still part of the polygon you draw.
I'll answer your question, but know that your code is sub-optimal and that it is not the best way to draw 2 circles or polygons.
so with minimal change to your code this is what you can do:
....
figure(1)
color = -0.8;
for zz = 1:2
color = color + 0.8;
for i=1:3:49; % plot circle for one period
h(zz)=plot([uu(zz,i) uu(zz,i+3)],[ww(zz,i) ww(zz,i+3)], 'color',([color+0.2 0 0]), 'linewidth', 2)
hold on
end
end
title('Plot of lines from (0,0) to (u(i), v(i). Radius or amplitude in cm/s')
axis equal;
grid on;
legend([h(1) h(2)],{'radius at surface','radius at depth 20'});

Finding the most common point of intersection among plotted triangles

I plotted a set of triangles using the code below:
A=[1, 1; 1, 5; 3, 9; 4, 2;9,9];
plot(A(:,1),A(:,2),'oc','LineWidth',2,'MarkerSize',5);
axis([0 10 0 10]);
grid on
for ii = 1:size(A, 1) - 1
for jj = ii + 1:size(A, 1)
line([A(ii, 1), A(jj, 1)], [A(ii, 2), A(jj, 2)])
end
end
The problem is, i will like the plot to indicate the region with the highest number of intersections. In this particular code, the region is the black polygon (i had to indicate this region manually).
Please can anyone help out with this problem. Thanks
Here is a variant with a more graphical approach.
Create a grid of points
Check the number of triangles that a point
is inside
Plot the points with highest number of intersecting
triangles
The code
% Create the combination of all points that make the triangles
% This could be used to plot the lines as well
N = size(A,1);
comb = [];
for i = 1:N-2
for j = i+1:N-1
comb = [comb; repmat([i j], N-j,1) (j+1:N)']; %#ok<AGROW>
end
end
nComb = size(comb,1);
% Create a mesh grid
dg = 0.1; % Resolution - tune this!
gridEdge = [min(A);max(A)];
[X, Y] = meshgrid(gridEdge(1,1):dg:gridEdge(2,1), gridEdge(1,2):dg:gridEdge(2,2));
% Check if a point is inside each triangle
[isInside, onEdge] = deal(zeros(numel(X),nComb));
for i = 1:nComb
[isInside(:,i), onEdge(:,i)] = inpolygon(X(:),Y(:),A(comb(i,:),1),A(comb(i,:),2));
end
% Remove points on edge
isInside = isInside - onEdge;
% Get index of points with most intersection
inTri = sum(isInside,2);
idx = find(inTri == max(inTri));
% Plot result
hold on
plot(X(idx),Y(idx),'.')
text(mean(X(idx)),mean(Y(:)),num2str(max(inTri)),'FontSize',20)

Plotting too slow on Matlab

I am having some issues with a code I am writing, simply because it is too long to plot. What I am trying to do is for matlab to plot a series of ellipses filled with colors depending on a specific parameter.
Here is the code I am using:
clearvars -except data colheaders
close all
clc
data(:,15)=data(:,9)*pi/180; % Convers Column 9 (angle of rotation) in rad
data(:,16)=1196-data(:,6); % Reset the Y coordinate axis to bottom left
delta = 0 : 0.01 : 2*pi; % Converts roation angle in rad
theta=45*pi/180; % Sample cutting angle
imax=5352; % Numbers of rows in data sheet
% Define variables for colors
beta=acos(data(1:imax,8)./data(1:imax,7));%./acos(0);
phi=atan(sin(beta).*cos(data(1:imax,15))./(sin(theta)*sin(beta).*sin(data(1:imax,15))+cos(theta)*cos(beta)))/(pi/2);
phi2=phi/2+1/2; % Set phi within 0 and 1 for colormap
gamma=atan((cos(theta)*sin(beta).*sin(data(1:imax,15))-sin(theta)*cos(beta))./...
(sin(theta)*sin(beta).*sin(data(1:imax,15))+cos(theta)*cos(beta)))/(pi/2);
gamma2=gamma+1/2; % Set gamma between 0 and 1 for colormap
cm = colormap(jet) ; % returns the current color map
% Sort and get their index to access the color array
[~,idx] = sort(phi);
for i=1:imax
x = data(i,7)/2 * cos(delta) * cos(data(i,15)) - data(i,8)/2 * sin(delta) * sin(data(i,15)) + data(i,5);
y = data(i,8)/2 * sin(delta) * cos(data(i,15)) + data(i,7)/2 * cos(delta) * sin(data(i,15)) + data(i,16);
colorID1 = max(1, sum(phi2(i) > [0:1/length(cm(:,1)):1]));
colorID2 = max(1, sum(gamma2(i) > [0:1/length(cm(:,1)):1]));
ColorMap1(i,:) = cm(colorID1, :); % returns your color
ColorMap2(i,:) = cm(colorID2, :); % returns your color
hold on
% Columns (5,6) are the centre (x,y) of the ellipse
% Columns (7,8) are the major and minor axes (a,b)
% Column 9 is the rotation angle with the x axis
figure(1);
fill(x,y,ColorMap1(i,:),'EdgeColor', 'None');
title('Variation of In-plane angle \phi')
colorbar('SouthOutside')
grid on;
caxis([-90 90])
%text(data(i,5),data(i,16),[num2str(0.1*round(10*acos(0)*180*phi(i)/pi))])
figure(2);
fill(x,y,ColorMap2(i,:),'EdgeColor', 'None');
title('Variation of Out-of-plane angle \gamma')
colorbar('SouthOutside')
grid on;
caxis([-45 45])
%text(data(i,5),data(i,16),[num2str(0.1*round(10*acos(0)*180*gamma(i)/pi))])
% Assigns angle data to each ellipse
end
axis equal;
Maybe someone knows how to make that it doesnt take ages to plot ( i know figure is a bad method, but I want 2 specific colormap for the 2 variables phi and gamma).
Cheers guys
Example data you can use to run the code
data(:,5) = [3 ;5 ;12; 8]; % Centre location X
data(:,6) = [1; -5 ;-2; 4]; % Centre location Y
data(:,7) = [6 ;7;8;9]; % Major Axis a
data(:,8) = [2;3;3;5]; % Minor axis b
data(:,9) = [10;40;45;90]; % Angle of rotation
All you need to do is change imax for 4 instead of 5352 and it should work
Dorian

Draw log graph curve on Matlab by clicking?

I'd like to draw a curve on an empty (semilog-y) graph by clicking the points I want it to run through, on the X-Y plane.
Is there a function for this?
edit: I'm trying to do this by obtaining the position of last pointer click -
axis([0 3000 0 1000]);
co=get(gcf, 'CurrentPoint');
It seems to return the cursor position at the time of execution, but it does not change later.
edit2: Here's what works for me. The actual drawing I can do by using the arrays of points collected.
clear
clc
h=plot(0);
grid on;
xlim([0 3000]);
ylim([0 1000]);
datacursormode on;
% Enlarge figure to full screen.
screenSize = get(0,'ScreenSize');
set(gcf, 'units','pixels','outerposition', screenSize);
hold on;
% Print the x,y coordinates - will be in plot coordinates
x=zeros(1,10); y=zeros(1,10);
for p=1:10;
[x(p),y(p)] = ginput(1) ;
% Mark where they clicked with a cross.
plot(x(p),y(p), 'r+', 'MarkerSize', 20, 'LineWidth', 3);
% Print coordinates on the plot.
label = sprintf('(%.1f, %.1f)', x(p), y(p));
text(x(p)+20, y(p), label);
end
Not really, but now there is:
function topLevel
%// parameters
xrange = [0 100];
yrange = [1e-4 1e4];
%// initialize figure, plot
figure, clf, hold on
plot(NaN, NaN);
axis([xrange yrange]);
set(gca, 'YScale', 'log')
t = text(sum(xrange)/2, sum(yrange)/2, ...
'<< Need at least 3 points >>',...
'HorizontalAlignment', 'center');
%// Main loop
xs = []; p = [];
ys = []; P = [];
while true
%// Get new user-input, and collect all of them in a list
[x,y] = ginput(1);
xs = [xs; x]; %#ok<AGROW>
ys = [ys; y]; %#ok<AGROW>
%// Plot the selected points
if ishandle(p)
delete(p); end
p = plot(xs, ys, 'rx');
axis([xrange yrange]);
%// Fit curve through user-injected points
if numel(xs) >= 3
if ishandle(t)
delete(t); end
%// Get parameters of best-fit in a least-squares sense
[A,B,C] = fitExponential(xs,ys);
%// Plot the new curve
xp = linspace(xrange(1), xrange(end), 100);
yp = A + B*exp(C*xp);
if ishandle(P)
delete(P); end
P = plot(xp,yp, 'b');
end
end
%// Fit a model of the form y = A + B·exp(C·x) to data [x,y]
function [A, B, C] = fitExponential(x,y)
options = optimset(...
'maxfunevals', inf);
A = fminsearch(#lsq, 0, options);
[~,B,C] = lsq(A);
function [val, B,C] = lsq(A)
params = [ones(size(x(:))) x(:)] \ log(abs(y-A));
B = exp(params(1));
C = params(2);
val = sum((y - A - B*exp(C*x)).^2);
end
end
end
Note that as always, fitting an exponential curve can be tricky; the square of the difference between model and data is exponentially much greater for higher data values than for lower data values, so there will be a strong bias to fit the higher values better than the lower ones.
I just assumed a simple model and used a simple solution, but this gives a biased curve which might not be "optimal" in the sense that you need it to be. Any decent solution really depends on what you want specifically, and I'll leave that up to you ^_^