New to Rust? Grab our free Rust for Beginners eBook Get it free →
np.linspace in Python: Syntax, parameters and examples

np.linspace is a function from NumPy, one of Python’s core data science libraries, that builds an array of evenly spaced numbers between a start and stop value. Instead of picking a step size, you tell it how many points you want and it works out the spacing for you. Devs reach for it constantly when they need a clean set of x-values for a plot or a fixed number of samples for a simulation.
Syntax and parameters of np.linspace
Here’s the current signature straight from NumPy’s source:
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0, *, device=None)
Parameters:
- start: the first value of the sequence (array_like, so it can be a scalar or a list)
- stop: the last value of the sequence, included by default unless endpoint is False
- num: how many samples to generate, defaults to 50 and must be non-negative
- endpoint: if True (default), stop is the last value in the array. If False, stop is left out
- retstep: if True, the function returns a tuple of (array, step size) instead of just the array
- dtype: the data type of the output array. If left as None, NumPy infers it from start and stop
- axis: which axis to place the samples along when start or stop are array-like, default is 0
- device: the array API device to place the result on, added in NumPy 2.0 and only relevant if you’re writing array-API-portable code
The function returns an ndarray (a numpy tool for storing and doing math on grids of numbers) containing num evenly spaced values. If retstep is True, it returns the step size alongside the array.
Basic usage of np.linspace
The simplest call only needs a start and a stop value. NumPy fills in num=50 by default, so you get 50 evenly spaced points between the two numbers you gave it.
import numpy as np
result = np.linspace(1, 10)
print(result.shape)
# Output: (50,)
That default of 50 points is easy to forget and it can quietly bloat your output if you only wanted a handful of values. In practice you almost always want to set num explicitly.
import numpy as np
result = np.linspace(1, 10, num=5)
print(result)
# Output: [1. 3.25 5.5 7.75 10. ]
Here NumPy split the range from 1 to 10 into 5 equal steps, including both endpoints. This is the pattern you’ll use for the vast majority of np.linspace calls.
Controlling the stop value with endpoint
By default np.linspace treats stop as inclusive, so it shows up as the final entry in the array. Set endpoint to False and NumPy excludes it, spacing the remaining values as if stop were one step further along.
import numpy as np
with_stop = np.linspace(0, 10, num=5)
without_stop = np.linspace(0, 10, num=5, endpoint=False)
print(with_stop)
# Output: [ 0. 2.5 5. 7.5 10. ]
print(without_stop)
# Output: [0. 2. 4. 6. 8.]
Notice the spacing itself changes, not just the last value. With endpoint=False, NumPy divides the range into num equal segments instead of num-1, so every value shifts down to make room for the excluded endpoint. This comes up when you’re tiling values around a circle or a periodic function, where you don’t want the first and last point to overlap.
Getting the step size with retstep
Sometimes you need to know the actual spacing between values, not just the array itself. Pass retstep=True and np.linspace returns a tuple instead of a plain array.
import numpy as np
values, step = np.linspace(0, 20, num=5, retstep=True)
print(values)
# Output: [ 0. 5. 10. 15. 20.]
print(step)
# Output: 5.0
This saves you from manually computing (stop – start) / (num – 1) yourself, which matters when you’re feeding that step size into another calculation, like a finite-difference approximation or a loop that needs to know how far apart your grid points sit.
Setting the output type with dtype
By default np.linspace infers a float type from your start and stop values, even if both are whole numbers. If you need integers, dates or another type, pass it explicitly through dtype.
import numpy as np
int_array = np.linspace(0, 100, num=5, dtype=int)
print(int_array)
# Output: [ 0 25 50 75 100]
One thing worth knowing if you’re on an older NumPy install: since version 1.20, integer dtype values are rounded toward negative infinity instead of toward zero. If you’re comparing output against an old tutorial or Stack Overflow answer written before that change, values close to a rounding boundary might not match. Casting after generation with array.astype(np.int_) reproduces the older rounding behavior if you need it for compatibility.
Generating multi-dimensional arrays
np.linspace works beyond flat 1D output too. If you pass array-like values for start and stop, or reshape the result, you can build 2D grids directly.
Passing array-like start and stop values
import numpy as np
grid = np.linspace([0, 10], [5, 15], num=4)
print(grid)
# Output:
# [[ 0. 10. ]
# [ 1.66666667 11.66666667]
# [ 3.33333333 13.33333333]
# [ 5. 15. ]]
Here NumPy interpolates between the pair [0, 10] and the pair [5, 15], producing one row per step. Use the axis parameter to control whether those steps line up as rows or columns.
import numpy as np
grid = np.linspace([0, 10], [5, 15], num=4, axis=1)
print(grid)
# Output:
# [[ 0. 1.66666667 3.33333333 5. ]
# [10. 11.66666667 13.33333333 15. ]]
Reshaping a flat array into a grid
The more common approach for a simple grid is to generate a flat 1D array and reshape it (see NumPy reshape for the full breakdown of how reshaping works in NumPy).
import numpy as np
flat = np.linspace(0, 1, num=16)
grid = flat.reshape(4, 4)
print(grid)
# Output:
# [[0. 0.06666667 0.13333333 0.2 ]
# [0.26666667 0.33333333 0.4 0.46666667]
# [0.53333333 0.6 0.66666667 0.73333333]
# [0.8 0.86666667 0.93333333 1. ]]
Using negative values with np.linspace
Negative numbers work exactly the way you’d expect, since np.linspace only cares about the distance between start and stop, not their sign.
import numpy as np
result = np.linspace(-10, 10, num=5)
print(result)
# Output: [-10. -5. 0. 5. 10.]
This is useful for building symmetric ranges centered on zero, which come up a lot when you’re plotting functions like sine or a normal distribution curve.
np.linspace vs np.arange
np.linspace and NumPy arange both build sequences of numbers but they start from different questions. arange asks “what step size do I want” and linspace asks “how many points do I want.” That single difference explains most of the practical gap between them.
- arange excludes the stop value by default and takes a step argument. It’s the better fit when you know the spacing you need, like every 5th integer.
- linspace includes the stop value by default and takes a count argument. It’s the better fit when you know exactly how many points you want, regardless of what the resulting spacing works out to.
- Floating-point step sizes in arange can drift due to rounding, so if precision at the boundaries matters, linspace is the safer choice.
import numpy as np
arange_result = np.arange(0, 10, 2)
linspace_result = np.linspace(0, 10, 2)
print(arange_result)
# Output: [0 2 4 6 8]
print(linspace_result)
# Output: [ 0. 10.]
Notice arange_result excludes 10 while linspace_result treats 10 as the second of exactly 2 points. Mixing them up is a common source of off-by-one bugs, especially when porting code between the two.
Where np.linspace shows up in practice
np.linspace shows up constantly outside of toy examples, mostly because so many numerical and visual tasks need a fixed number of evenly spaced inputs.
Plotting smooth curves
When you’re plotting a mathematical function, you need enough x-values that the resulting curve looks smooth rather than jagged. np.linspace is the standard way to generate those x-values (see plotting smooth curves in Matplotlib for a deeper walkthrough of this exact pattern).
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, num=200)
y = np.sin(x)
plt.plot(x, y)
plt.show()
Using 200 points here keeps the sine wave looking continuous. Drop that down to 10 or 15 and the same curve starts to look like a jagged polygon instead of a smooth wave, which is a quick way to see why the count matters.
Feeding simulations and models
Financial and scientific simulations often need to test a variable across a full range rather than at one fixed value. If you wanted to see how bond prices respond to different interest rates, np.linspace gives you an evenly spaced set of rates to test.
import numpy as np
interest_rates = np.linspace(0.01, 0.08, num=8)
print(interest_rates)
# Output: [0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08]
Building axis ticks and color scales
Charts with a large number of data points sometimes need evenly spaced tick positions or color values rather than relying on whatever the plotting library picks by default. np.linspace generates those positions directly, which keeps the labeling consistent whether you’re building a scatterplot with multiple datasets or a full 3D plot in Matplotlib.
Common issues when using np.linspace
A few mistakes come up often enough that they’re worth flagging before you hit them.
Passing a negative num: NumPy requires num to be zero or positive. A negative value raises a ValueError, so if you’re computing num dynamically, guard against a calculation that could go negative.
Forgetting the default num=50: If you call np.linspace(0, 1) without a num argument, you get 50 points, not a small handful. This is the most common surprise for people coming from np.arange, where the array length depends entirely on the step size you provide.
Confusing endpoint’s effect on spacing: As shown above, endpoint=False doesn’t just drop the last value, it changes the spacing of every value before it. Assuming otherwise is an easy way to introduce a subtle numerical bug in anything downstream of the array.
Alternatives to np.linspace
np.linspace isn’t the only way to build a sequence and depending on what you need, one of these might fit better.
- NumPy arange: better when you know the step size rather than the number of points.
- np.logspace and np.geomspace: generate values spaced evenly on a logarithmic scale instead of a linear one, useful for frequency sweeps or anything spanning several orders of magnitude.
- List comprehensions: fine for small, simple integer ranges, but they don’t give you NumPy’s vectorized operations or performance on larger arrays.
- NumPy where: not a generator itself, but useful right after linspace when you need to filter or replace values in the array based on a condition.
Key takeaways
- np.linspace generates num evenly spaced values between start and stop
- The default num is 50 if you don’t set it explicitly
- stop is included by default, set endpoint=False to exclude it
- retstep=True returns the step size alongside the array
- dtype controls the output type, with integer rounding changed since NumPy 1.20
- axis controls the layout when start and stop are array-like
- linspace picks the count, arange picks the step size
- Reshape a flat linspace array to build 2D or 3D grids
Frequently asked questions
What is the difference between np.linspace and np.arange?
np.linspace takes the number of points you want and calculates the spacing, while np.arange takes a step size and calculates however many points fit inside the range.
Does np.linspace include the stop value?
Yes, by default. Set endpoint=False if you want the sequence to stop just short of that value instead, which also shifts the spacing of every other value in the array.
How do I get the step size from np.linspace?
Pass retstep=True. The function then returns a tuple containing the array and the float step size between consecutive values, saving you a manual calculation.
Can np.linspace generate a 2D array?
Yes, either by passing array-like start and stop values with the axis parameter, or by generating a flat array and calling reshape on it.
Why did I get 50 values when I only passed start and stop?
num defaults to 50 whenever it isn’t specified, regardless of how far apart your start and stop values are. Pass num explicitly any time you want a different count.
Can np.linspace use negative numbers?
Yes, start and stop can both be negative or span across zero, and the spacing works the same way regardless of sign.
Is np.linspace faster than a Python list comprehension?
For anything beyond a small handful of values, yes. np.linspace runs as a vectorized NumPy operation, while a list comprehension loops in plain Python and returns a plain list.




