How do I customize the picture in matlab legends? - matlab

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

Related

Matlab figure problems: half scatter points, black lines inside a red region

Consider the following figure in Matlab (matrices here)
load matrices
%Rb, vertices_deg, vertices_comp
close all
patch([0 0 1],[0 1 0],[1 0 0],[0.8 0.8 0.8]);
axis equal
axis([0 1 0 1 0 1])
view(120,30)
hold on
T = delaunayTriangulation(Rb.');
K = convexHull(T);
patch('Faces',K,'Vertices',T.Points,'FaceColor','k','edgecolor','k');
hold on
scatter3(vertices_deg(:,1), vertices_deg(:,2) , vertices_deg(:,3),100,'o','filled','b')
hold on
patch(vertices_comp(:,1), vertices_comp(:,2) , vertices_comp(:,3),'red')
hold off
xlim([0 1])
ylim([0 1])
zlim([0,1])
box on
set(gca, 'ytick',0:0.2:1,'xtick',0:0.2:1,'ztick',0:0.2:1,'FontSize',13)
I would like to save this figure in a way such that:
within the red region, I do not get the black lines that I can see in the Matlab output
the blu scatter point is a full circle (and not half circle, as it appears in the Matlab output)
I tried two ways of saving the figure
saveas(gcf,'3.jpg')
print(gcf, '3.jpg', '-dpng', '-r300', '-painters')
None of these two gives me what I want. Could you help?
This is what I get with PRINT
This is what I get with SAVEAS
And here a screenshot of the Matlab window
The problem you are seeing is that the patches are plotted at the exact same plane, which causes this render effect. This is called Z-fighting.
An easy fix is to add some small offset to some of the planes that are drawn in front of the others. You can tweak this value till the effect is gone, and the error from the indented place is minimal.
load matrices
close all
patch([0 0 1],[0 1 0],[1 0 0],[0.8 0.8 0.8]);
axis equal
axis([0 1 0 1 0 1])
view(120,30)
hold on
T = delaunayTriangulation(Rb.');
K = convexHull(T);
d_patch = 0.001;
d_z = 0.01;
patch('Faces',K,'Vertices',T.Points + d_patch,'FaceColor','k','edgecolor','k');
patch(vertices_comp(:,1), vertices_comp(:,2) , vertices_comp(:,3)+d_z,'red')
scatter3(vertices_deg(:,1), vertices_deg(:,2) , vertices_deg(:,3),100,'o','filled','r')
scatter3(vertices_deg(:,1), vertices_deg(:,2) , vertices_deg(:,3)+2*d_z,100,'o','filled','b')
xlim([0 1])
ylim([0 1])
zlim([0,1])
box on
set(gca, 'ytick',0:0.2:1,'xtick',0:0.2:1,'ztick',0:0.2:1,'FontSize',13)
saveas(gcf,'3saveas.png')
print(gcf, '3print.png', '-dpng', '-r300', '-painters')
You can do the same for the blue dot, which is partially drawn into the plane. Just give it a little offset, and it appears as a full dot again. I plotted the dot in red and blue, so you can see the offset in location.

Annular ring pattern with alternate bright and dark rings: using 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).

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

How to combine a custom color range with colorbar in MATLAB?

I'd like to have a surface plot like the one below, but with a proper colorbar.
This is my code:
[X,Y,Z] = peaks(30);
[maxval dummy] = max(Z(:));
[minval dummy] = min(Z(:));
crange = 1.5;
% red, yellow, green
cmap = [1 0 0; 1 1 0; 0 1 0];
colormap(cmap);
colors = zeros(size(Z));
colors(Z <= -crange) = 1; % red (1)
colors(Z > -crange & Z < crange) = 2; % yellow (2)
colors(Z >= crange) = 3; % green (3)
surf(X,Y,Z, colors);
axis([-3 3 -3 3 -10 10]);
%cbh = colorbar('YGrid','on');
%caxis([minval-0.1 maxval+0.1]);
%set(cbh,'YTick',[minval -crange crange maxval]);
So far I had no luck in adding a colorbar where the colors (green,yellow,red) are aligned according to my custom range (green[8 ... 1.5],yellow[1.5 ... -1.5], red[-1.5 ... -6.4]). Instead, when I uncomment the last three lines,
a colorbar with linearly aligned colors shows up and the colors in my plot are aligned according to the colorbar and not to my custom range.
Now, what I'd like to have is that the colors in the colorbar match my custom ticks and that the plot looks like in the first picture.
The problem is that you specify the colors of each point in the surf plot by yourself, so they're not related to the z-value as is by default. The colorbar therefor is constructed only based on the color numbers, being 1 to 3. These therefor also show up as the default ticks of the colorbar (before you change them.
As you found out, you can set the ticks manually, and in the same way you can 'cheat' and use yticklabels:
figure
colormap(cmap);
surf(X,Y,Z, colors);
axis([-3 3 -3 3 -10 10]);
cbh = colorbar('YGrid','on');
set(cbh,'ytick',linspace(1,3,4));
set(cbh,'yticklabel',arrayfun(#num2str,[minval -crange crange maxval],'uni',false));
Or another way is to simply use caxis, but then the colors of the plot are linearly defined by the minmax values. So with this you can't set your non-linear ranges.
Illustration:
figure
colormap(cmap);
surf(X,Y,Z);
axis([-3 3 -3 3 -10 10]);
caxis([minval-0.1 maxval+0.1]);
cbh=colorbar
set(cbh,'YTick',[minval -crange crange maxval]);
So after all, I think my first method (using yticklabels) is the only way of doing what you want.
I know this is a crazy old post, but it came up as I was looking for answers. And here would be my answer (which has to assume unfortunately that the graduations on the color bar are equal size).
So given that you have made the color map, which is only 3 colors, the next part is algebra. The caxis follows a simple formula which is determined by the how many colors are in the color bar, and your min and max range.
index = fix((C-cmin)/(cmax-cmin)*m)+1;
So index will refer to the index in the color map (m = 3 since that is the length of your colormap), and what I would do is make C= 1.5, decide if you want it symmetrical (you are solving for cmax and cmin and is easier if both are x), and make index=2 (since you only have 3 colors, that should mean solving for 1.5 would give you the cmin/cmax to set which would make 1.5 the cutoff between yellow and red. You should be able to set the display range value somewhere, which will set the colormap appropriately (though probably not the labels).
Sorry to reply to such an old post, but maybe this will help others.
I came across this question when finding solutions for a problem that I had. Anyway this question helped me to get a solution for my problem after making little modifications on written codes.
At the same time I like to suggest some changes for the code so that user can get the required plot with necessary colors and the appropriate color bar also.
Here is the code,
[X,Y,Z] = peaks(30);
[maxval dummy] = max(Z(:));
[minval dummy] = min(Z(:));
crange=1.5;
% red, yellow, green
cmap = [1 0 0; 1 1 0; 0 1 0];
colormap(cmap);
colors = zeros(size(Z));
colors(Z <= -crange) = minval-0.1; % red (1)
colors(Z > -crange & Z < crange) = crange; % yellow (2)
colors(Z >= crange) = maxval+0.1; % green (3)
surf(X,Y,Z, colors);
axis([-3 3 -3 3 -10 10]);
cbh = colorbar('YGrid','on');
caxis([minval-0.1 maxval+0.1]);
set(cbh,'YTick',[minval -crange crange maxval]);
Plot

Matlab Ploting with different color for iso-surface

I was trying use the code shown below to plot in such a way that each iso-surface will be different in color and there will be a color bar at the right. I made a ss(k) color matrix for different colors. Number of iso-surfaces is 10 but I have only 8 colors. That's why I wrote ss(9)='r' and ss(10)='r'.
I need a solution to plot the iso-surface with different color and bar at the right side.
ss=['y','m','c','r','g','b','w','k','r','r']
k=1;
for i=.1:.1:1
p=patch(isosurface(x,y,z,v,i));
isonormals(x,y,z,v,p)
hold on;
set(p,'FaceColor',ss(k),'EdgeColor','none');
daspect([1,1,1])
view(3); axis tight
camlight
lighting gouraud
k=k+1;
end
Another possibility is to draw the patches with direct color-mapping (by setting the property 'CDataMapping'='direct'), while assigning the 'CData' of each patch to an index in the colormap of your choice. This is in fact recommended for maximum graphics performance.
Consider the following example:
%# volumetric data, and iso-levels we want to visualize
[x,y,z,v] = flow(25);
isovalues = linspace(-2.5,1.5,6);
num = numel(isovalues);
%# plot isosurfaces at each level, using direct color mapping
figure('Renderer','opengl')
p = zeros(num,1);
for i=1:num
p(i) = patch( isosurface(x,y,z,v,isovalues(i)) );
isonormals(x,y,z,v,p(i))
set(p(i), 'CData',i);
end
set(p, 'CDataMapping','direct', 'FaceColor','flat', 'EdgeColor','none')
%# define the colormap
clr = hsv(num);
colormap(clr)
%# legend of the isolevels
%#legend(p, num2str(isovalues(:)), ...
%# 'Location','North', 'Orientation','horizontal')
%# fix the colorbar to show iso-levels and their corresponding color
caxis([0 num])
colorbar('YTick',(1:num)-0.5, 'YTickLabel',num2str(isovalues(:)))
%# tweak the plot and view
box on; grid on; axis tight; daspect([1 1 1])
view(3); camproj perspective
camlight; lighting gouraud; alpha(0.75);
rotate3d on
I also included (commented) code to display the legend, but I found it to be redundant, and a colorbar looks nicer.
Matlab usually plots different iso-surfaces in different colors automatically, so you don't need to care about that. What kind of bar do you need? A colorbar or a legend? Either way, it is just to use the colorbar or legend function..
%Create some nice data
[x y z] = meshgrid(1:5,1:5,1:5);
v = ones(5,5,5);
for i=1:5
v(:,:,i)=i;
end
v(1:5,3:5,2)=1
v(1:5,4:5,3)=2
%Plot data
for i=1:5
isosurface(x,y,z,v,i)
end
%Add legend and/or colorbar
legend('one','Two','Three','Four')
colorbar
Since the color bar encodes value->color, it is impossible to do what you ask for, unless there is no intersection in z-values between all pairs of surfaces. So the solution below assumes this is the case. If this is not the case, you can still achieve it by adding a constant value to each surface, so to separate the surfaces along the z axis, and eliminate any intersection.
The solution is based on constructing a colormap matrix of piecewise constant values, distributed similarly to the z values of your surfaces. So for example, if you have 3 surfaces, the first has z values between 1 and 10, the 2nd between 11 and 30, and the 3rd between 31 and 60, you should do something like this (I plot in 2D for simplicity)
r = [1 0 0];
g = [0 1 0];
b = [0 0 1];
cmap = [r(ones(10,1),:); g(ones(20,1),:); b(ones(30,1),:)];
z1 = 1:10;
z2 = 11:30;
z3 = 31:60;
figure; hold on
plot(z1,'color',r)
plot(z2,'color',g)
plot(z3,'color',b)
colorbar
colormap(cmap)
More complex colormaps (i.e, more colors) can be constructed with different mixtures of red, green, and blue (http://www.mathworks.com/help/techdoc/ref/colorspec.html)