This question already has answers here:
Produce a 3D stem plot with a custom colormap in MATLAB
(2 answers)
Closed 7 years ago.
I have produced the following figure using MATLAB plot3 function.
This figure is not good.
Because, I think, it's too hard for readers to estimate the coordinates from this figure.
Points height (Z value) is too hard to be estimated from the figure.
What is missing in my figure that makes it hard to be interpreted ?
To Play with the data:
The visualized data is here. The function to produce my current figure is here. Either comment the mArrow3 call, or download it from here.
To better see height you can use stem3 to draw a vertical line from the floor to each point. You can enhance the representation with a semi-transparent patch at zero height to highlight the floor.
% // Random data
x = -20+50*rand(1,50);
y = 150*rand(1,50);
z = -5+10*rand(1,50);
%// With plot
figure
plot3(x,y,z,'.','markersize',8)
grid on
axis equal
view(-33, 14)
%// With stem3 and patch
figure
stem3(x,y,z,'.','markersize',8)
grid on
hold on
patch([-20 30 30 -20], [0 0 150 150], [0 0 0 0], 'k', ...
'edgecolor', [.5 .5 .5], 'FaceAlpha' , .1)
axis equal
view(-33, 14)
I think the problem might be intrinsic to these kind of plots: the 0d dots of your data are hard to interpret perspectivically, your brain can't decypher at which depth the data points are located. For instance, it would seem to me that you have no data poinst above z=0 and above x=15, which is obviously wrong, but my brain attributes most of your points to the z=-5 plane.
Unless your data points have finite volume which proportionally changes with distance (which can not be done with matlab, and probably wouldn't help much anyway), you might want to reconsider your way of visualization. How about having 3 plots, one each with camera along the x, y, and z axes?
EDIT: the suggestion of Luis Mendo makes me think I should probably have a more open mind when trying to answer a question:)
You could also use different colors/markers/point size to discriminate between various regions in your data. For instance values having z below 0 are red and those above are green. Here is a simple example using scatter3 with 4 distinct regions. Thanks to Luis Mendo for the dummy data.
clc;clear;close all
% // Random data...thanks Luis Mendo
x = -20+50*rand(1,50);
y = 150*rand(1,50);
z = -5+10*rand(1,50);
%// Get indices for various regions in your data
region1 = find(z>=-4 & z<-2);
region2 = find(z>=-2 & z<0);
region3 = find(z>=0 & z<2);
region4 = find(z>=2 & z<4);
%// Draw each region with its own color/size
scatter3(x(region1),y(region1),z(region1),20,'r','filled')
hold on
scatter3(x(region2),y(region2),z(region2),40,'y','*')
scatter3(x(region3),y(region3),z(region3),60,'g','filled')
scatter3(x(region4),y(region4),z(region4),80,'b')
grid on
view(-33, 14)
kkuilla's answer about heat map produced a much better result:
Related
I need assistance making a nice contour plot. I have data from an underwater glider that dives and climbs repeatedly from the surface of the ocean to around 30 m, in this case.
I think my issue is with interpolating the data, and I am not sure how to proceed. Here is the contour plot of density I have generated this far.
The Contour plot of density was generated using this code
xlin = linspace(min(time),max(time),500);
ylin = linspace(min(depth),max(depth),500);
[X,Y] = meshgrid(xlin,ylin);
Z = griddata(time,depth,density,X,Y);
[C,h] = contour(X,Y,Z,[1022.0, 1022.5, 1023.0, 1023.5, 1024.0, 1024.5, 1025.0, 1025.5, 1026.0],'color',[0.5 0.5 0.5]);
v = [1022.0, 1022.5, 1023.0, 1023.5, 1024.0, 1024.5, 1025.0, 1025.5, 1026.0];
clabel(C,h,v,'fontsize',8);
set(gca,'ydir','reverse');
I want the plot to have smooth contour lines. Once I get the contour plot to look good I will overlay it on salinity and temperature scatter plots.
Please let me know how I can make a better looking contour plot.
Is it an issue with interpolation? Or the way I gridded the data?
Thanks very much! Please be specific and give code examples if you've played with the data.
Here is the time, depth, and density matlab data: https://www.dropbox.com/s/agi70zh7haggf07/data.mat?dl=0
The problem is that bunch of your interpolated data are missing. I mean that Z has a bunch of NaNs:
xlin = linspace(min(time),max(time),500);
ylin = linspace(min(depth),max(depth),500);
[X,Y] = meshgrid(xlin,ylin);
Z = griddata(time,depth,density,X,Y);
%surf(X,Y,Z) %also interesting
spy(isnan(Z));
Result:
Your input data are somehow ill-defined, and griddata gives up. Here's why:
>> sum(isnan(density))
ans =
3174
Fix the NaNs in your raw data, and you'll most probably fix the plot.
Update
I threw away your NaNs:
inds=~isnan(density);
time=time(inds);
depth=depth(inds);
density=density(inds);
to see how the result looks like. It turns out that your original code is already looking OK to me!
Original on the left, de-NaNed version on the right:
So... maybe your datetime transformation is off? Or your time limits, not showed in your original code?
This question already has answers here:
How to create a custom colormap programmatically?
(2 answers)
Closed 7 years ago.
I have a contour plot with data that goes from -90 to 90 degrees. for now i am using jet so I have a map that looks like this
I have been asked to change the colormap so that instead of having a gradient, I have a fixed color for each 5 degress (so I believe 36 colors). Also i was thinking of maybe having same colors for the interval [5 10] and [-10 -5], and so on if that makes sense.
My code is quite long because i have a lot of data to process, but that's part of it just so you can see what function i am using to plot this
%%
x1=data(:,5); %x location
y1=data(:,16); %y location
z1=phi*90; %angle phi
z2=gamma*90; %angle gamma
n=300; precision of grid
%Create regular grid across data space
[X,Y] = meshgrid(linspace(min(x1),max(x1),n), linspace(min(y1),max(y1),n));
figure(3);
contourf(X,Y,griddata(x1,y1,z1,X,Y),100,'EdgeColor', 'None')
%title('Variation of In-plane angle \phi')
axis equal
axis ([0 8000 0 12000])
axis off
h=colorbar;
caxis([-90 90])
set(h, 'YTick', [-90:15:90])
Does anyone know how to create this colorbar?
Cheers
Every colormap-generating function in Matlab, including jet, takes an argument that specifies how many colormap entries there should be. In your case, you want 180 / 5 = 36 discrete colors:
colormap(jet(36))
To make sure the 36 colors cover exactly the 5 degree steps, set the color axis explicitly:
caxis([-90 90])
The result looks e.g. like this:
I am trying to make a simple plot (for this example doing a plot of y=x^2 will suffice) where I want to set the colors of the points based on their magnitude given some colormap.
Following along my simple example say I had:
x = 1:10;
y = x.^2;
Use gscatter(x,y,jet(10)); legend hide; colorbar which produces a plot with the points colored but the colorbar does not agree with the colored values. (Can't post picture as this is my first post). Using a caxis([1,100]) command gives the right range but the colors are still off.
So I have two questions:
(1) How can I fix the colors to fit to a colorbar given a range? In my real data, I am looking at values that range from -50 to 50 in some instances and have many more data points.
(2) I want to create a different plot with the same points (but on different axes) and I want the colors of each point on this new plot to have the same colors as their counterparts in the previous plot. How can I, programmatically, extract the color from each point so I can plot it on two different sets of axes?
I would just move the points into a matrix and do an imagesc() command but they aren't spaced as integers or equally so simple scaling wouldn't work either.
Thanks for any help!
Regarding you first question, you need to interpolate the y values into a linear index to the colormap. Something like:
x = 1:10;
y = x.^4;
csize = 128;
cmap = jet(csize);
ind = interp1(linspace(min(y),max(y),csize),1:csize,y,'nearest');
scatter(x,y,14,cmap(ind,:),'filled')
colorbar
caxis([min(y) max(y)])
Using interp1 in this case is an overkill; you could calculate it directly. However, I think in this way it is clearer.
I think it also answers your 2nd question, since you have the index of the color of each data point, so you can use it again in the same way.
When I generate a set of rectangular patches in a matlab figure, some of the rectangle edges are rendered curved or clipped rather than sharp, which is unwanted. This depends on the scale, zooming into the image tends to eliminate the effect. I thought this might have to do with an aliasing/compression effect. Curiously, using rectangle the problem seems to go away.
Here is an example of the problem at intermediate magnification (other problems such as dashed borders which shouldn't be there are also evident):
The code is from an answer to another question:
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
patch(X(ii) + [0 0 1 1],Y(ii) + [0.15 0.9 0.9 0.1],[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',[])
My questions are:
(1) Is it possible (and how) to get rid of the curved corners and other glitches of patch objects seen in the example shown, at low to intermediate degrees of magnification used to display the entire figure on screen.
(2) Most important is to be able to generate an image file (jpg, png, pdf...) which lacks the curved corners. All formats I looked into appear to conserve the unwanted effect. Answering 2 makes answering (1) essentially unimportant, and answering (1) presumably solves (2).
Edit
Since the problem goes away when rectangle is used, this appears to be a problem with the matlab rendering engine? Note: the example was generated with R14 but the OP of the question linked to had similar problems (matlab version unknown).
I went through the various lighting and edge representation options available for patch objects but no improvement was observed.
The question is a likely repeat, for instance a similar questions was asked here.
The answer appears to be to avoid explicit use of patch when drawing rectangles. Use either fill or just rectangle instead. The following ways of generating the figure provide nearly equivalent results, as far as I could tell:
load had.mat % <-- load the data containing the matrix of interest in array E
[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])
% fill([X(ii) X(ii) X(ii)+1 X(ii)+1], [Y(ii)+0.2 Y(ii)+0.8 Y(ii)+0.8 Y(ii)+0.2],[1 1 1],'edgecolor',[1 1 1],'marker','.','markersize',1)
end
set(gca,'color',[0 0 0])
set(gca,'XTickLabel',[],'YTickLabel',[],'XTick',[],'YTick',[])
set(gcf,'Renderer','zbuffer')
I'm using polar plots (POLAR(THETA,RHO)) in MATLAB.
Is there an easy way to fix the range for the radial axis to say, 1.5?
I'm looking for something analogous to the xlim, ylim commands for cartesian axes. Haven't found anything in the docs yet.
this worked for me... i wanted the radius range to go to 30, so i first plotted this
polar(0,30,'-k')
hold on
and then plotted what i was actually interested in. this first plotted point is hidden behind the grid marks. just make sure to include
hold off
after your final plotting command.
Here's how I was able to do it.
The MATLAB polar plot (if you look at the Handle Graphics options available) does not have anything like xlim or ylim. However, I realized that the first thing plotted sets the range, so I was able to plot a function with radius range [-.5 .5] on a [-1 1] plot as follows:
theta = linspace(0,2*pi,100);
r = sin(2*theta) .* cos(2*theta);
r_max = 1;
h_fake = polar(theta,r_max*ones(size(theta)));
hold on;
h = polar(theta, r);
set(h_fake, 'Visible', 'Off');
That doesn't look very good and hopefully there's a better way to do it, but it works.
Simple solution is to make a fake graph and set its color to white.
fake=100;
polar(0,fake,'w');
hold on;
real=10;
polar(0,real,'w');
In case anyone else comes across this, here's the solution:
As Scottie T and gnovice pointed out, Matlab basically uses the polar function as an interface for standard plots, but with alot of formatting behind the scenes to make it look polar. Look at the values of the XLim and YLim properties of a polar plot and you'll notice that they are literally the x and y limits of your plot in Cartesian coordinates. So, to set a radius limit, use xlim and ylim, or axis, and be smart about the values you set:
rlim = 10;
axis([-1 1 -1 1]*rlim);
...that's all there is to it. Happy Matlabbing :)