I have some observational data that is relatively complete, but contains some NaN values, in an matrix in matlab and I want to interpolate them to a more evenly spaced grid using interp2
So, to keep things simple lets say I have one complete (no NaN values) matrix, and one that looks something like:
A = [ 1 2 3 4;
2 3 2 NaN;
0 2 3 4;
0 NaN 4 5 ]
with B and C being complete matrices, interp2 won't accept an input matrix with NaN values. So if I do something like this:
[AI,BI] = meshgrid(a,b) %# matrices to interpolate data to, arbitrary
CI = interp2(A,B,C,AI,BI) %# interpolation, A has NaN values
I get an error:
Error using griddedInterpolant
The coordinates of the input points must be finite values; Inf and NaN are not permitted.
Can anyone suggest either a solution, or reasonable work around that doesn't obstruct my data?
Sorry the quick fix I gave in comment does not work directly for 2D data (it does work that simply with interp1 though, if you ever need it).
For gridded data, if you have NaNs in your grid then you do not have a uniform grid and you cannot use interp2 directly. In this case you have to use griddata first, to re-interpolate your data over a uniform grid (patch the holes basically).
(1) Let's show an example inspired from the Matlab doc:
%% // define a surface
[A,B] = meshgrid(-3:0.25:3);
C = peaks(A,B);
%// poke some holes in it (in every coordinate set)
A(15,3:8) = NaN ;
B(14:18,13) = NaN ;
C(8,16:21) = NaN ;
(2) Now let's fix your data on a clean grid:
%// identify indices valid for the 3 matrix
idxgood=~(isnan(A) | isnan(B) | isnan(C));
%// define a "uniform" grid without holes (same boundaries and sampling than original grid)
[AI,BI] = meshgrid(-3:0.25:3) ;
%// re-interpolate scattered data (only valid indices) over the "uniform" grid
CI = griddata( A(idxgood),B(idxgood),C(idxgood), AI, BI ) ;
(3) Once your grid is uniform, you can then use interp2 if you want to mesh on a finer grid for example:
[XI,YI] = meshgrid(-3:0.1:3) ; %// create finer grid
ZI = interp2( AI,BI,CI,XI,YI ) ; %// re-interpolate
However, note that if this is all what you wanted to do, you could also use griddata only, and do everything in one step:
%// identify indices valid for the 3 matrix
idxgood=~(isnan(A) | isnan(B) | isnan(C));
%// define a "uniform" grid without holes (finer grid than original grid)
[XI,YI] = meshgrid(-3:0.1:3) ;
%// re-interpolate scattered data (only valid indices) over the "uniform" grid
ZI = griddata( A(idxgood),B(idxgood),C(idxgood), XI, YI ) ;
This produces the exact same grid and data than we obtained on step (3) above.
Last note: In case your NaNs are on the border of your domain, by default these functions cannot "interpolate" values for these border. To force them to do so, look at the extrapolation options of these functions, or simply interpolate on a slightly smaller grid which doesn't have NaN on the border.
Related
I have two 80*80 matrices. I would like to plot normalized frequency plot. I tried to normalize the 80* 80 grid with the following code:
A = per_monsoon_postmon; % (A is my 80*80 matrix)
A = rand (80,80);
minA = repmat(min(A), [size(A, 1), 1]);
normA = max(A) - min(A);
normA = repmat(normA, [length(normA) 1]);
normalizedA = (A - minA)./normA;
But this code didn't give me the desired result, as grids with nan values also has a number in it. For eg. earlier grid 1*1 is nan now it has a value of 0.8340. Could you please help me how to normalize the 2D matrix and then plot frequency distribution plot in MATLAB? Is there a way to directly plot normalized frequency distribution plot?
If you have nan values in your verctor you might have problems. I would first replace the nans (for example with zeros).
Normalisation between 0 and one works like this:
a=rand(80,80); %generates random 80x80 array
a=a-min(min(a)); %shifts the values from 0 to n, min(min() ) because it is 2x2
a=a./max(max(a));% shifts to 0 to 1
If you want tot plot these values in 3d I would use a surf plot therefore you first generate the sample values and then feed them the z values
[x,y]=meshgrid(1:80);
surf(x,y,z)
I have a problem with MATLAB bar3 plots: Here is what I have:
m x n Array Values containing values of a measurement.
Another m x n Array Angles Represents the angle at which a value was measured (e.g. the 3rd value was measured at an angle of 90°). The angular values for each measurement value are stored in another variable.
I need a range for my x-axis from -180° to +180°. This alone is no problem. But how do I hand over my measurement values? I have to somehow link them to the angular values. So that each value in Values is somehow linked to it's angular value in Angles. For my y-axis, I can simply count from 0 to the amount of rows of my Values Array.
EXAMPLE:
Valueslooks like:
3 5 6
2 1 7
5 8 2
Angles looks like:
37° 38° 39°
36° 37° 38°
34° 35° 36°
Values(1,1) = 3 was measured at Angles(1,1) = 37° for example.
At each angle, the number of bars varies depending on how many measurements exist for that angle. bar3 needs a matrix input. In order to build a matrix, missing values are filled with NaN.
Warning: NaNs are usually ignored by plotting commands, but bar3 apparently breaks this convention. It seems to replace NaNs by zeros! So at missing values you'll get a zero-height bar (instead of no bar at all).
[uAngles, ~, uAngleLabels] = unique(Angles); %// get unique values and
%// corresponding labels
valuesPerAngle = accumarray(uAngleLabels(:), Values(:), [], #(v) {v});
%// cell array where each cell contains all values corresponding to an angle
N = max(cellfun(#numel, valuesPerAngle));
valuesPerAngle = cellfun(#(c) {[c; NaN(N-numel(c),1)]}, valuesPerAngle);
%// fill with NaNs to make all cells of equal lenght, so that they can be
%// concatenated into a matrix
valuesPerAngle = cat(2, valuesPerAngle{:}); %// matrix of values for each angle,
%// filled with NaNs where needed
bar3(uAngles, valuesPerAngle.'); %'// finally, the matrix can be plotted
ylabel('Angles')
xlabel('Measurement')
With your example Values and Angles this gives:
Given the following code, how would one make the Inf values invisible in the scatter plot without color manipulation?
J = rand(20, 40, 5);
J(J>.6 & J<.4) = Inf;
% Plot a scatter matrix
shape = size(J);
[x,y,z] = meshgrid(1:shape(1), 1:shape(2), 1:shape(3));
scatter3(x(:), y(:), z(:), 4, J(:), 'fill');
Data that have NaN values are made invisible when plotting with MATLAB, which you can exploit in your case. Since you want to make the Infinte values as invisible, you can convert all those to NaNs and then plot them. Here you can take help of logical indexing to index into Inf element positions. Thus, the code would be -
J(isinf(J))=NaN
%// ... Plot J
One method could be to change the values higher than a certain threshold to NaN (or any other number). I believe NaN values will not show up in your scatter plot. You can do this with the same code you are already using.
J(J>10^6) = NaN;
I have a 2d array and I want to scatter plot the points grouped by row so that each row has a different symbol. This is my code so far, all the points are the same symbol so I can't tell which points are part of which row.
a = zeros (31,3);
for k = 0:30
y = 5*k
dent = [1 10 10 y]
a(k+1, [1 2 3]) = roots(dent)
end
t = 1:3
gscatter(real(a(:,t)),imag(a(:,t)));
You do not need a loop, you can exploit the gscatter options:
a = zeros (31,3);
for k = 0:30
y = 5*k;
dent = [1 10 10 y];
a(k+1, [1 2 3]) = roots(dent);
end
group = ones(size(a));
group(:,1) = group(:,1).*0;
group(:,3) = group(:,3).*2;
gscatter(real(a(:)),imag(a(:)),group(:),'brg','xo+');
You need an additional vector, group, which contains information on which points in your data-set belong to a specific group. This variable is very versatile, see it's documentation.
In your case, I suggest setting up a matrix that is 0 in the first column, 1 in the second and 2 in the third.
In the gscatter function call, reshape all your matrices into vectors using (:) (because gscatter only works with vectors.
The other two strings passed to gscatter:
'brg'
'xo+'
determine the color and shape of the symbols, respectively. Your plot then looks like this:
EDIT
For those users without access to the gscatter function, this is how it can be done using scatter:
s = 40;
hold on
COLORS='brg';
SYMBOLS='xo+';
for t=1:size(a,2)
scatter(real(a(:,t)),imag(a(:,t)),s,SYMBOLS(t),'MarkerEdgeColor',COLORS(t))
end
hold off
A few things to take note of:
to be used in this way, scatter needs a symbol-size, which was set to s = 40 in this example.
the symbols are stored in a string variable so that the can be called in the loop.
the same is true for the edge colors (face colors could also be specified, check the scatter documentation
when called in a loop, use hold to plot into the same figure (roughly speaking)
This is the output from the standard scatter plot:
I've got a 2-D histogram (the plot is 3D - several histograms graphed side by side) that I've generated with the bar3 plot command. However, all the zero values show up as flat squares in the x-y plane. Is there a way I can prevent MATLAB from displaying the values? I already tried replacing all zeros with NaNs, but it didn't change anything about the plot. Here's the code I've been experimenting with:
x1=normrnd(50,15,100,1); %generate random data to test code
x2=normrnd(40,13,100,1);
x3=normrnd(65,12,100,1);
low=min([x1;x2;x3]);
high=max([x1;x2;x3]);
y=linspace(low,high,(high-low)/4); %establish consistent bins for histogram
z1=hist(x1,y);
z2=hist(x2,y);
z3=hist(x3,y);
z=[z1;z2;z3]';
bar3(z)
As you can see, there are quite a few zero values on the plot. Closing the figure and re-plotting after replacing zeros with NaNs seems to change nothing:
close
z(z==0)=NaN;
bar3(z)
One solution is to modify the graphics objects created by bar3. First, you have to get the handles returned from bar3:
h = bar3(z);
In your case, h will be a 3-element vector of handles, one for each set of colored bars. The following code should then make the bins with counts of zero invisible:
for i = 1:numel(h)
index = logical(kron(z(:, i) == 0, ones(6, 1)));
zData = get(h(i), 'ZData');
zData(index, :) = nan;
set(h(i), 'ZData', zData);
end
And here's an illustration (with obligatory free-hand circles):
How it works...
If your vector of bin counts is N-by-1, then bar3 will plot 6*N rectangular patches (i.e. the 6 faces of a cuboid for each bin). The 'ZData' property for each set of patch objects in h will therefore be (6*N)-by-4, since there are 4 corners for each rectangular face. Each cluster of 6 rows of the 'ZData' property is therefore a set of z-coordinates for the 6 faces of one bin.
The above code first creates a logical vector with ones everywhere the bin count equals 0, then replicates each element of this vector 6 times using the kron function. This becomes an index for the rows of the 'ZData' property, and this index is used to set the z-coordinates to nan for the patches of empty bins. This will cause the patches to not be rendered.
EDIT:
Here's a slightly modified version of the code that makes it more general by fetching the bar height from the 'ZData' property of the plotted bars, so all that's needed for it to work are the handles returned from bar3. I've also wrapped the code in a function (sans error and input checking):
function remove_empty_bars(hBars)
for iSeries = 1:numel(hBars)
zData = get(hBars(iSeries), 'ZData'); % Get the z data
index = logical(kron(zData(2:6:end, 2) == 0, ones(6, 1))); % Find empty bars
zData(index, :) = nan; % Set the z data for empty bars to nan
set(hBars(iSeries), 'ZData', zData); % Update the graphics objects
end
end
Here is an example that shows how to hide bars with zero-values. We start with a normal BAR3 plot:
x = 1:7;
Y = jet(numel(x));
h = bar3(x,Y,'detached');
xlabel x; ylabel y; zlabel z; box on;
Note that the variable h contains an array of surface handles (3 in this case, one for each "group" of bars. The groups correspond to the columns of the Y matrix, each represented by a different color).
And now the code to hide zero values:
for i=1:numel(h)
%# get the ZData matrix of the current group
Z = get(h(i), 'ZData');
%# row-indices of Z matrix. Columns correspond to each rectangular bar
rowsInd = reshape(1:size(Z,1), 6,[]);
%# find bars with zero height
barsIdx = all([Z(2:6:end,2:3) Z(3:6:end,2:3)]==0, 2);
%# replace their values with NaN for those bars
Z(rowsInd(:,barsIdx),:) = NaN;
%# update the ZData
set(h(i), 'ZData',Z)
end
Explanation:
For each group of bars, a surface graphic object is created (with handle stored in h(i)). It's Z-coordinates matrix ZData is represented as a 6*N-by-4 matrix (same thing for XData, YData, and CData matrices), where N is the number of rectangular bars in each group or 7 in the example above.
This way each rectangle is represented with 6x4 matrices (one for each of X/Y/Z coordinates). For example the coordinates of one such rectangle would look like:
>> xx = get(h(3),'XData'); yy = get(h(3),'YData'); zz = get(h(3),'ZData');
>> xx(1:6,:)
ans =
NaN 2.6 3.4 NaN
2.6 2.6 3.4 3.4
2.6 2.6 3.4 3.4
NaN 2.6 3.4 NaN
NaN 2.6 3.4 NaN
NaN NaN NaN NaN
>> yy(1:6,:)
ans =
NaN 0.6 0.6 NaN
0.6 0.6 0.6 0.6
1.4 1.4 1.4 1.4
NaN 1.4 1.4 NaN
NaN 0.6 0.6 NaN
NaN NaN NaN NaN
>> zz(1:6,:)
ans =
NaN 0 0 NaN
0 1 1 0
0 1 1 0
NaN 0 0 NaN
NaN 0 0 NaN
NaN NaN NaN NaN
The second column of each traces the points along the left face, the third column traces the points along the right face, and when the two are connected would draw 4 faces of the rectangle:
>> surface(xx(1:6,2:3), yy(1:6,2:3), zz(1:6,2:3), cc(1:6,2:3))
>> view(3)
The first and last columns would draw the two remaining faces by closing the sides of the rectangle.
All such matrices are concatenated as one tall matrix, and the rectangles are all drawn using a single surface object. This is achieved by using NaN values to separate the different parts, both inside the points of the same rectangle, and in-between the difference rectangles.
So what the above code does is to look for rectangles where the Z-height is zero, and replace all its values with NaN values which effectively tells MATLAB not to draw the surfaces formed by those points.
My problem was not zero values, but NaN values (which are converted into zero values inside of bar3).
I wanted to keep displaying elements with values zero, but not the elements with value nan.
I adjusted the code slightly, and it worked perfectly:
for i = 1:numel(h)
index = logical(kron(isnan(z(:,i)),ones(6,1)));
zData = get(h(i),'ZData');
zData(index,:) = nan;
set(h(i),'ZData',zData);
end
Thanks!