Annular ring pattern with alternate bright and dark rings: using matlab - matlab

I am attempting to make a pattern consisting of annular rings with radii proportional to the square root of the natural numbers. Also I want the inner most circle to be white followed by a black circle followed by a white and so on.
c = [0 0; 0 0];
r = [5.2494 9.0922];
viscircles(c, r)
r1 = [7.4328 10.4988];
viscircles(c, r1)
I have generated the above code to form the annular ring structure but I want to fill in the color as well. What should I do?

You could go the mathematical route and plot the function ceil(sin(pi*(X.^2 + Y.^2))):
zoomlevel = 50;
for n = 1:zoomlevel
[X,Y] = ndgrid(linspace(-n,n,500));
I = ceil(sin(pi*(X.^2 + Y.^2)));
imshow(mat2gray(I));
drawnow;
pause(0.03);
end
Of course this will only be a raster graphic instead of a vector one, so don't zoom in too much. ;-) (Although the aliasing artefacts will look quite cool if you zoom out. Plot at your own risk.)

My Matlab version doesn't have viscircles, so here's an approach which plots each individual circle with alternating colors. It uses the rectangle function, which lets you define the curvature of the corners so that the rectangle/square becomes an ellipse/circle. Bigger circles should be drawn first, so that they don't completely cover smaller circles.
colors = [.9 .9 .9; 0 0 0]; %// light gray and black
N = 16; %// maximum number
hold on
for n = N:-1:1; %// bigger circles first
s = sqrt(n);
rectangle('curvature', [1 1], 'position', [-s/2 -s/2 s s], ...
'edgecolor', 'none', 'facecolor', colors(mod(n-1,2)+1,:));
end
axis square

