ndarray ¶
A ndarray is a fundamental concept in the NumPy library, serving as a powerful tool for organizing data. Picture it as a grid, like an image or chessboard, where each square contains a specific number or piece of information. For example, we can look at a cute image of a racoon (i.e., trash panda) in gray scale.
Note that our origin
(0, 0)
is not
at the bottom left like we are used to in graphs.
We will go more in detail later.
This image is actually just a NumPy array! Each value is how bright that pixel is—a value of 0 is black and 255 is white.
print(image)
[[117 134 149 ... 118 128 136] [ 86 107 127 ... 117 133 145] [ 70 91 112 ... 117 133 144] ... [ 97 102 115 ... 140 139 139] [ 93 103 119 ... 139 138 138] [ 93 105 118 ... 138 137 136]]
For example, let's look get a closer look at our furry friend.
We see darker pixels at the top right (i.e., low values) and lighter pixels (i.e., higher values) in the bottom right.
Now, let's print the array of this 5x5 array.
[[ 33 26 17 14 18] [ 79 64 43 26 16] [123 110 88 67 50] [129 126 122 117 109] [112 118 128 136 140]]
We indeed do see lower values in the top right near index
[480, 604]
and higher values in the bottom left near index
[484, 600]
.
As you can see, ndarray just holds data for us just like a massive Excel file with a bunch of numbers.
You know how videos are around 60 images displayed per second? Well, we can stack these images together in NumPy to get a 3D array.
import io
from urllib import request
NPY_PATH = "https://github.com/oasci-bc/python/raw/refs/heads/main/docs/files/npy/steamboat-willie.npy"
response = request.urlopen(NPY_PATH)
content = response.read()
# Load the .npy file
public_domain_willie = np.load(io.BytesIO(content))
Let's print a row of this mystery film.
print(public_domain_willie[34, 24])
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 67 107 123 122 121 121 121 121 122 123 123 123 123 123 123 123 123 123 123 123 124 124 124 125 125 125 125 125 125 125 125 125 125 125 125 125 125 126 126 126 128 129 129 129 129 130 130 130 131 131 132 132 132 132 132 131 131 131 131 131 131 131 131 131 131 131 131 131 131 132 132 132 133 133 133 135 135 135 136 136 136 137 137 137 137 137 136 136 136 136 136 136 136 136 136 135 135 135 135 135 133 132 132 131 130 129 130 130 130 130 130 130 130 130 129 129 128 128 128 128 129 128 128 128 128 129 119 98 87 98 117 119 117 116 112 109 104 96 89 83 78 74 72 69 67 66 65 68 71 76 81 88 96 93 75 66 64 79 103 114 117 118 118 117 118 121 122 124 126 128 128 129 130 132 133 135 136 137 137 137 138 138 137 137 137 138 138 138 138 139 139 139 139 139 139 139 139 139 140 140 140 140 140 140 140 140 140 140 140 140 140 142 142 143 142 142 142 144 144 142 142 140 140 142 140 142 139 138 139 140 139 136 124 105 98 87 55 37 52 52 55 65 86 105 112 107 108 93 83 67 51 51 57 64 79 90 100 109 118 125 128 133 137 137 137 139 138 138 138 139 140 140 142 140 140 139 139 139 139 138 138 138 138 137 137 137 137 137 137 137 137 136 135 133 133 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 137 137 136 136 136 136 136 135 135 135 133 133 132 132 132 132 132 132 132 132 132 132 132 132 132 132 132 132 132 132 132 131 130 129 129 130 129 130 129 128 129 129 128 128 128 126 126 126 125 125 125 125 125 124 124 123 123 123 121 117 114 125 114 103 88 61 44 34 27 25 27 31 31 32 34 33 25 20 13 13 30 45 55 69 90 105 116 119 119 119 121 121 121 121 121 122 123 124 125 126 126 128 130 131 131 132 132 133 135 135 137 139 140 142 144 146 147 140 116 71 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
Yes, that makes sense ... right? This is just one row of pixels and I cannot get much information out of it. Let's just display the frames one after another. This following code is not web friendly, so I rendered this animation using the code below and saved as a gif.
This is public domain, Disney!
Code
from matplotlib.animation import FuncAnimation
frames = public_domain_willie.shape[0]
# Set up the plot
fig, ax = plt.subplots()
img = ax.imshow(public_domain_willie[0], cmap='gray')
ax.set_title('Frame 1/{}'.format(frames))
# Update function for the animation
def update(frame):
img.set_array(public_domain_willie[frame])
ax.set_title('Frame {}/{}'.format(frame + 1, frames))
return img,
# Create the animation
animation = FuncAnimation(fig, update, frames=frames, interval=30, blit=True)
animation.save('animation.gif', writer='imagemagick', fps=30)