Coloring the Mandelbrot set in Matlab - matlab

I made a program to calculate points that are in the mandelbrot set. For the points not belonging to the mandelbrot set I keep track of how many iterations it take for the starting point to diverge to where the magnitude is greater that 2. Basically for every point not in the mandelbrot set I have a counter of how fast it diverges on a scale of 1 to 256. What id like to do is give each point a color according to how fast it diverges. For instance the points that diverge in 255 iterations could be white and the faster it diverges the more it gets colored. I've made an easy adjustment where diverging points that diverge in more than 20 steps are colored red, the ones that diverge in 10-19 steps are blue and one that diverge in 5-9 steps are yellow and it looks like this.
Now I cant do this for all possible 255 rates of divergence. How can I make a graduating scale and implement it in Matlab. Thanks in advance for any help. If anyone would like to know any more please ask. Thanks!
EDIT I am sorry but the image seems to not work. Basically what I need it this. I am plotting points, to each point a value between 1 and 255 is assigned and I want the color to gradually change depending on the value assigned to it. Thanks!

A simple approach to plotting the mandelbrot set in Matlab is as follows
function mandelbrot(n, niter)
x0 = -2; x1 = 1;
y0 = -1.5; y1 = 1.5;
[x,y] = meshgrid(linspace(x0, x1, n), linspace(y0, y1, n));
c = x + 1i * y;
z = zeros(size(c));
k = zeros(size(c));
for ii = 1:niter
z = z.^2 + c;
k(abs(z) > 2 & k == 0) = niter - ii;
end
figure,
imagesc(k),
colormap hot
axis square
This just keeps track of the number of iterations until divergence in the array k, and plots it using a linear color scale by using imagesc. The result is
>> mandelbrot(800, 40)

