MATLAB Answers

Fill NaN cell with mean of eight surrounding cells in grid data in matlab

11 views (last 30 days)
Shakir Hussain
Shakir Hussain on 21 Apr 2018
Edited: Jan on 25 Apr 2018
I am trying to fill the NaN values of grid data with 8 surrounding values but could not understand, what is going wrong here in my matlab code. The data is 752*891*11 %%% (11 years precipitation of 752*891 cells).
for i = 2 : 752
for j = 2 : 891
for k = 1 : 11
if isnan(data(i,j,k)) == 1
data(i,j,k) = nanmean(nanmean(data(i-2:i+2,j-2:j+2,k-2:k+2)));
Thanks in advance for help


Sign in to comment.

Accepted Answer

Jan on 21 Apr 2018
Edited: Jan on 25 Apr 2018

If you want to replace a scalar based on a 3D array, you either need 3 nanmean calls:

nanmean(nanmean(nanmean(data(i-1:i+1, j-1:j+1, k-1:k+1))))

with i-1:i+1, instead of i-2:i+2. This would be easier:

if isnan(data(i,j,k))   % "== 1" is not needed
  tmp         = data(i-1:i+1, j-1:j+1, k-1:k+1);  % 3D block
  data(i,j,k) = nanmean(tmp(:));                  % Make it a vector

But this is a 3x3x3 neighborhood with 27 elements, not 8. I assume you mean:

if isnan(data(i,j,k))   % "== 1" is not needed
  tmp1        = data(i-1:i+1, j, k);
  tmp2        = data(i:i, j-1:j+1, k);
  tmp3        = data(i, j, k-1:k+1);
  tmp         = [tmp1(:); tmp2(:); tmp3(:)];  % Create a vector
  data(i,j,k) = nanmean(tmp);

Because the center point data(i,j,k) is included 3 times, but ignored by nanmean, you have 6 neighbors now, not 8.

So please explain again, what you exactly want.


Show 4 older comments
Shakir Hussain
Shakir Hussain on 24 Apr 2018
The above four preference is for single year and wants to repeat the same way for 11 years. We have both positive and negative values of temperature and your above given code is pop up with (Subscript indices must either be real positive integers or logicals.) error.
Jan on 24 Apr 2018

When you access the index i-2:i+2, the loop for i must start at 3, not at 2, because 0 is not a valid index. And the loop must stop at size(data, 1) - 2. Equivalently for j.

Please post a copy of the complete message, if you mention an error in the forum.

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 22 Apr 2018
means = conv2(YourMatrix, [1 1 1;1 0 1;1 1 1]/8,'same') ;
mask = isnan(YourMatrix);
YourMatrix(mask) = means(mask);

No loops needed.

Note: you would need a little adjustment to handle a nan on the edge of the matrix, to calculate the means properly.


Show 1 older comment
Walter Roberson
Walter Roberson on 22 Apr 2018
Ah, good point, the 0 * nan at the point itself makes the conv2() result into nan.
Jan on 22 Apr 2018

A solution to use conv2 with NaNs:

nanX    = isnan(X);
X(nanX) = 0;
mask    = [1 1 1; 1 0 1; 1 1 1];
means   = conv2(X,     mask, 'same') ./ ...
          conv2(~nanX, mask, 'same');
X(nanX) = means(nanX);

But I'm not sure, how this can be applied to the OP's problem. A neighborhood of 6 or 10(?) elements is wanted.

Sign in to comment.

Sign in to answer this question.

Translated by