# Numpy 2D arrays - some examples

This notebook demonstrates how to work with 2D numpy arrays, including array slicing, random numbers, and making plots with them. Note that this works with higher-dimensional arrays as well!

``````

In [ ]:

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import random

``````

# Array creation and basic properties

Create an 8x10 array of zeros called `my_array`. Note that you can do this with any numpy array method (`ones`, `zeros_like`, `ones_like`, etc.). See this page for a full list of routines for array creation.

``````

In [ ]:

a = np.zeros([8,10])
print(a)

``````

You have already created a 1D numpy array of predetermined values by giving `np.array` a list. You can make a multi-dimensional numpy array by giving `np.array` a set of nested lists (i.e., a list of lists). The following will create a 3x3 array with predetermined values:

``````

In [ ]:

b = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(b)

``````

The array `.shape` property tells you how large the array is in each dimension, `.ndim` tells you the number of dimensions, and `.size` tells you the total number of elements in the array. You can access each of the dimensions `dim` by `.shape[dim]`.

``````

In [ ]:

print("the shape of this array is:", a.shape)
print("there are:", a.ndim, "dimensions")
print("there are", a.size, "total elements")

for i in range(a.ndim):
print("the size of dimension", i, "is", a.shape[i])

``````

You can manipulate individual cells of an array by:

`a[index_1,index_2]`

Note that when you print it, the first index corresponds to rows (counting down from the top) and the second index corresponds to columns (counting from the left). Indices in both directions count by zeros.

``````

In [ ]:

a[2,6]=11

#print entire array
print(a)

#print a single element of the array
print(a[2,6])

``````

# Slicing arrays

You can also use the same type of slicing that you use with lists - in other words, python allows you to select some subset of the elements in a list or an array to manipulate or copy. With slicing, there are three values that can be used along each dimension: `start`,`end`, and `step`, separated by colons. Here are some examples in 1D:

``````myarray[start,end]   # items start through end-1
myarray[start:]      # items start through the end of the array
myarray[:end]        # items from the beginning of the array through end-1
myarray[:]           # a copy of the whole array
myarray[start,end,step]  # every "step" item from start to end-1
myarray[::step]      # every "step" item over the whole array, starting with the first element.``````

Note that negative indices count from the end of the array, so `myarray[-1]` is the last element in the array, `myarray[-2]` is the second-to-last element, etc. You can also reverse the order of the array by starting at the end and counting to the beginning by negative numbers -- in other words, `myarray[-1::-1]` starts at the end of the array and goes to the first element by counting down by one each time.

``````

In [ ]:

# create a 1D array with values 0...10
c = np.arange(0,10)

# note: the '\n' at the beginning of many of the print statements
# adds a carriage return (blank line)

print("some elements from the middle of the array:",c[3:7] )
print("\nthe second element through the second-to-last element:", c[2:-1])
print("\nthe first half of the array:", c[:5])
print("\nthe second half of the array:", c[5:])
print("\nevery other element from 2-8 (inclusive):",c[2:9:2])
print("\nevery third element in the array:",c[::3])
print("\nreverse the array:",c[-1::-1])

``````

The same sort of technique can be used with a multi-dimensional array, with `start`, `stop`, and (optionally) `step` specified along each dimension, with the dimensions separated by a comma. The syntax would be:

``my2Darray[start1:stop1:step1, start2:stop2:step2]``

With the same rules as above. You can also combine slicing with fixed indices to get some or all elements from a single row or column of your array.

For example, array `b` created above is a 3x3 array with the values 1-9 stored in it. We can do several different things:

``````b[0,:]     # get the first row
b[:,2]     # get the third column
b[1,::2]   # get every other element of the first row, starting at element 0
b[:2,:2]   # get a square array containing the first two elements along each dimension
b[-2:,-2:] # get a square array containing the last two elements along each dimension
b[::2,::2] # get a square array of every other element along each dimension
b[-1::-1,-1::-1]  # original sized array, but reversed along both dimensions``````
``````

In [ ]:

print("the array b:\n",b,"\n")
#  To get a square array containing the first two elements along each dimension:
print("the first row:", b[0,:])

print("\nthe third column:",b[:,2])

print("\nevery other element of the second row, starting with element 0:",b[1,::2])

print("\nsquare array of first two elements along each dimension:\n",b[:2,:2])