The image doesn't come in the link and I don't know Matlab, but can you not make the color of each point a function of its divergence? A lot of tools will allow you to specify RGB values, say, from 0-255. Can you not input its divergence for all three RGB values (or whatever color scale you're using) to get shades of gray? i.e. RGB(20,20,20)

I did a little improvement to the code, this will now run given a specific starting point for (x,y) and a starting position. For those looking to zoom in a little further.
function mandelbrot(n, n2, x0, y0, g)
x1 = x0 - g; x2 = x0 + g;
y1 = y0 - g; y2 = y0 + g;
[x,y] = meshgrid(linspace(x1, x2, n), linspace(y1, y2, n));
c = x + 1i * y;
z = zeros(size(c));
k = zeros(size(c));
for ii = 1:n2
z = z.^2 + c;
k(abs(z) > 2 & k == 0) = n2 - ii;
end
figure,
imagesc(k),
colormap hot
axis square
end

Related

Spiral of non-overlapping circles

I want to create a spiral of circle markers which never overlap with each other. This is what I got so far, but it overlaps the first markers, and the last ones are too far apart from each other.
t = pi : pi/20 : 20*pi;
t = asind(1./t);
r = t;
x = r .* cos(t);
y = r .* sin(t);
plot(x,y,'o-');
axis equal; hold on
Plotting without redefining t as asinf(1/t) as follows, is shown in the second plot.
t = pi : pi/20 : 20*pi;
r = t;
x = r .* cos(t);
y = r .* sin(t);
plot(x,y,'o-');
Any ideas on how does the spacing of the angles t must be to accomplish that the markers don't overlap?
You can approximate the arc length, greatly simplifying Gilles-Phillipe's solution. This is a simplification, which means that the distance between the markers is not identical everywhere. However the distances are fairly consistent, especially further out.
The approximation here is to assume that the spiral is, locally, a circle. The arc length then is r*dt at a position in the spiral a distance r from the origin, for a change in angle of dt radian.
We now no longer need to solve symbolic equations. I wrote the code in a loop. I'm sure it's possible to vectorize it, making the whole thing two lines of code, but I'll leave that as an exercise to the reader.
This is the code:
d = 1; % step size
q = 1/(2*pi); % spiral constant -- radius grows by q every 1 radian turn
N = 300; % number of points
t = 0; % initial angle
r = d; % initial radius
p = zeros(100,2);
p(1,:) = [r*cos(t),r*sin(t)]; % first point
for ii=2:N
dt = d/r;
t = t+dt;
r = r+dt*q;
p(ii,:) = [r*cos(t),r*sin(t)];
end
clf
plot(p(:,1),p(:,2),'o-')
axis equal
Try this:
syms s;
scale = 10;
l = scale/2 : scale/2 : 40*scale;
t = double(arrayfun(#(y) vpasolve((0.5*(s*sqrt(1+s^2)+asinh(s)))==y,s), l));
x = t .* cos(t);
y = t .* sin(t);
plot(x,y,'o-');
pbaspect([1 1 1]);
axis(scale*[-5 5 -5 5])
The idea is to parameterize using the arclength of the curve. The arclength of this spiral is l=1/2*(t*sqrt(1+t*t)+asinh(t)) (can be found using Matlab symbolic integration). To place points uniformly, we do a uniform sampling of the arclength, and find the corresponding t by solving the equation. Since it cannot be solved easily symbolically, we use a numerical solver.
Note that the scale and the aspect ratio of the plot is really important for it to look uniform and non-overlapping. This is why I added axis/ratio definition. Since each point is solved numerically, it can take quite some time to evaluate. There may be a faster way to do it, but at least you have a result.
I obtain the following result:

Ideas for reducing the complexity of a 3D density function for generating a ternary surface plot in Matlab

I have a 3D density function q(x,y,z) that I am trying to plot in Matlab 8.3.0.532 (R2014a).
The domain of my function starts at a and ends at b, with uniform spacing ds. I want to plot the density on a ternary surface plot, where each dimension in the plot represents the proportion of x,y,z at a given point. For example, if I have a unit of density on the domain at q(1,1,1) and another unit of density on the domain at q(17,17,17), in both cases there is equal proportions of x,y,z and I will therefore have two units of density on my ternary surface plot at coordinates (1/3,1/3,1/3). I have code that works using ternsurf. The problem is that the number of proportion points grows exponentially fast with the size of the domain. At the moment I can only plot a domain of size 10 (in each dimension) with unit spacing (ds = 1). However, I need a much larger domain than this (size 100 in each dimension) and much smaller than unit spacing (ideally as small as 0.1) - this would lead to 100^3 * (1/0.1)^3 points on the grid, which Matlab just cannot handle. Does anyone have any ideas about how to somehow bin the density function by the 3D proportions to reduce the number of points?
My working code with example:
a = 0; % start of domain
b = 10; % end of domain
ds = 1; % spacing
[x, y, z] = ndgrid((a:ds:b)); % generate 3D independent variables
n = size(x);
q = zeros(n); % generate 3D dependent variable with some norm distributed density
for i = 1:n(1)
for j = 1:n(2)
for k = 1:n(2)
q(i,j,k) = exp(-(((x(i,j,k) - 10)^2 + (y(i,j,k) - 10)^2 + (z(i,j,k) - 10)^2) / 20));
end
end
end
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
x(isnan(x)) = 0; % set coordinate (0,0,0) to 0
y(isnan(y)) = 0; % set coordinate (0,0,0) to 0
z(isnan(z)) = 0; % set coordinate (0,0,0) to 0
xP = reshape(x,[1, numel(x)]); % create a vector of the proportions of x
yP = reshape(y,[1, numel(y)]); % create a vector of the proportions of y
zP = reshape(z,[1, numel(z)]); % create a vector of the proportions of z
q = reshape(q,[1, numel(q)]); % create a vector of the dependent variable q
ternsurf(xP, yP, q); % plot the ternary surface of q against proportions
shading(gca, 'interp');
colorbar
view(2)
I believe you meant n(3) in your innermost loop. Here are a few tips:
1) Loose the loops:
q = exp(- ((x - 10).^2 + (y - 10).^2 + (z - 10).^2) / 20);
2) Loose the reshapes:
xP = x(:); yP = y(:); zP = z(:);
3) Check Total once, instead of doing three checks on x,y,z:
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
Total( abs(Total) < eps ) = 1;
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
PS: I just recognized your name.. it's Jonathan ;)
Discretization method probably depends on use of your plot, maybe it make sense to clarify your question from this point of view.
Overall, you probably struggling with an "Out of memory" error, a couple of relevant tricks are described here http://www.mathworks.nl/help/matlab/matlab_prog/resolving-out-of-memory-errors.html?s_tid=doc_12b?refresh=true#brh72ex-52 . Of course, they work only up to certain size of arrays.
A more generic solution is too save parts of arrays on hard drive, it makes processing slower but it'll work. E.g., you can define several q functions with the scale-specific ngrids (e.g. ngridOrder0=[0:10:100], ngridOrder10=[1:1:9], ngridOrder11=[11:1:19], etc... ), and write an accessor function which will load/save the relevant grid and q function depending on the part of the plot you're looking.

