Wednesday, October 14th, 2026¶

Last week, we started to look at multi-dimensional numpy arrays.

In [1]:
import matplotlib.pyplot as plt
import numpy as np
In [2]:
np.ones((10,6))
Out[2]:
array([[1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1., 1.]])

Visualizing 2-dimensional arrays¶

Consider the following 2D-array, filled with integers 0 up to 99.

In [3]:
A = np.arange(100).reshape(10,10)
print(A)
[[ 0  1  2  3  4  5  6  7  8  9]
 [10 11 12 13 14 15 16 17 18 19]
 [20 21 22 23 24 25 26 27 28 29]
 [30 31 32 33 34 35 36 37 38 39]
 [40 41 42 43 44 45 46 47 48 49]
 [50 51 52 53 54 55 56 57 58 59]
 [60 61 62 63 64 65 66 67 68 69]
 [70 71 72 73 74 75 76 77 78 79]
 [80 81 82 83 84 85 86 87 88 89]
 [90 91 92 93 94 95 96 97 98 99]]

For this array, it is small enough that we can simply print the array to understand its contents. For other larger arrays, this becomes infeasable. The plt.imshow function is a very useful tool for visualizing 2D arrays of any size. The basic syntax is plt.imshow(<some 2D array>).

In [4]:
plt.imshow(A)
Out[4]:
<matplotlib.image.AxesImage at 0x29d4a891160>
No description has been provided for this image
In [ ]:
 

When calling plt.imshow on a 2D array, the graph places a colored block at each row & column index pair. The color of the block is determined by the value of the array in that row & column position. The colors are assigned according to a designated colormap.

The colors are assigned so that the lowest value in the array is assigned the "lowest" color in the colormap (dark blue by default) and the highest value of the array is assigned the "highest" color in the colormap (yellow by default). Intermdiate values are assigned intermediate colors between the "lowest" and "highest" colors in the colormap.

Let's make some changes to the A array and see how the output of plt.imshow is affected. For example, suppose we want to set the values in rows 3 or 4 and columns 6 or 7 to be 120.

In [6]:
my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

print(my_list[3:4+1])
['d', 'e']
In [8]:
A[3:5, 6:8]
Out[8]:
array([[36, 37],
       [46, 47]])
In [9]:
A[3:5, 6:8] = 120
In [11]:
print(A)
[[  0   1   2   3   4   5   6   7   8   9]
 [ 10  11  12  13  14  15  16  17  18  19]
 [ 20  21  22  23  24  25  26  27  28  29]
 [ 30  31  32  33  34  35 120 120  38  39]
 [ 40  41  42  43  44  45 120 120  48  49]
 [ 50  51  52  53  54  55  56  57  58  59]
 [ 60  61  62  63  64  65  66  67  68  69]
 [ 70  71  72  73  74  75  76  77  78  79]
 [ 80  81  82  83  84  85  86  87  88  89]
 [ 90  91  92  93  94  95  96  97  98  99]]
In [10]:
plt.imshow(A)
Out[10]:
<matplotlib.image.AxesImage at 0x29d4c100a50>
No description has been provided for this image

Note: Just like the plt.plot function, we can take manual control of the figure and axes generation using plt.figure and plt.subplot. We can use plt.imshow within a subplot in the same way that we use plt.plot. There are also many optional arguments that can be included to modify the default behavior of plt.imshow. For example:

  • We can supply a value vmin that the "darkest" color will be assigned to. Any values in the array that are below this minimum value will also be mapped to the "darkest" color.
  • We can supply a value vmax that the "brightest" color will be assigned to. Any values in the array that are above this maximum value will also be mapped to the "brightest" color.
In [12]:
plt.imshow(A, vmax=99)
Out[12]:
<matplotlib.image.AxesImage at 0x29d4c1665d0>
No description has been provided for this image
In [13]:
plt.imshow(A, vmin=20, vmax=99)
Out[13]:
<matplotlib.image.AxesImage at 0x29d4c1c3750>
No description has been provided for this image

