Written and maintained by CASRAI Editorial Board
Last updated
numpy.meshgrid turns 1-D coordinate vectors into coordinate matrices, so a function of two or three variables can be evaluated at every grid point in one vectorised expression. The two choices that trip people up are indexing='xy' versus 'ij', which swap the first two output axes, and sparse=True, which returns broadcastable arrays instead of full ones. This guide shows the syntax, a shape table for both indexing modes in 2-D and 3-D, a function-on-a-grid example, and the problems to expect. Outputs below were run on NumPy 2.5.1 and checked against the NumPy 2.5 reference (read 2026-11-07).
What numpy.meshgrid is used for in research
Given vectors x1, x2, ..., xn, numpy.meshgrid returns a tuple of n coordinate arrays, one per input, so that every combination of coordinates is represented. Typical research uses are evaluating a response surface or likelihood over two parameters, building a 2-D field for a contour or surface plot (see contour plots in Matplotlib and 3-D plots in MATLAB for the plotting side), and generating coordinates for a spatial model.
Install or access
The only prerequisite for NumPy is Python. The official install page (numpy.org/install, read 2026-11-07) gives pip install numpy for pip, and for conda: conda create -n my-env, conda activate my-env, then conda install numpy. If you do not have Python yet, see installing Anaconda Python. meshgrid ships inside NumPy; there is nothing separate to install.
Step-by-step: build and use a grid
The signature in the NumPy 2.5 reference is numpy.meshgrid(*xi, copy=True, sparse=False, indexing='xy').
- Import NumPy and create the 1-D coordinate vectors.
import numpy as np nx, ny = (3, 2) x = np.linspace(0, 1, nx) y = np.linspace(0, 1, ny) - Call meshgrid.
xv, yv = np.meshgrid(x, y) # xv -> [[0. , 0.5, 1. ], [0. , 0.5, 1. ]] # yv -> [[0., 0., 0.], [1., 1., 1.]]Each output has one row per
yvalue and one column perxvalue, soxv.shapeis (2, 3). - Evaluate a function on the grid. Using the reference’s own pattern:
x = y = np.linspace(-5, 5, 101) xx, yy = np.meshgrid(x, y) zz = np.sqrt(xx**2 + yy**2) # shape (101, 101)No Python loop is needed because the arithmetic is applied element-wise to the whole grid.
- Pass the arrays to your plotting or analysis code.
xx,yyandzznow share one shape, which is what contour and surface functions expect.
Output and how to read it: indexing=’xy’ versus ‘ij’
The default indexing='xy' is Cartesian: the first input varies along columns, the second along rows. indexing='ij' is matrix indexing: the first input varies along the first axis. For inputs of length M and N the NumPy reference gives these output shapes (3-D with inputs M, N, P; for 1-D and 0-D inputs, indexing and sparse have no effect):
| Number of inputs | indexing=’xy’ (default) | indexing=’ij’ |
|---|---|---|
| 2 (lengths M, N) | (N, M) | (M, N) |
| 3 (lengths M, N, P) | (N, M, P) | (M, N, P) |
Check on the example above: with x of length 3 and y of length 2, the default gives shape (2, 3), while np.meshgrid(x, y, indexing='ij') gives shape (3, 2), with the first output equal to [[0, 0], [0.5, 0.5], [1, 1]]. In 3-D with input lengths 2, 3, 4, I got shape (3, 2, 4) for ‘xy’ and (2, 3, 4) for ‘ij’.
sparse=True: same result, far less memory
With sparse=True, output i has shape (1, …, Ni, …, 1), so it relies on broadcasting. For the example above, xs has shape (1, 101) and ys has shape (101, 1), yet zs = np.sqrt(xs**2 + ys**2) has shape (101, 101) and np.array_equal(zz, zs) is True. On NumPy 2.5.1 the full xx array occupied 81,608 bytes against 808 bytes for sparse xs; the gap grows with grid size.
copy=False
The reference states that copy=False returns views to save memory; with sparse=False the result is likely non-contiguous and more than one element may refer to the same memory location. Copy the arrays before writing into them.
Troubleshooting
- Plot or table looks transposed. You mixed up ‘xy’ and ‘ij’. If your downstream code indexes
Z[i, j]with i over the first vector, useindexing='ij'; for code that expects x along columns, keep the default. - Shape mismatch when combining arrays. Check
.shapeof every grid. An ‘ij’ grid and an ‘xy’ grid built from the same inputs have swapped first two axes. - Unexpected memory use. Dense 3-D grids grow with the product of the input lengths. Use
sparse=Truewhen broadcasting is enough. - Warning when writing into a result. On NumPy 2.5.1, writing into a result built with
copy=False(withsparse=False) emitted a DeprecationWarning about overlapping memory when I tried it. Keepcopy=True(the default), or copy the arrays before writing, if you need to modify the grid.
Free alternatives and built-in options
| Option | What it does (NumPy 2.5 reference) |
|---|---|
sparse=True |
Returns broadcastable arrays of shape (1, …, Ni, …, 1); broadcasting still gives the full result. |
copy=False |
Returns views to save memory; copy before writing. |
indexing='ij' |
Matrix indexing instead of the Cartesian default. |
All three are part of NumPy itself, which is free and open source; this page does not compare other grid helpers.
FAQ
What does numpy.meshgrid return?
A tuple of coordinate arrays, one per input vector. With two inputs of lengths M and N and the default ‘xy’ indexing, each array has shape (N, M).
What is the difference between indexing=’xy’ and ‘ij’?
‘xy’ is Cartesian and puts the second input along the first axis; ‘ij’ is matrix indexing and keeps input order. For 2-D the shapes are (N, M) and (M, N).
Do I need meshgrid for plotting?
Only if your plotting function wants full 2-D coordinate arrays, as contour and surface plots do. See the Matplotlib contour guide.
Sources
- NumPy v2.5 manual, numpy.meshgrid, read 2026-11-07.
- NumPy, Installing NumPy, read 2026-11-07.
- Related on CASRAI: NumPy sum, pip install matplotlib.