Parabola plot with data in Octave

I have been trying to fit a parabola to parts of data where y is positive. I am told, that P1(x1,y1) is the first data point, Pg(xg,yg) is the last, and that the top point is at x=(x1+xg)/2. I have written the following:
x=data(:,1);
y=data(:,2);
filter=y>0;
xp=x(filter);
yp=y(filter);
P1=[xp(1) yp(1)];
Pg=[xp(end) yp(end)];
xT=(xp(1)+xp(end))/2;
A=[1 xp(1) power(xp(1),2) %as the equation is y = a0 + x*a1 + x^2 * a2
1 xp(end) power(xp(end),2)
0 1 2*xT]; % as the top point satisfies dy/dx = a1 + 2*x*a2 = 0
b=[yg(1) yg(end) 0]'; %'
p=A\b;
x_fit=[xp(1):0.1:xp(end)];
y_fit=power(x_fit,2).*p(3)+x_fit.*p(2)+p(1);
figure
plot(xp,yp,'*')
hold on
plot(x_fit,y_fit,'r')
And then I get this parabola which is completely wrong. It doesn't fit the data at all! Can someone please tell me what's wrong with the code?
My parabola
Well, I think the primary problem is some mistake in your calculation. I think you should use three points on the parabola to obtain a system of linear equations. There is no need to calculate the derivative of your function as you do with
dy/dx = a1 + 2*x*a2 = 0
Instead of a point on the derivative you choose another point in your scatter plot, e.g. the maximum: PT = [xp_max yp_max]; and use it for your matrix A and b.
The equation dy/dx = a1 + 2*x*a2 = 0 does not fulfill the basic scheme of your system of linear equations: a0 + a1*x + a2*x^2 = y;
By the way: If you don't have to calculate your parabola necessarily in this way, you can maybe have a look at the Matlab/Octave-function polyfit() which calculates the least squares solution for your problem. This would result in a simple implementation:
p = polyfit(x, y, 2);
y2 = polyval(p, x);
figure(); plot(x, y, '*'); hold on;
plot(x, y2, 'or');

Finding and plotting parabola in matlab

I have been trying to find a parabola in an image. For the starting purposes I took an image with a black parabola on a white background. Then I found the black pixels on the image using the find command by
[yi xi] = find(im<10); % im is the image with black parabola and white background
After that I randomly took 3 points from the collection and solved the equation for the parabola using the symbolic toolbox using
syms x y;
%solve them for the parabola equation
A = [ x^2 x y 1 ;x0^2 x0 y0 1; x1^2 x1 y1 1; x2^2 x2 y2 1];
where
%(x0,y0) = (104,137)
%(x1,y1) = (244,161)
%(x2,y2) = (300,229)
S = solve(det(A),y);
Then I get the coeffcients a,b,c as
a = 0.0100
b = -1.6800
c = 254.1900
where a, b and c are
a*x^2 + b*x + c = y;
Since now I have got the eqn I plot the parabola by putting the coefficient values
and taking
xx = 1:300;
yy = a*xx.^2 + b*xx +c ;
then I plot the parabola on the image as
plot(xx,yy,'-');
For the confirmation that I have taken correct points I also plot the selected points on the image and they lie exactly on the parabola in the image. So that is not the problem.
The problems are :
The parabola that I plot (blue) doesn't lie on the parabola of the image(black).
When I put the value of x co-ordinates in the above equation. The value of y is not the same as of the y co-ordinate.
for eg: (104,137)
0.0100*104*104 -1.68*104 + 254.19 = 108.16 - 174.72 + 254.19 = 187.63
whereas it should be 137
My parabola is wrong. Any help will be appreciated. The images are
I think you must be rounding somewhere in your calculation of a, b, and c.
I had a go with the three points you mentioned using the function fit (with fit type poly2) and my a,b,c were 0.0053, -1.6802 and 254.1895 (or add more decimal places when using format long).
Similarly, when using same the code you give, the output of solve is:
S = (73*x^2)/13720 - (5763*x)/3430 + 87187/343
S2 = double(coeffs(S))
S2 =
254.1895 -1.6802 0.0053
This gives me the same a, b, and c as with fit/poly2 (just from looking at it, the output of 73/13720 cannot be 0.01). Also, if I plot this curve over the original points using the same code you give, it works fine. So the only remaining source of error that I can see is some sort of rounding in whatever code you use to extract values of a, b, and c from the output of solve.
The following works. The habit of imshow to swap the intuitive meaning of ordinate and abscissa as used in plot can make overlays problematic at times. Your problem might stem from how you define your coordinate system when plotting with different function (imshow or related image display routines versus plot) in particular the position of the origin in the image. Here's my code:
% create image of parabola
k =[-0.3 10 10];
x = [1:0.1:50];
y = round(k(1)*x.^2 + k(2)*x + k(3));
crd = unique(round([x(:) y(:)]),'rows');
Nx = 100;
Ny = 100;
img = ones(Nx,Ny)*255;
iok = find((crd(:,1)>0) & (crd(:,1)<=Nx) & (crd(:,2)>0) & (crd(:,2)<=Ny));
indx = sub2ind([Nx Ny],crd(iok,1),crd(iok,2));
img(indx) = 0;
imshow(img)
Next we fit the parabola
% pick three points:
x0 = crd(1,1);
y0 = crd(1,2);
x1 = crd(80,1);
y1 = crd(80,2);
x2 = crd(160,1);
y2 = crd(160,2);
% plot these on the original image
hold on
plot(y0,x0,y1,x1,y2,x2,'Markersize',20,'Linestyle','none','Marker','x','Color','r')
Solved the equation precisely as you showed, then the result is
S = -1094/3627*x^2+12073/1209*x+37415/3627
Overlay the fitted equation
a= -1094/3627;
b = 12073/1209;
c = 37415/3627;
xx = 1:100;
yy = a*xx.^2 + b*xx +c ;
% then I plot the parabola on the image as
plot(yy,xx,'g--');
A not so pretty plot (green= fit, red crosses=picked points, blue=parabola plotted without swapping order of x and y):

