plot a structure in matlab - matlab

I have a structure of known (but variable length) like this-
1 0 1
0 1 1
I want to plot this structure as colored squares- color each 1 as a green square, and 0s as a red square
Something like
[green][red][green]
[red][green][green]
It would be nice to add some optional text on each square.
Also, I have another data structure of same length, with numbers going from 0.0 to 1.0 .. something like
0.99 0.09 1.0
0.09 0.87 1.0
I want to possibly change the intensity of red and green in the above pic depending on how close to 0 or 1 is the corresponding number.
Any suggestions are helpful. Thanks a lot.

You can set the colormap after displaying the matrix as a scaled image:
Z = [1 0 1; 0 1 1];
figure; imagesc(Z);
colormap([1 0 0; 0 1 0]);
axis off; axis image;

Essentially, you want to turn the 2-d structure into a 3-d one, the last dimension being x3, one for each of the RGB colors. Start with this code, and play with it until it does what you want.
map=zeros(2,2,3);
map(:,:,1)=[1 1; 0 0];
map(:,:,2)=[1 0; 1 0];
map(:,:,3)=[0 0; 0 0];
figure;image(map);
Alternatively, you could have a colormap, which would translate the pixel counts to intensity. It's been a while since I've done it, but I can at least point you in the right direction. Run the first command, and look at the colormap. You want to have a gradual changing from Green to Red. Format it how you want it, pass it back in with the last command, and see what you get out.
cmap = colormap;
%You'll want to change cmap to meet your needs
imagesc([.1 .2; .8 .9]);
colormap(cmap);

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];

Find contour/edge in pcolor in Matlab

