I have 2D numpy array that I want to mask and plot. I have tried this.
import numpy as np
import matplotlib.pyplot as plt
a = np.random.random((101,99))
data1 = a.copy()
bound = np.percentile(data1, 80)
data1[data1<bound] = np.nan
plt.figure()
plt.imshow(data1)
Output:
data2 = a.copy()
data2[data2 < bound] = 0
plt.figure()
plt.imshow(data2)
Output:
I am expecting the first image to look like the second image, where there are the same number of white pixels as dark-blue pixels, and the white pixels are in the same position as the dark-blue pixels. Clearly, there are more white pixels than dark-blue pixels. I feel like I'm missing something simple. Is something wrong with my matplotlib
configuration?
EDIT:
To show the first image actually has more white pixels than the second image -- and there are no anti-aliasing effects -- I have rerun the code block using plt.gca().set_facecolor('black')
:
a = np.random.random((101,99))
data1 = a.copy()
bound = np.percentile(data1, 80)
data1[data1<bound] = np.nan
plt.figure()
plt.imshow(data1)
plt.gca().set_facecolor('black')
Output:
data2 = a.copy()
data2[data2 < bound] = 0
plt.figure()
plt.imshow(data2)
Output:
The effect is due to antialiasing. For each pixel on the screen, matplotlib averages out the corresponding pixels of the data. If one of the data pixels is NaN
, the complete screen pixel is considered transparent. With zeros instead of NaN
s, the standard averaging is used.
The following code example illustrates what's happening.
import numpy as np
import matplotlib.pyplot as plt
a = np.random.random((101, 99))
data1 = a.copy()
bound = np.percentile(data1, 80)
data1[data1 < bound] = np.nan
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(15, 6))
ax1.imshow(data1)
ax2.imshow(data1)
ax2.set_facecolor('black')
data2 = a.copy()
data2[data2 < bound] = 0
ax3.imshow(data2)
plt.tight_layout()
plt.show()
Now, the same, but with figsize=(10,4)