Plotting an ellipse in MATLAB given in matrix form

I have an ellipse in 2 dimensions, defined by a positive definite matrix X as follows: a point x is in the ellipse if x'*X*x <= 1. How can I plot this ellipse in matlab? I've done a bit of searching while finding surprisingly little.
Figured out the answer actually: I'd post this as an answer, but it won't let me (new user):
Figured it out after a bit of tinkering. Basically, we express the points on the ellipse border (x'*X*x = 1) as a weighted combination of the eigenvectors of X, which makes some of the math to find the points easier. We can just write (au+bv)'X(au+bv)=1 and work out the relationship between a,b. Matlab code follows (sorry it's messy, just used the same notation that I was using with pen/paper):
function plot_ellipse(X, varargin)
% Plots an ellipse of the form x'*X*x <= 1
% plot vectors of the form a*u + b*v where u,v are eigenvectors of X
[V,D] = eig(X);
u = V(:,1);
v = V(:,2);
l1 = D(1,1);
l2 = D(2,2);
pts = [];
delta = .1;
for alpha = -1/sqrt(l1)-delta:delta:1/sqrt(l1)+delta
beta = sqrt((1 - alpha^2 * l1)/l2);
pts(:,end+1) = alpha*u + beta*v;
end
for alpha = 1/sqrt(l1)+delta:-delta:-1/sqrt(l1)-delta
beta = -sqrt((1 - alpha^2 * l1)/l2);
pts(:,end+1) = alpha*u + beta*v;
end
plot(pts(1,:), pts(2,:), varargin{:})
I stumbled across this post while searching for this topic, and even though it's settled, I thought I might provide another simpler solution, if the matrix is symmetric.
Another way of doing this is to use the Cholesky decomposition of the semi-definite positive matrix E implemented in Matlab as the chol function. It computes an upper triangular matrix R such that X = R' * R. Using this, x'*X*x = (R*x)'*(R*x) = z'*z, if we define z as R*x.
The curve to plot thus becomes such that z'*z=1, and that's a circle. A simple solution is thus z = (cos(t), sin(t)), for 0<=t<=2 pi. You then multiply by the inverse of R to get the ellipse.
This is pretty straightforward to translate into the following code:
function plot_ellipse(E)
% plots an ellipse of the form xEx = 1
R = chol(E);
t = linspace(0, 2*pi, 100); % or any high number to make curve smooth
z = [cos(t); sin(t)];
ellipse = inv(R) * z;
plot(ellipse(1,:), ellipse(2,:))
end
Hope this might help!