I'm trying to make a contour that follows the edges of the 'pixels' in a pcolor plot in Matlab. This is probably best explained in pictures. Here is a plot of my data. There is a distinct boundary between the yellow data (data==1) and the blue data (data==0):
Note that this is a pcolor plot so each 'square' is essentially a pixel. I want to return a contour that follows the faces of the yellow data pixels, not just the edge of the yellow data.
So the output contour (green line) passes through the mid-points of the face (red dots) of the pixels.
Note that I don't want the contour to follow the centre points of the data (black dots), which would do something like this green line. This could be achieved easily with contour.
Also, if it's any help, I have a few grids which may be useful. I have the points in the middle of the pixels (obviously, as that's what I've plotted here), I also have the points on the corners, AND I have the points on the west/east faces and the north/south faces. IF you're familiar with Arakawa grids, this is an Arakawa-C grid, so I have the rho-, u-, v- and psi- points.
I've tried interpolation, interweaving grids, and a few other things but I'm not having any luck. Any help would be HUGELY appreciated and would stop me going crazy.
Cheers, Dave
EDIT:
Sorry, I simplified the images to make what I was trying to explain more obvious, but here is a larger (zoomed out) image of the region I'm trying to separate:
As you can see, it's a complex outline which heads in a "southwest" direction before wrapping around and moving back "northeast". And here is the red line that I'd like to draw, through the black points:
You can solve this with a couple of modifications to a solution I posted to a related question. I used a section of the sample image mask in the question for data. First, you will need to fill the holes in the mask, which you can do using imfill from the the Image Processing Toolbox:
x = 1:15; % X coordinates for pixels
y = 1:17; % Y coordinates for pixels
mask = imfill(data, 'holes');
Next, apply the method from my other answer to compute an ordered set of outline coordinates (positioned on the pixel corners):
% Create raw triangulation data:
[cx, cy] = meshgrid(x, y);
xTri = bsxfun(#plus, [0; 1; 1; 0], cx(mask).');
yTri = bsxfun(#plus, [0; 0; 1; 1], cy(mask).');
V = [xTri(:) yTri(:)];
F = reshape(bsxfun(#plus, [1; 2; 3; 1; 3; 4], 0:4:(4*nnz(mask)-4)), 3, []).';
% Trim triangulation data:
[V, ~, Vindex] = unique(V, 'rows');
V = V-0.5;
F = Vindex(F);
% Create triangulation and find free edge coordinates:
TR = triangulation(F, V);
freeEdges = freeBoundary(TR).';
xOutline = V(freeEdges(1, [1:end 1]), 1); % Ordered edge x coordinates
yOutline = V(freeEdges(1, [1:end 1]), 2); % Ordered edge y coordinates
Finally, you can get the desired coordinates at the centers of the pixel edges like so:
ex = xOutline(1:(end-1))+diff(xOutline)./2;
ey = yOutline(1:(end-1))+diff(yOutline)./2;
And here's a plot showing the results:
imagesc(x, y, data);
axis equal
set(gca, 'XLim', [0.5 0.5+size(mask, 2)], 'YLim', [0.5 0.5+size(mask, 1)]);
hold on;
plot(ex([1:end 1]), ey([1:end 1]), 'r', 'LineWidth', 2);
plot(ex, ey, 'k.', 'LineWidth', 2);
Take a look at the following code:
% plotting some data:
data = [0 0 0 0 0 0 1 1
0 0 0 0 0 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 0 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1
0 0 0 0 1 1 1 1];
p = pcolor(data);
axis ij
% compute the contour
x = size(data,2)-cumsum(data,2)+1;
x = x(:,end);
y = (1:size(data,1));
% compute the edges shift
Y = get(gca,'YTick');
y_shift = (Y(2)-Y(1))/2;
% plot it:
hold on
plot(x,y+y_shift,'g','LineWidth',3,'Marker','o',...
'MarkerFaceColor','r','MarkerEdgeColor','none')
It produces this:
Is this what you look for?
The most important lines above is:
x = size(data,2)-cumsum(data,2)+1;
x = x(:,end);
which finds the place of shifting between 0 to 1 for every row (assuming there is only one in a row).
Then, within the plot I shift y by half of the distance between two adjacent y-axis tick, so they will be placed at the center of the edge.
EDIT:
After some trials with this kind of data, I have got this result:
imagesc(data);
axis ij
b = bwboundaries(data.','noholes');
x = b{1}(:,1);
y = b{1}(:,2);
X = reshape(bsxfun(#plus,x,[0 -0.5 0.5]),[],1);
Y = reshape(bsxfun(#plus,y,[0 0.5 -0.5]),[],1);
k = boundary(X,Y,1);
hold on
plot(X(k),Y(k),'g','LineWidth',3,'Marker','o',...
'MarkerFaceColor','r','MarkerEdgeColor','none')
It's not perfect, but may get you closer to what you want in a more simple approach:
OK, I think I've solved it... well close enough to be happy.
First I take the original data (which I call mask_rho and use this to make masks mask_u, mask_v, which is similar to mask_rho but is shifted slightly in the horizontal and vertical directions, respectively.
%make mask_u and mask_v
for i = 2:size(mask_rho,2)
for j = 1:size(mask_rho,1)
mask_u(j, i-1) = mask_rho(j, i) * mask_rho(j, i-1);
end
end
for i = 1:size(mask_rho,2)
for j = 2:size(mask_rho,1)
mask_v(j-1, i) = mask_rho(j, i) * mask_rho(j-1, i);
end
end
I then make modified masks mask_u1 and mask_v1 which are the same as mask_rho but averaged with the neighbouring points in the horizontal and vertical directions, respectively.
%make mask which is shifted E/W (u) and N/S (v)
mask_u1 = (mask_rho(1:end-1,:)+mask_rho(2:end,:))/2;
mask_v1 = (mask_rho(:,1:end-1)+mask_rho(:,2:end))/2;
Then I use the difference between the masks to locate places where the masks change from 0 to 1 and 1 to 0 in the horizontal direction (in the u mask) and in the vertical direction (in the v mask).
% mask_u-mask_u1 gives the NEXT row with a change from 0-1.
diff_mask_u=logical(mask_u-mask_u1);
lon_u_bnds=lon_u.*double(diff_mask_u);
lon_u_bnds(lon_u_bnds==0)=NaN;
lat_u_bnds=lat_u.*double(diff_mask_u);
lat_u_bnds(lat_u_bnds==0)=NaN;
lon_u_bnds(isnan(lon_u_bnds))=[];
lat_u_bnds(isnan(lat_u_bnds))=[];
%now same for changes in mask_v
diff_mask_v=logical(mask_v-mask_v1);
lon_v_bnds=lon_v.*double(diff_mask_v);
lon_v_bnds(lon_v_bnds==0)=NaN;
lat_v_bnds=lat_v.*double(diff_mask_v);
lat_v_bnds(lat_v_bnds==0)=NaN;
lon_v_bnds(isnan(lon_v_bnds))=[];
lat_v_bnds(isnan(lat_v_bnds))=[];
bnd_coords_cat = [lon_u_bnds,lon_v_bnds;lat_u_bnds,lat_v_bnds]'; %make into 2 cols, many rows
And the result grabs all the coordinates at the edges of the boundary:
Now my answer goes a bit awry. If I plot the above vector as points plot(bnd_coords_cat(:,1),bnd_coords_cat(:,2),'kx' I get the above image, which is fine. However, if I join the line, as in: plot(bnd_coords_cat(:,1),bnd_coords_cat(:,2),'-' then the line jumps around, as the points aren't sorted. When I do the sort (using sort and pdist2) to sort by closest points, Matlab sometimes chooses odd points... nevertheless I figured I'd include this code as an appendix, and optional extra. Someone may know a better way to sort the output vectorbnds_coords_cat:
% now attempt to sort
[~,I]=sort([lon_u_bnds,lon_v_bnds]);
bnd_coords_inc1 = bnd_coords_cat(I,1);
bnd_coords_inc2 = bnd_coords_cat(I,2);
bnd_coords = [bnd_coords_inc1,bnd_coords_inc2];
bnd_coords_dist = pdist2(bnd_coords,bnd_coords);
bnd_coords_sort = nan(1,size(bnd_coords,1));
bnd_coords_sort(1)=1;
for ii=2:size(bnd_coords,1)
bnd_coords_dist(:,bnd_coords_sort(ii-1)) = Inf; %don't go backwards?
[~,closest_idx] = min(bnd_coords_dist(bnd_coords_sort(ii-1),:));
bnd_coords_sort(ii)=closest_idx;
end
bnd_coords_final(:,1)=bnd_coords(bnd_coords_sort,1);
bnd_coords_final(:,2)=bnd_coords(bnd_coords_sort,2);
Note that the pdist2 method was suggested by a colleague and also from this SO answer, Sort coordinates points in matlab. This is the final result:
To be honest, plotting without the line is fine. So as far as I'm concerned this is close enough to be answered!

Plot with variable background color

I'm plotting line charts with the x-axis representing the timeline. Some of the dataranges should be marked as unreliable. For showig this it would be great to change the background color over these x-ranges to some bringt yellow or red. Is there an option of doing that?
I know that could us gscatter instead of gplot for using colors. But then only the data is colored and not the background and I don't get linecharts but point charts. Colored data would be an acceptable alternative, but I need line charts.
It is always possible to make a filled polygon plot. Try,
a = 0:0.1:1;
b = a;
figure;
plot(a,b,'r');
hold on;
x = [0 0 1 1 0];
y = [0 1 1 0 0];
h = fill(x,y,'g');
set(h,'FaceAlpha',0.1); % or alpha(h,0.1); would also work

MATLAB: how to set colors in matrix

I have a matrix N*N, with three different values, for example 0, 0.5, 1.
How can i print to the screen an image, which each value represent a different color?
Important: the matrix is a loop so the values may change (i want to print the matrix every iteration).
I tried to use colormap, it worked fine if all the three values were in the matrix,
but when one or two values only remain, the colors were changed.
How I want it to work: matrix with values 0, 0.5, 1 prints to the screen a matrix which each cell contains 0 colored black, 0.5 colored green, 1 colored yellow.
Thanks a lot!
Just create your own colormap that has only three possible values:
a = [1 0.5 0;1 .5 0;0.5 0 1];
b = [1 0 1;1 1 0;0 0 1];
cmap = [0,0,0;0,1,0;1,1,0];
clims = [0 1];
imagesc(a,clims); colormap(cmap);
imagesc(b,clims); colormap(cmap);
a gives:
b gives:
I would try maybe imagsec. Or any other scaling for the colors. Start with gray scale. RGB will be alittle more complex

Matlab - attach scalar value to RGB colours

When I read the following image into Matlab I am obtaining a 3D matrix which basically contains the values of RGB colour samples which compose every pixel within the image.
Is there any Matlab function which I can use to assign a scalar value between lets say [-10, 10] to every pixel within the image based on the RGB values? Pure red should be like 10, yellow should be 5, green should be 0, blue should be like -8 and cyan should be like -10.
Have a look at RGB2IND: http://www.mathworks.com/help/techdoc/ref/rgb2ind.html
You could then replace the Nx3 index output with your own custom N element index vector.
As you can see from running
colorlist=[1 0 0;1 1 0;0 1 0; 0 0 1; 0 1 1];
valuelist=[10 5 0 -8 -10];
figure;
hold all;
for i=1:10
bar(i,i,'FaceColor',colorlist(i,:))
end;
the colorlist defined above corresponds to the colors you are interested in.
To solve your question, for each pixel in your image, you would have to determine which RGB values are exactly zero and which ones are exactly one to determine between which pair you want to interpolate. For example, assuming size(image)==[100,100,3] and image=im2double(imread(myfilename)) i.e. max(image(:))==1:
if ((image(x,y,:)==0)==[0 0 1]) && ((image(x,y,:)==1)==[1 0 0])
%# interpolate between red and yellow
result(x,y)=10 - 5*image(x,y,2); %# pure red gives 10, pure yellow gives 5
elseif ((image(x,y,:)==0)==[0 0 1]) && ((image(x,y,:)==1)==[0 1 0])
%# interpolate between yellow and green
result(x,y)=5*image(x,y,1); %# pure yellow gives 5, pure green gives 0
elseif
%# ...
end
This solution is not vectorized, but it should get you on the right track for a doable implementation. Of course, if you could avoid saving the data with a multicolor lookup-table as RGB but save the raw values instead, you could save yourself some hassle...