Adding Axes: newaxis & expand_dims

Reviewed & published by Brayan K

np.newaxis (and its function form np.expand_dims) inserts a new length-1 dimension into an array, reshaping a flat vector into a row or a column so that broadcasting can combine it with other arrays.

Part of the free NumPy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

You'll add axes with newaxis and expand_dims, remove size-1 axes with squeeze, and use a column-versus-row vector to build a grid of values entirely through broadcasting.

What You'll Learn in This Lesson

1 np.newaxis: Rows and Columns from a Vector

A 1D array of shape (3,) is neither a row nor a column — it is just a flat sequence. Indexing with np.newaxis (which is literally None) inserts a length-1 axis to give it a 2D shape. Put the new axis last for a column (3, 1), or first for a row (1, 3).

import numpy as np

v = np.array([1, 2, 3])     # shape (3,)

v[:, np.newaxis]            # shape (3, 1)  -> column
# [[1]
#  [2]
#  [3]]

v[np.newaxis, :]            # shape (1, 3)  -> row
# [[1 2 3]]
import numpy as np

v = np.array([1, 2, 3])
print(v.shape)              # (3,)

col = v[:, np.newaxis]
print(col.shape)            # (3, 1)
print(col)
# [[1]
#  [2]
#  [3]]

row = v[np.newaxis, :]
print(row.shape)            # (1, 3)
print(row)
# [[1 2 3]]

# ✅ Expected output:
# (3,)
# (3, 1)
# [[1]
#  [2]
#  [3]]
# (1, 3)
# [[1 2 3]]

2 expand_dims to Add, squeeze to Remove

np.expand_dims(arr, axis) does the same job as newaxis but as a function call, which is handy when the axis number is computed. Its inverse is np.squeeze, which deletes every length-1 axis (or just the one you name), collapsing a shape like (1, 3, 1) back down to (3,).

v = np.array([1, 2, 3])

np.expand_dims(v, axis=0).shape   # (1, 3)
np.expand_dims(v, axis=1).shape   # (3, 1)

a = np.zeros((1, 3, 1))
np.squeeze(a).shape               # (3,)
np.squeeze(a, axis=0).shape       # (3, 1)
import numpy as np

v = np.array([1, 2, 3])

# expand_dims: add a size-1 axis by number
print(np.expand_dims(v, axis=0).shape)   # (1, 3)
print(np.expand_dims(v, axis=1).shape)   # (3, 1)

# squeeze: remove size-1 axes
a = np.zeros((1, 3, 1))
print(a.shape)                           # (1, 3, 1)
print(np.squeeze(a).shape)               # (3,)
print(np.squeeze(a, axis=2).shape)       # (1, 3)

# ✅ Expected output:
# (1, 3)
# (3, 1)
# (1, 3, 1)
# (3,)
# (1, 3)

3 The Payoff: Broadcasting a Grid

The main reason to add axes is to unlock broadcasting. Make one vector a column (n, 1) and another a row (1, m); combining them stretches each across the other to produce an (n, m) grid. This is how you build an addition table or an outer product without any loops — a lighter-weight alternative to meshgrid.

a = np.array([1, 2, 3])          # will be the column
b = np.array([10, 20])           # will be the row

a[:, None] + b[None, :]          # shape (3, 2)
# [[11 21]
#  [12 22]
#  [13 23]]
import numpy as np

a = np.array([1, 2, 3])
b = np.array([10, 20, 30])

# Column (3, 1) + row (1, 3) -> a full (3, 3) addition table
table = a[:, np.newaxis] + b[np.newaxis, :]

print(table.shape)   # (3, 3)
print(table)
# [[11 21 31]
#  [12 22 32]
#  [13 23 33]]

# Same idea makes a multiplication (outer) product
print(a[:, None] * b[None, :])
# [[10 20 30]
#  [20 40 60]
#  [30 60 90]]

# ✅ Expected output:
# (3, 3)
# [[11 21 31]
#  [12 22 32]
#  [13 23 33]]
# [[10 20 30]
#  [20 40 60]
#  [30 60 90]]

🎯 YOUR TURN: Fill in the Blank

Turn v into a column vector of shape (4, 1) by filling in the indexing token.

import numpy as np

v = np.array([5, 6, 7, 8])

# Insert a NEW axis at the end to make a column vector
col = v[:, np.___]

print(col.shape)   # (4, 1)
print(col)
# Expected output:
# [[5]
#  [6]
#  [7]
#  [8]]

Answer: newaxis (so v[:, np.newaxis]). You could also write v[:, None].

! Common Errors (And How to Fix Them)

❌ Two 1D arrays will not broadcast into a grid

Adding two shape-(3,) arrays just adds them element-wise, not as a table:

a + b   # shape (3,), an element-wise sum, NOT a (3, 3) grid

✅ Fix: add axes so one is a column and one is a row:

a[:, None] + b[None, :]   # shape (3, 3)

❌ squeeze removed an axis you wanted to keep

A bare np.squeeze(arr) drops every size-1 axis at once.

✅ Fix: name the axis, e.g. np.squeeze(arr, axis=0), to remove only that one.

❌ Wrong axis position for the new dimension

v[np.newaxis, :] makes a row, v[:, np.newaxis] makes a column — easy to swap.