By default, plt.imshow will not interpolate colors between neighboring array positions (unless your screen's resolution is too low to display all of the colored blocks). That is, we can see a discrete set of boxes of colors. We can modify this behavior by using the interpolation keyword. Some available interpolation methods include:

  • 'nearest': each pixel is colored according to the closest colored block to that pixel
  • 'bilinear': each pixel is colored according to a bilinear interpolation (both horizontally and vertically) between nearby colored blocks
  • 'bicubic': each pixel is colored according to a bicubic interpolation (both horizontally and vertically) between nearby colored blocks
  • 'lanczos': each pixel is colored according to Lancsoz interpolation (both horizontally and vertically) between nearby colored blocks
In [15]:
plt.imshow(A, vmin=20, vmax=99, interpolation='bilinear')
Out[15]:
<matplotlib.image.AxesImage at 0x29d4c2bd450>
No description has been provided for this image
In [17]:
plt.imshow(A, vmin=20, vmax=99, interpolation='lanczos')
Out[17]:
<matplotlib.image.AxesImage at 0x29d4c373250>
No description has been provided for this image

We can also modify the color choices used by plt.imshow. These choices are called colormaps. A collection of colormaps can be found on the Matplotlib documentation page.

The cmap keyword argument can be used to change colormaps:

In [19]:
plt.imshow(A, vmin=20, vmax=99, interpolation='bicubic', cmap='plasma')
Out[19]:
<matplotlib.image.AxesImage at 0x29d4a99d090>
No description has been provided for this image
In [ ]:
 

Note: The figures produced above do not indicate what the actual values in the array are. We can call plt.colorbar to add a colorbar that indicates which values correspond to which colors.

In [20]:
plt.imshow(A, vmin=20, vmax=99, interpolation='bicubic', cmap='plasma')
plt.colorbar()
Out[20]:
<matplotlib.colorbar.Colorbar at 0x29d4a891550>
No description has been provided for this image
In [ ]:
 

We can also use colormaps in plt.plot to assign colors to our plots. The colormaps can be found in the cm submodule of matplotlib.

In [21]:
import matplotlib.cm as cm
In [24]:
#help(cm)
In [25]:
cm.plasma
Out[25]:
plasma
plasma colormap
under
bad
over

Each colormap works as a function that takes in a float, where:

  • any input 0 or less returns the color at the left-end of the colormap,
  • any input 1 or more returns the color at the right-end of the colormap,
  • any input between 0 and 1 returns the color that is proportionally between the left-end and right-end of the colormap.
In [26]:
cm.viridis
Out[26]:
viridis
viridis colormap
under
bad
over
In [27]:
cm.inferno
Out[27]:
inferno
inferno colormap
under
bad
over
In [28]:
cm.rainbow
Out[28]:
rainbow
rainbow colormap
under
bad
over

What does the output actually look like when we plug a float into a colormap?

In [37]:
print(cm.plasma(0))
(np.float64(0.050383), np.float64(0.029803), np.float64(0.527975), np.float64(1.0))
In [42]:
print(cm.rainbow(255))
(np.float64(1.0), np.float64(1.2246467991473532e-16), np.float64(6.123233995736766e-17), np.float64(1.0))

RGB(A) values¶

The output from the colormap above is an Red/Green/Blue/Alpha value, or RGBA value. That is, we have a tuple (R, G, B, A) where:

  • R is the amount of red in the color (R=1 means full red, R=0 means no red),
  • G is the amount of green in the color (G=1 means full green, G=0 means no green),
  • B is the amount of blue in the color (B=1 means full blue, B=0 means no blue),
  • A is the transparency of the color (A=1 means fully opaque, A=0 means fully transparent).

If the transparency channel is omitted (i.e. if we work with a pure RGB triple), the color is assume to be fully opaque. We can also supply our own RGB(A) tuples in plt.plot to specify colors.

In [46]:
t = np.linspace(0,1,1000)
y1 = t**2
y2 = t**2 + 1
y3 = t**2 + 2

plt.plot(t,y1, color=(.3, .7, .4))
plt.plot(t,y2, color=(0, .6, .8))
plt.plot(t,y3, color=(1, .2, .4))
Out[46]:
[<matplotlib.lines.Line2D at 0x29d4c652c10>]
No description has been provided for this image
In [ ]:
 
In [ ]:
 

The plt.imshow function can also work with RGB(A) values. Instead of supplying a 2D-array, we can supply a 3D-array where:

  • The first axis corresponds to the row of the array,
  • The second axis corresponds to the column of the array,
  • The third axis corresponds to the RGB(A) values of the array.

For example, let's define a 10 by 20 array with 3 color channels (RGB) called RGB_array.

In [52]:
RGB_array = np.zeros((10,20,3))
In [53]:
RGB_array[4, 6]    # Get the element in row 4, column 6
Out[53]:
array([0., 0., 0.])
In [54]:
RGB_array[8, 1]
Out[54]:
array([0., 0., 0.])
In [55]:
plt.imshow(RGB_array)
Out[55]:
<matplotlib.image.AxesImage at 0x29d4c6cd090>
No description has been provided for this image

For the above array, we will think of RGB_array[:,:,0] as a $2D$-array containing the red data. Similarly, RGB_array[:,:,1] contains the green data, and RGB_array[:,:,2] contains the blue data. Let's add some colored stripes to the array.

Note: We can take slices through the rows/columns of an (m,n,3) array of RGB values. For example, RGB_array[:4, 3:7] will give a (4,4,3) array consisting of the RGB triples in rows 0, 1, 2, 3 and columns 3, 4, 5, 6. If we set RGB_array[:4, 3:7] = (.1, .7, .9), then every RGB triple in these rows/columns will be set to (.1, .7, .9). This is called broadcasting, and is a very useful feature of NumPy.

In [57]:
RGB_array[:4, 3:7].shape
Out[57]:
(4, 4, 3)
In [58]:
RGB_array[:4, 3:7] = (.1, .7, .9)
In [59]:
plt.imshow(RGB_array)
Out[59]:
<matplotlib.image.AxesImage at 0x29d4c72f610>
No description has been provided for this image
In [63]:
RGB_array[:4, 3:7] = (.1, .7, .9)
RGB_array[7:10, -4:] = (1, .7, .7)
RGB_array[4:7, :] = (0, 1, 1)
RGB_array[:, 10:15] = (1, 0, 1)
RGB_array[7:,5:10] = (1, 1, 0)

plt.imshow(RGB_array)
Out[63]:
<matplotlib.image.AxesImage at 0x29d4da80cd0>
No description has been provided for this image
In [ ]:
 

Most computer images are stored as arrays of RGB(A) values. We can read an image file into an RGB(A) array using plt.imread. The syntax is: plt.imread(<path to some image file>). For example, download the image mario.png from the course webpage and place it into the same folder as this Jupyter notebook.

In [95]:
mario = plt.imread('mario.png')
In [99]:
plt.imshow(mario)
Out[99]:
<matplotlib.image.AxesImage at 0x29d4fb3fed0>
No description has been provided for this image
In [100]:
mario.shape
Out[100]:
(224, 256, 4)
In [101]:
print(mario[0, 0])
[0.36078432 0.5803922  0.9882353  1.        ]

We can look at the shape of the array to see if it contains RGB or RGBA values. In this case, the mario.png image file includes a transparency channel.

In [102]:
mario.shape
Out[102]:
(224, 256, 4)
In [ ]:
 

Exercise: Use NumPy slicing to remove the transparency channel from the mario array.

In [103]:
my_list = [1,2,3,4,5]
In [104]:
my_list[:4]
Out[104]:
[1, 2, 3, 4]
In [105]:
my_list[:-1]
Out[105]:
[1, 2, 3, 4]
In [106]:
mario[:, :, :3].shape
Out[106]:
(224, 256, 3)
In [107]:
mario = mario[:,:,:3]
In [108]:
mario.shape
Out[108]:
(224, 256, 3)

Exercise: Use NumPy slicing and plt.imshow to zoom in on Mario (in the lower-left corner).

In [111]:
mario[180:210, 35:65].shape
Out[111]:
(30, 30, 3)
In [116]:
plt.imshow(mario[180:210, 35:65])
Out[116]:
<matplotlib.image.AxesImage at 0x29d4f9c20d0>
No description has been provided for this image
In [ ]:
 

Exercise: Create an array blueless_mario where the blue channel information from mario has been removed (i.e. set to 0) and plot using plt.imshow.

In [117]:
blueless_mario = mario.copy()    # Create a copy so that we don't modify the original array
In [118]:
blueless_mario[:,:,2] = 0
In [119]:
plt.imshow(blueless_mario)
Out[119]:
<matplotlib.image.AxesImage at 0x29d4fe97ed0>
No description has been provided for this image

Exercise: Create an array mixed_mario where:

  • the red channel of mixed_mario matches the green channel of mario,
  • the green channel of mixed_mario matches the blue channel of mario,
  • the blue channel of mixed_mario matches the red channel of mario.
In [120]:
mixed_mario = mario.copy()
In [123]:
mixed_mario[:,:,0] = mario[:,:,1]   # Set red channel of mixed array to green channel of original
mixed_mario[:,:,1] = mario[:,:,2]   # Set green channel of mixed array to blue channel of original
mixed_mario[:,:,2] = mario[:,:,0]   # Set blue channel of mixed array to red channel of original
In [124]:
plt.imshow(mixed_mario)
Out[124]:
<matplotlib.image.AxesImage at 0x29d4ff27390>
No description has been provided for this image
In [ ]:
 
In [ ]:
 

Note: For the next project, we will be working with integer-valued RGB triples. The integer-values will range from 0 to 255. An integer 0 means no color while an integer 255 means full color (equivalent to a float of 1).

Exercise: Convert the mario array to an integer-type array mario_RGB_int containing RGB triples with values between 0 and 255.

In [125]:
mario[0,0]
Out[125]:
array([0.36078432, 0.5803922 , 0.9882353 ], dtype=float32)
In [132]:
mario_RGB_int = (mario*255).astype(int)
In [133]:
plt.imshow(mario_RGB_int)
Out[133]:
<matplotlib.image.AxesImage at 0x29d511dd090>
No description has been provided for this image

Exercise: Convert the mario_RGB_int array into a float-type array containing RGB triples with values between 0 and 1.

In [134]:
mario_RGB_float = mario_RGB_int / 255
In [135]:
plt.imshow(mario_RGB_float)
Out[135]:
<matplotlib.image.AxesImage at 0x29d5125c550>
No description has been provided for this image
In [ ]: