I have a 3D matrix of size 300x178x124 that I plot using the slice command:
diff = double(squeeze(glacier));
diff(diff==0)=nan;
h = slice(realx,realy,realz,diff, [], [], 1:size(diff,1));
set(h, 'EdgeColor','none', 'FaceColor','interp', 'FaceLighting','gouraud')
colormap(flipud(pink))
colorbar;
caxis([0 5])
shading interp
daspect([0.5 1 .2])
view(-149,32)
I was wondering if it is possible to
(a) add transparency based upon the value of the 3D matrix, e.g. value of 0 in "diff" is 100% transparency while the maximum value of "diff" is displayed using 0% transparency.
(b) is there a way to visually improve the 3D presentation? It seems to me that the data display is rather patchy and does not really look that nice.
Related
I have 2 matrices. Matrix A contains values between 0 and 1 and matrix B contains values between 0 and 90. I would like to display an image with a different color for the numbers in each matrix.
When I use the colormap function with:
figure; colormap(jet); imshow(A);
The image displayed has several levels of gray, when I am supposed to have several colors (because I am using jet).
When I use the colormap function with:
figure; colormap(jet); imshow(B);
The image displayed is completely white, probably because my values are higher than 64 (which is the max of jet).
How can I solve these two problems? I read a lot of tutorials in several forums but I can't find the answer...
Thank you very much for answering my problem!
Just normalize the matrix by its max value if the values are more than 1. So for your B matrix try:
imshow(B/max(B(:)))
You can specify the colormap scaling and the number of actual colors within the colormap like so:
figure; imshow( A, [0 1], 'Colormap', jet(100) );
figure; imshow( B, [0 100], 'Colormap', jet(100) );
The jet(100) indicates 100 unique colors within the colormap to be used.
You are using the wrong function for the task in hand.
imshow expects an N by M by 3 array input, of the RGB channels of an image. When you use a 2D matrix the function assumes it's a grayscale image (it's like replicating it to 3 identical matrices to create these three channels - if all the channels in RGB have the same values you get grayscale colors). You can use this function together with a colormap to get a colored matrix, but there are much more convenient alternatives.
One simple function for getting a colored representation of a matrix is imagesc or (image if you want to scale the values by yourself). This function takes the values in your matrix, and assign them a color from the colormap you choose:
A = rand(10);
figure; colormap(jet); imagesc(A);
Another option is pcolor, which works a little different but give a similar result. pcolor attach the values to the vertices of the cells (in oppose to the center, as imagesc does), and interpolate the color in each cell from its' vertices. The resulted colored matrix is always smaller in one row and one column because it takes n+1 points (values in the original matrix) to define n gaps (the cells in the colored matrix). Here is an example:
A = rand(10);
figure; colormap(jet); pcolor(A);
shading flat
I'd like to read a custom image and apply a colormap like in the example from matlab. How can I do that? I see the example imageext uses custom images and applies colormaps and I'd like to do the same with my images. How can it be done? I want just to use my own picture for an example like imageext in matlab.
This does not work:
I = im2double(imread('niklas3.png')); figure(1); imshow(I,[]); daspect([1 1 1]); axis off; colormap gray;
niklas3.png:
But this code works:
I = im2double(imread('cameraman.tif')); figure(1); imshow(I,[]); daspect([1 1 1]); axis off; colormap summer;
You can apply a colormap in any image you want if it was previously displayed into a figure.
I recommend you to use imagesc or imshow to display images. In order to do that, you need to load the image with imread. A good practice is to convert your image data to double precision.
I = im2double(imread('cameraman.tif'));
As you can see, im2double converts image data to double precision ranging from 0 values to 1 values. If you do not want this, you can use the double function, ranging from 0 values to 255 value.
Later, you need to display the image into a figure. I strongly recommend to use imagesc instead of imshow, because imagesc allows you to customize your data and your display (for example, adding a different colormap).
figure(1); imagesc(I); daspect([1 1 1]); axis off;
Now, you can use the colormap you want. Type help colormap for more information, but you can use a jet colormap (default), gray, hot, bones, or whatever you want, just typing:
colormap gray;
If you plotted several images, you need to indicate the aimed image with:
figure(1); colormap gray;
If you want to use imshow, just type:
figure(1); imshow(I,[]); daspect([1 1 1]); axis off; colormap gray;
Edited: Once I saw your image, I knew your problem is that you are trying to apply a colormap into a RGB image. That is, you are trying to apply it into a 3D matrix, where rows and columns identify the pixel value and the third dimension identifies the RGB components.
So, you need to convert your RGB image into a 2D matrix (a black and white one). You can do it by performing the mean along the third dimension.
I = nanmean(I,3);
Finally, you should apply the colormap as I said it before. The final code would be:
I = im2double(imread('niklas3.jpg'));
I = nanmean(I,3);
figure(1); imshow(I,[]); daspect([1 1 1 ]); axis off;
colormap jet;
This is the result using a jet colormap:
I am currently trying to plot 3D streamtubes. I want the tubes to be colored corresponding to their respective velocity (e.g. slow = blue, fast = red).
To be more exact, I have three 3D-matrices containing the velocity in x, y and z direction. The color of the streamtubes should be sqrt(vx^2+vy^2+vz^2). When using streamtube(x,y,z,vx,vy,vz,sx,sy,sz) the tubes are colored according to their z-coordinate which is useless because it's a 3D plot anyway.
Well this wasn't easy (it ought to be a builtin option), but by modifying the CData of each tube (they are each their own graphics object), you can achieve the desired result. Here's an example
load wind
[sx,sy,sz] = meshgrid(80,20:10:50,0:5:15);
h=streamtube(x,y,z,u,v,w,sx,sy,sz);
drawnow
view(3)
axis tight
shading interp;
This gives this picture:
but then doing this:
vel=sqrt(u.^2+v.^2+w.^2); %// calculate velocities
for i=1:length(h)
%// Modify the colour data of each tube
set(h(i),'CData',interp3(x,y,z,vel,get(h(i),'XData')...
,get(h(i),'YData'),get(h(i),'ZData'),'spline'))
end
drawnow
view(3)
axis tight
shading interp;
gives this result
NOTES:
1) I don't know if this is fully correct, I don't know how to test it
2) You have to interpolate the velocity data from the points where it's known onto the vertices of the streamtubes
3) I found the spline interpolation option to work best, but the other options might work better in other cases
I'm trying to draw a large mesh in Matlab using the trimesh function, with the z coordinate of the vertices controlling the color. Unfortunately, Matlab stops interpolating colors correctly when the size of the mesh exceeds 120 triangles. Here's a picture demonstrating the problem, with 120 triangles on the left, and 121 triangles on the right.
As you can see, for large meshes, Matlab interpolates directly from the color of one vertex to the color of the other vertex. This was probably done for performance reasons, but I'm trying to generate nice pictures for my thesis, and I don't care how long it takes to compute them. Is there a way to disable this approximation?
Here's the code to generate the picture:
function test(n)
%%% Generate a mesh with n triangles.
oneTriVerts = [0 0 0;
1 0 0;
1 0 1];
offset = [0 (1/n) 0;
0 (1/n) 0;
0 (1/n) 0];
verts = zeros(0,3);
tris = zeros(0,3);
for i = 0:(n-1)
verts = [verts; (oneTriVerts + i * offset)];
tris = [tris; i*3+1, i*3+2, i*3+3];
end
%%% Draw the mesh, with color corresponding to the z coordinate.
trimesh(tris, verts(:,1), verts(:,2), verts(:,3), verts(:,3));
title(sprintf('n = %d', n))
shading interp
axis equal
I think that after a certain threshold, MATLAB switched to the OpenGL renderer for better performance (hardware acceleration). Unfortunately, it is not without bugs.
I haven't closely looked at how you are building the triangular faces (there might a problem with how they are ordererd), but an easy solution is to explicitly set the rendering method. Simply add the following call at the end of your function:
set(gcf, 'Renderer','zbuffer')
EDIT
The workaround above should do just fine. Now the real problem is not a buggy OpenGL, but rather a documented limitation:
OpenGL does not do colormap interpolation. If you create a surface or
patch using indexed color and interpolated face or edge coloring,
OpenGL interpolates the colors through the RGB color cube instead of
through the colormap.
Note that the TRIMESH call is equivalent to the following:
patch('Faces',tris, 'Vertices',verts, 'FaceVertexCData',verts(:,3), ...
'EdgeColor','none', 'FaceColor','interp', 'CDataMapping','scaled')
So for each vertex you specify a color equal to its z-coordinate (you only have two unique values, either 0 or 1). This is interpreted as an indexed color into the current figure's colormap using scaled mapping (the default is the jet colormap). So the two colors end up being:
clr = jet(64); % default colormap
clr(1,:) % blueish color [0 0 0.5625] mapped from 0
clr(end,:) % reddish color [0.5 0 0] mapped from 1
Unfortunately as the quote above explains, OpenGL renderer will not do the interpolation using the colors of colormap palette, rather perform the interpolation in the RGB colorspace between the two colors above. Thus we get the blue-red gradient you saw.
So your only option is to use one of the two other renderers, zbuffer being the best method here.
Here is the code to see the difference between the two rendering methods:
% plot patch
clf
patch('Faces',tris, 'Vertices',verts, 'FaceVertexCData',verts(:,3), ...
'EdgeColor','none', 'FaceColor','interp', 'CDataMapping','scaled')
view(3)
axis vis3d
colorbar
% choose one of the two
set(gcf, 'Renderer','opengl')
set(gcf, 'Renderer','zbuffer')
OpenGL
Z-Buffer
I have some data (a function of two parameters) stored in a matlab format, and I'd like to use matlab to plot it. Once I read the data in, I use mesh() to make a plot. My mesh() plot gives me the the value of the function as a color and a surface height, like this:
What matlab plotting function should I use to make a 2D mesh plot where the dependent variable is represented as only a color? I'm looking for something like pm3d map in gnuplot.
By default mesh will color surface values based on the (default) jet colormap (i.e. hot is higher). You can additionally use surf for filled surface patches and set the 'EdgeColor' property to 'None' (so the patch edges are non-visible).
[X,Y] = meshgrid(-8:.5:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
% surface in 3D
figure;
surf(Z,'EdgeColor','None');
2D map: You can get a 2D map by switching the view property of the figure
% 2D map using view
figure;
surf(Z,'EdgeColor','None');
view(2);
... or treating the values in Z as a matrix, viewing it as a scaled image using imagesc and selecting an appropriate colormap.
% using imagesc to view just Z
figure;
imagesc(Z);
colormap jet;
The color pallet of the map is controlled by colormap(map), where map can be custom or any of the built-in colormaps provided by MATLAB:
Update/Refining the map: Several design options on the map (resolution, smoothing, axis etc.) can be controlled by the regular MATLAB options. As #Floris points out, here is a smoothed, equal-axis, no-axis labels maps, adapted to this example:
figure;
surf(X, Y, Z,'EdgeColor', 'None', 'facecolor', 'interp');
view(2);
axis equal;
axis off;
gevang's answer is great. There's another way as well to do this directly by using pcolor. Code:
[X,Y] = meshgrid(-8:.5:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
figure;
subplot(1,3,1);
pcolor(X,Y,Z);
subplot(1,3,2);
pcolor(X,Y,Z); shading flat;
subplot(1,3,3);
pcolor(X,Y,Z); shading interp;
Output:
Also, pcolor is flat too, as show here (pcolor is the 2d base; the 3d figure above it is generated using mesh):
Note that both pcolor and "surf + view(2)" do not show the last row and the last column of your 2D data.
On the other hand, using imagesc, you have to be careful with the axes. The surf and the imagesc examples in gevang's answer only (almost -- apart from the last row and column) correspond to each other because the 2D sinc function is symmetric.
To illustrate these 2 points, I produced the figure below with the following code:
[x, y] = meshgrid(1:10,1:5);
z = x.^3 + y.^3;
subplot(3,1,1)
imagesc(flipud(z)), axis equal tight, colorbar
set(gca, 'YTick', 1:5, 'YTickLabel', 5:-1:1);
title('imagesc')
subplot(3,1,2)
surf(x,y,z,'EdgeColor','None'), view(2), axis equal tight, colorbar
title('surf with view(2)')
subplot(3,1,3)
imagesc(flipud(z)), axis equal tight, colorbar
axis([0.5 9.5 1.5 5.5])
set(gca, 'YTick', 1:5, 'YTickLabel', 5:-1:1);
title('imagesc cropped')
colormap jet
As you can see the 10th row and 5th column are missing in the surf plot. (You can also see this in images in the other answers.)
Note how you can use the "set(gca, 'YTick'..." (and Xtick) command to set the x and y tick labels properly if x and y are not 1:1:N.
Also note that imagesc only makes sense if your z data correspond to xs and ys are (each) equally spaced. If not you can use surf (and possibly duplicate the last column and row and one more "(end,end)" value -- although that's a kind of a dirty approach).
I also suggest using contourf(Z). For my problem, I wanted to visualize a 3D histogram in 2D, but the contours were too smooth to represent a top view of histogram bars.
So in my case, I prefer to use jucestain's answer. The default shading faceted of pcolor() is more suitable.
However, pcolor() does not use the last row and column of the plotted matrix. For this, I used the padarray() function:
pcolor(padarray(Z,[1 1],0,'post'))
Sorry if that is not really related to the original post