✅ Fix: print .shape after adding the axis to confirm it is (1, n) or (n, 1).

🎯 Mini Challenge: Pairwise Differences

Use newaxis to compute the difference between every pair of values in a vector — a common step in distance calculations.

import numpy as np

points = np.array([0, 3, 7])

# Subtract every value from every value: column - row
diffs = points[:, np.newaxis] - points[np.newaxis, :]

print(diffs.shape)   # (3, 3)
print(diffs)
# [[ 0 -3 -7]
#  [ 3  0 -4]
#  [ 7  4  0]]

# Absolute pairwise distances
print(np.abs(diffs))
# [[0 3 7]
#  [3 0 4]
#  [7 4 0]]

# ✅ Expected output:
# (3, 3)
# [[ 0 -3 -7]
#  [ 3  0 -4]
#  [ 7  4  0]]
# [[0 3 7]
#  [3 0 4]
#  [7 4 0]]

❓ Frequently Asked Questions

Lesson complete — you can reshape with new axes!

You can insert a length-1 dimension with np.newaxis or np.expand_dims, remove one with np.squeeze, and use a column-versus-row pairing to broadcast a full grid.

Practice quiz

What is np.newaxis literally equal to?

  • None
  • 0
  • An empty array
  • 1

Answer: None. np.newaxis is just an alias for Python's None, so v[:, None] and v[:, np.newaxis] are identical.

What shape does v[:, np.newaxis] give a shape-(3,) array?

  • (1, 3)
  • (3, 1)
  • (3,)
  • (3, 3)

Answer: (3, 1). Putting the new axis last makes a column vector of shape (3, 1).

What shape does v[np.newaxis, :] give a shape-(3,) array?

  • (3, 1)
  • (3, 3)
  • (1, 3)
  • (3,)

Answer: (1, 3). Putting the new axis first makes a row vector of shape (1, 3).

Which function inserts a size-1 axis using a number argument?

  • np.squeeze
  • np.reshape
  • np.ravel
  • np.expand_dims

Answer: np.expand_dims. np.expand_dims(arr, axis=1) adds a length-1 axis at the given position, the function form of newaxis.

What does np.squeeze do by default?

  • Removes every length-1 axis
  • Adds a new axis
  • Flattens to 1D always
  • Transposes the array

Answer: Removes every length-1 axis. Bare np.squeeze drops all size-1 dimensions; name an axis to remove just one.

What shape does np.expand_dims(v, axis=0) produce from shape (3,)?

  • (3, 1)
  • (1, 3)
  • (3,)
  • (3, 3)

Answer: (1, 3). axis=0 inserts the new length-1 axis first, giving (1, 3).

To broadcast a column against a row into an (n, m) grid, you need...

  • Two 1D arrays of the same length
  • One (n, 1) and one (1, m) array
  • Two scalars
  • A single (n, m) array

Answer: One (n, 1) and one (1, m) array. A column (n, 1) and a row (1, m) broadcast into an (n, m) grid.

Does adding an axis with newaxis move or copy the underlying data?

  • It copies all the data
  • It sorts the data
  • No, only the shape changes
  • It deletes elements

Answer: No, only the shape changes. newaxis only changes the shape metadata; the data is never moved.

Which removes only the first axis from shape (1, 3, 1)?

  • np.squeeze(a, axis=0)
  • np.squeeze(a)
  • np.expand_dims(a, 0)
  • a.ravel()

Answer: np.squeeze(a, axis=0). Naming axis=0 removes only that size-1 axis, leaving (3, 1).

What does a[:, None] + b[None, :] compute for 1D a and b?

  • An element-wise sum
  • A scalar
  • A broadcast grid of pairwise sums
  • An error

Answer: A broadcast grid of pairwise sums. Pairing a column with a row broadcasts into a full 2D grid of pairwise sums.

Continue this course

Frequently asked questions

What does np.newaxis actually do?

np.newaxis is just an alias for Python's None, and using it inside indexing inserts a new dimension of length 1 at that position. arr[:, np.newaxis] turns a shape (3,) array into shape (3, 1), and arr[np.newaxis, :] turns it into (1, 3). The data is unchanged; only the shape gains a size-1 axis that broadcasting can stretch.

What is the difference between np.newaxis and np.expand_dims?

They do the same thing in two styles. arr[:, np.newaxis] uses indexing syntax, while np.expand_dims(arr, axis=1) is a function call that inserts a size-1 axis at the given position. expand_dims is often clearer in code that computes the axis number, while newaxis is more compact inline.

How do I remove dimensions of length 1?

Use np.squeeze. np.squeeze(arr) drops every axis whose length is 1, turning shape (1, 3, 1) into (3,). Pass an axis argument like np.squeeze(arr, axis=0) to remove only a specific size-1 axis. It is the inverse of adding axes with newaxis or expand_dims.

Why do I need to add an axis to broadcast a column against a row?

To form an outer-product-style grid, one operand must vary down the rows and the other across the columns. A plain 1D array only varies along one axis. By making one a column vector with shape (n, 1) and the other a row vector with shape (1, m), broadcasting expands them into an (n, m) result. newaxis is the tool that creates those size-1 axes.