print("\nsquare array of last two elements along each dimension:\n",b[-2:,-2:])

print("\nsquare array of every other element along each dimension:\n",b[::2,::2])

print("\nreversed array:\n",b[-1::-1,-1::-1])

``````

# Copying arrays

So far, we've only shown you how to create arrays and manipulate subsets of arrays. But what about copying arrays? What happens when you create an array c, and set d=c?

``````

In [ ]:

c = np.full((4,4),10.0)  # makes an array of shape (4,4) where all elements are value 10.0

d = c

print("c:\n",c, "\nd:\n", d)

``````

The two arrays are the same, which is what you would expect. But, what happens if we make changes to array d?

``````

In [ ]:

d[:,0] = -1.0  # make column 0 equal to -1
d[:,2] = -6.0  # make column 2 equal to -6

print("c:\n",c, "\nd:\n", d)

``````

Arrays `c` and `d` are identical, even though you only changed `d`!

So what's going on here? When you equate arrays in Numpy (i.e., `d = c`), you create a reference, rather than copying the array -- in other words, the array `d` is not a distinct array, but rather points to the array `c` in memory. Any modification to either `c` or `d` will be seen by both. To actually make a copy, you have to use the `np.copy()` method:

``````

In [ ]:

e = np.full((4,4),10.0)  # makes an array of shape (4,4) where all elements are value 10.0

f = np.copy(e)

f[:,0] = -1.0  # make column 0 equal to -1
f[:,2] = -6.0  # make column 2 equal to -6

print("e:\n",e, "\nf:\n", f)

``````

You can also make a copy of a subset of an arrays:

``````

In [ ]:

g = np.full((4,4),10.0)  # makes an array of shape (4,4) where all elements are value 10.0

h = np.copy(g[0:2,0:2])

print("g:\n",g, "\nh:\n", h)

``````

Note that you can also create an array that references a subset of another array rather than copies it, and manipulate that in any way you want. The changes will then appear in both the new array and your original array. For example:

``````

In [ ]:

i = np.full((4,4),10.0)  # makes an array of shape (4,4) where all elements are value 10.0

j = i[0:2,0:2]

print("\nunmodified arrays:\n")

print("i:\n",i, "\nj:\n", j)

print("\narrays after modification:\n")

j[1,1]=-999.0

print("i:\n",i, "\nj:\n", j)

``````

# Numpy and random numbers

Numpy has a `random` module that can be used to generate random numbers in a similar way to the standard Python `random` module, but with the added advantage that it can do so for arrays of values. Two commonly-used methods are:

• `random`, which generates an array with user-specified dimensions (1D, 2D, or more dimensions!) and fills it with random floating-point values in the interval [0,1).
• `randint`, which generates an array with user-specified dimensions and fills it with random integers in a user-specified interval.
``````

In [ ]:

random_float_array = np.random.random((5,5))

print(random_float_array)

random_int_array = np.random.randint(0,10,(5,5))

print("\n",random_int_array)

``````

# Plotting numpy arrays

It's easy to plot 2D Numpy arrays in matplotlib using the pyplot `matshow` method:

``````

In [ ]:

new_rand_array = np.random.random((100,100))

plt.matshow(new_rand_array)

# uncomment the following line to save the figure to your hard drive!
#plt.savefig("myimage.png")

``````

And you can turn off the array axes with the following incantation:

``````

In [ ]:

myplot = plt.matshow(new_rand_array)
myplot.axes.get_xaxis().set_visible(False)
myplot.axes.get_yaxis().set_visible(False)

``````

(See this page for a more complex example.) Finally, you can use the pyplot `imshow` method to control many aspects of a plotted array, including things like the color map, opacity, and the minimum and maximum range.

``````

In [ ]:

# interpolation='none' keeps imshow() from trying to interpolate between values and
#   making it look fuzzy.
# cmap='mapname' changes the color map.
# vmin, vmax sets the range of the color bar (from 0.0 - 0.5 in this example)

myplot = plt.imshow(new_rand_array, interpolation='none',cmap='hot',vmin=0.0,vmax=0.5)

# uncomment the following lines to remove the axis labels
#myplot.axes.get_xaxis().set_visible(False)
#myplot.axes.get_yaxis().set_visible(False)

# uncomment the following line to save the figure to your hard drive!
#plt.savefig("myimage.png")

``````