You can also create a "surface" with value 1 for all your r radiuses and 0 for the r1. Then either plot as a surface seen form top, or directly use pcolor.
r = [0 5.2494 7.4328 9.0922 10.4988] ; %// define all your radiuses
bw = mod( 1:numel(r) , 2 ) ; %// create an alternance of 0 and 1 (same size as "r")
ntt = 50 ; %// define how many angular division for the plot
theta = linspace(0,2*pi,ntt) ; %// create all the angular divisions
[rr,tt]=meshgrid(r,theta) ; %// generate a grid
z = repmat( bw , ntt , 1 ) ; %// replicate our [0 1 0 ...] vector to match the grid
[xx,yy,zz] = pol2cart(tt,rr,z) ; %// convert everything to cartesian coordinates
pcolor(xx,yy,zz) %// plot everything
colormap(gray(2)) %// make sure we use only 2 colors (black and white)
shading flat ; axis equal %// refine the view (axis ratio and "spokes" not visible)
You can send as many radiuses as you like in the original r.
This will render:
This method look a bit longer at first than other solution, but you could remove many intermediate steps by consolidating some lines, and if you are to reuse the graphics later on, it may present 2 benefits:
if you get the handle of the graphic object (hp=pcolor(xx,yy,zz)), you only have one graphic object to handle.
if you need to change the color, you do not need to cycle through each circle, just change the colormap to the 2 colors you want (for example if you want "red" and "green", just call the colormap colormap([1 0 0;0 1 0]) and you're done.

viscircles returns an hggroup object. One of the properties of such an object is its Children, which is an array of handles to the graphics objects it creates. For instance you could write
h1 = viscircles(c, r)
c1 = h1.Children
The children here should just be the handles to the circular patches defined by viscircles. Now, to set the color of the ith circular patch, you can set the FaceColor property of the handle c1(i).

Related

How do I customize the picture in matlab legends?

I want to draw a contour plot of a plane and a surface with legends. Plotting two surfaces in the same figure create the same legends. I want to change the resulting ellipses in the legend. Can I draw parallel lines instead of ellipses on the legend chart?
This is a sample source code:
[X,Y] = meshgrid(-3:.1:3);
Z1 = peaks(X,Y);
Z2 = 2*X+3*Y+4;
contour(X,Y,Z1)
colormap jet
shading interp
axis([-3 3 -3 3])
hold on
contour(X,Y,Z2)
legend('surface','plane')
Honestly there's no good way to get an image in front.
There are a few work arounds that I could show you, but you'll have to be specific.
The easiest things are, getting a colorbar or a rectangular box (1 color) infront of text. These are standard options for datatypes/legend entries.
I suggest you start off with giving your surfaces/countours handles.
h1=surf(....);
h2=plot(....);
lgd=legend([h1, h2, ....],[entries']);
For text with white in front you can do
h_separator1 = plot(NaN,NaN,'.','Color',[1 1 1]);
lgd=legend([h_separator1],['text']);
Here's an example you can run that let's you do the things I just said
clear all; % just for ease of quickly plotting this
close all; %closing all figures
myc=[1 1 1; 0 0 0; 1 1 1; 0 0 0; 1 1 1]; %this is want we will use to draw the paralel lines, can be of any color, just replace the zeros, with the respective values of the colors you want, 0 0 0 is black
x = [0 0 0 0]; %making it have 0 area and thus invisible
y = [0 0 0 0];
c = [0 0.33 0.66 1]; %lets you add a colorbar
figure
colormap(myc); %update the figure to use your colormap
hold on
h3 = plot(NaN,NaN,'Color','none'); %blank entry
h4 = plot(NaN,NaN,':'); % entry with dotted line, color "pseudo random"
h1=patch(x,y,'red','EdgeColor','none'); %For a rectangular color entry in legend
h2=patch(x,y,c,'EdgeColor','none'); %lets you add the colorbar, later use to place inside the legend as paralel lines
[lgd,OBJH,OUTH,OUTM]=legend([h1,h3,h2,h4],{'HI your text here','Nothing','paralel lines','line'}); %the lgd handle let's you later modify properties of the legend
hcb=colorbar; %the colorbar can still be modified, to have no number or a different scale, color, etc.
hcm=OBJH(5)
xlim([0 1])
ylim([0 1])
lpos=lgd.Position; % get position legend
lnr=numel(OUTH); %legend entries is useful
lhstp=lpos(4)/(lnr+1); %heigth step
hax=gca;
axpos=hax.Position; %to shift position because the colorbar is placed in the figure and not within the axes in comparison to the legend
% placing at by example 3rd entry
wdentry=0.04; %at the moment trial and error depends on width on legend box which is based on amount of characters and text size.
p1=axpos(1)+lpos(1)+0.01;
p2=lpos(2)+3/2*lhstp;
p3=wdentry;
p4=lhstp-0.01;
hcb.TickLabels=[]; %remove tick labels
hcb.Ticks=[]; %remove ticks
hcb.Color=[1 1 1]; %white border around it to make it "semi-invisible"
hcb.Position=[p1 p2 p3 p4];

Rotating a Plot About the Y Axis

I have a vector of values that I want to plot as brightness on a circle through the radius of it (I.e. If it was 0 3 1 5 I'd want a circle that was dark at the centre, then a bright ring around it, then a slightly darker ring, then a brighter ring).
To do this I've attempted to rotate my radial vector (E) around the y axis, as such
[X,Y,Z] = cylinder(E);
h = surf(X,Y,Z),
However I'm clearly not doing it right, as this appears to be rotating my curve around the x axis. I've tried just swapping X and Y, but it still rotates it around the x axis. Any help would be greatly appreciated.
One way would be to rotate your vector and create a surface. The Z data of the surface (your rotated vector) will be color coded according to the colormap you choose, if you display the surface from the top you get your circles at the different brightness.
If you are really only interested from the "top view" of this surface, then no need to create a full surface, a simple pcolor will do the job.
example:
%% // input data (and assumptions)
E=[0 3 1 5 2 7];
nBrightness = 10 ; %// number of brightness levels
r = (0:numel(E)) ; %// radius step=1 by default for consecutive circles
%// otherwise define different thickness for each circle
So if I use stairs([E 0]) you get your different brightness levels:
I had to add a last 0 to the vector to "close" the last level, we'll have to do that again in the solution below.
Now to rotate/replicate that around Y, color code the height, and look at it from the top:
%% // replicate profile around axis
ntt = 50 ; %// define how many angular division for the plot
theta = linspace(0,2*pi,ntt) ; %// create all the angular divisions
[rr,tt]=meshgrid(r,theta) ; %// generate a grid
z = repmat( [E 0] , ntt , 1 ) ; %// replicate our "E" vector to match the grid
[xx,yy,zz] = pol2cart(tt,rr,z) ; %// convert everything to cartesian coordinates
pcolor(xx,yy,zz) %// plot everything
colormap(gray(nBrightness)) %// make sure we use only "nBrightness" colors (Shades of gray)
caxis([0 nBrightness])
shading flat ; axis equal %// refine the view (axis ratio and "spokes" not visible) etc...
colorbar
axis off
will yield the following :
Note that your problem was not fully defined, I had to take assumptions on:
What radius each brightness circle should have ? (I made them all the same but you can modify that)
How many brightness levels you want ? (You can also modify that easily though).
Have you tried the rotate function?
direction = [0 1 0];
rotate(h,direction,90);
In this example a 90 degree rotation is performed around the y axis.
Using this library http://www.mathworks.com/matlabcentral/fileexchange/45952-circle-plotter
%http://www.mathworks.com/matlabcentral/fileexchange/45952-circle-plotter
x0 = 0;
y0 = 0;
colors = [0 3 1 5];
maxC = max(colors);
sz = numel(colors);
for i=fliplr(1:sz)
c = colors(i);
circles(x0,y0,i,'facecolor',[c/maxC c/maxC 0]) % http://au.mathworks.com/help/matlab/ref/colorspec.html
end

Absolute scale for color map?

I am trying to make a plot with an intensity that varies over time:
[X,Y] = meshgrid(-30:.1:30);
figure;
colormap(bone);
for t = 0:0.1:2*pi
R = sqrt(X.^2 + Y.^2);
Z = cos(t)*abs(besselj(2,R));
surf(Z,'EdgeColor','None');
view(90,90);
axis([0 600 0 600 -0.5 0.5])
pause(0.1);
end
I want to look at this from the top, such that as the Z value changes, the color changes. The problem is that rather than having an absolute scale (black = -0.5, white = 0.5), the color scale is relative to the maximum and minimum values, such that the colors only change when the sign flips change. How can I set an absolute scale for the color map?
Thank you.
You have to use scaled colour mapping mode and set the limits of the scaling by using the caxis command.
Now the problem with your current code is that you call surf at each iteration of the loop, essentially destroying the current plot and generating a new plot each time. This will reset a lot of properties, including the caxis limits to auto. To overcome that, simply create your plot only once before the loop, then in the loop you only change the properties which are modified (the Z values in this case). This way everything else stays the same in the figure.
So you code becomes:
%% // Prepare and initialize the surface plot
[X,Y] = meshgrid(-30:.1:30);
R = sqrt(X.^2 + Y.^2) ; %// this doesn't need to be in the loop
Z = cos(0)*abs(besselj(2,R)) ; %// calculate initial value to create the surface
surfHandle = surf( Z , 'EdgeColor','None' ) ; %// create a first surface, and save the handle to the surface object
colormap(bone);
colorbar %// this is optional, just to make sure the colorbar does not vary
caxis([-5 5 ] ) ; %// this is what sets the color scaling to what you want
view(90,90);
axis([0 600 0 600 -0.5 0.5]) ; %// this doesn't need to be in the loop anymore
%% // Modify and update the surface plot
for t = 0:pi/100:2*pi
Z = cos(t)*abs(besselj(2,R));
set( surfHandle , 'ZData' , Z )
drawnow
pause(0.01);
end
Read coloring-mesh-and-surface-plots for more info on how surfaces can be colored.
If you just want white for values less than 0 and black for values greater than 0, you ca simply do:
surf(Z,sign(Z),'EdgeColor','None');
which uses the optional C argument to surf, telling Matlab to colour the plot depending on the values of C, not Z. sign(Z) is a matrix that has 1's where Z>0, 0's where Z=0, and -1's where Z<0.

Matlab custom colormap with only 3 colors

just want to check if it is possible to make a custom colormap with only 3 colors? (there is no need for gradient).
Example: Data ranges from 0-100,
so 0-33 is one color,
34-67 is another color,
and 68-100 is another color.
Just use a colormap with three rows. Each row defines a color in terms of R, G, B components.
A = randi(100,16,16); %// example data
imagesc(A) %// display matrix as image
colormap([1 0 0; 0 1 0; 0 0 1]) %// apply colormap
colorbar %// show color bar
This defines uniformly spaced thresholds between colors. If you need more control you need to have more than three rows, with some of the colors repeated. For example,
colormap([1 0 0; 1 0 0; 0 1 0; 0 0 1]) %// apply colormap
will define a 50% threshold for first color, 75% for second and 100% for third.
Take this example:
% some matrix with integer values in the range [0,100]
Z = peaks;
Z(:) = round((Z(:)-min(Z(:))) ./ range(Z(:))*100);
% show as image (with scaled color mapping)
image(Z, 'CDataMapping','scaled')
caxis([0 100]) % set axes CLim property
colormap(eye(3)) % set figure Colormap property
colorbar % show colorbar
Note that the colors are scaled to the range [0 100], that range is mapped to the current figure's colormap (which we set to only three colors).
Follow this example: How to create a custom colormap programmatically? but instead of R = linspace(0,t(1),50)' you would use R = ones(50,1)*t(1)
or even simpler:
if colour 1 is t1 = [r1, g1, b1] etc then
map(1:34, :) = repmat(t1, 33, 1)
map(35:68, :) = repmat(t2, (67-34), 1)
etc...
OR
map(1:34, :) = bsxfun(#times, t, ones(33,3))
etc...
Check my answer here
You can use that code and decide to interpolate between values or not, its just 2 lines of the code.
The result image shown in the original post for a GYR cutom colormap.

How can thin horizontal lines be added between each row in a grayscale image?

I need to create an nth-order Hadamard matrix, row double it, within each row randomly permute the elements of the matrix, and then display it. So far, I have accomplished all of these things. What I end up with when I imshow(matrix) is a nice picture of black and white boxes. But I haven't figured out how to insert a fine line to divide each row. I can create something like the first image on the left, but not the image on the right (these are Figures 1 and 2 from this paper)
Any help or comments would be thoroughly appreciated.
I've found using vector approaches (e.g., patch and rectangle) for this sort of problem unnecessarily challenging. I think that it's more straightforward to build a new image. This avoids floating-point rounding issues and other things that crop up with vector graphics. My solution below relies on some functions in the Image Processing Toolbox, but is simple and fast:
% Create data similarly to #TryHard
H = hadamard(48);
C = (1+[H;-H])/2;
rng(0); % Set seed
C(:) = C(randperm(numel(C))); % For demo, just permute all values, not rows
% Scale image and lines
scl = 10; % Amount to vertically scale each row
pad = 2; % Number of pixels to add between each row
C = imresize(C,scl,'nearest');
C = blockproc(C,[scl size(C,2)],#(x)[x.data;zeros(pad,size(C,2))]);
C = C(1:end-pad,:); % Remove last line added
% Dispay image
imshow(C)
This results in an image like this
The scl and pad parameters can be easily adjusted to obtain different sizes and relative sizes. You can call imresize(...,'nearest') again after adding the lines to further scale the image if desired. The blocproc line could potentially be made more efficient with various options (see the help). It could also be replaced by calls to im2col and col2im, which possibly could be faster, if messier.
I did not try the code, but I think that something like that should work:
sizeOfACube = 6;
numberOfRows = 47;
RGB = imread('image.png');
RGB = imresize(A, [(numRows+numberOfRows) numCols]);
for i=1:1:NumberOfRows
RGB(i*6,:,:) = 0;
end
imagesc(RGB);
imwrite(RGB,'newImage.png');
with:
sizeOfAcube the size of one cube on the QRcode.
numRows and numCols the number of Rows and Column of the original image.
One solution is to use patches, for instance as follows:
% set up example array
xl = 24; yl = xl;
[X Y] = find(hadamard(xl)==1);
% generate figure
figure, hold on
for ii=1:length(X)
patch(X(ii) + [0 0 1 1],Y(ii) + [0.1 0.9 0.9 0.1],[1 1 1],'Edgecolor',[1 1 1])
end
axis([0 xl+1 0 yl+1])
axis('square')
The patch command patch(x,y, color) accepts the vertices of the polygon element as x and y. In this example you can modify the term [0.1 0.9 0.9 0.1] to set the thickness of the bounding black line.
This generates
Edited
For the particular instance provided by the OP:
H=Hadamard(48); %# now to row-double the matrix
A=(1+H)/2;
B=(1-H)/2;
C=[A; B]; %# the code below randomly permutes elements within the rows of the matrix
[nRows,nCols] = size(C);
[junk,idx] = sort(rand(nRows,nCols),2); %# convert column indices into linear indices
idx = (idx-1)*nRows + ndgrid(1:nRows,1:nCols); %# rearrange whatever matrix
E = C;
E(:) = E(idx);
[X Y] = find(logical(E));
xl = length(X);
yl = length(Y);
figure, hold on
for ii=1:xl
rectangle('Position',[X(ii) Y(ii)+.2 1 0.8],'facecolor',[1 1 1],'edgecolor',[1 1 1])
end
axis([0 max(X)+1 0 max(Y)+1])
axis('square')
set(gca,'color',[0 0 0])
set(gca,'XTickLabel',[],'YTickLabel',[],'XTick',[],'YTick',[])
This example uses rectangle instead of patch to generate sharp corners.
The image: