How to Use Linspace in NumPy
NumPy's `linspace` function creates arrays of evenly spaced numbers over a specified interval. The name comes from 'linear spacing'—you define the start, end, and how many points you want, and NumPy...
Key Insights
np.linspace()generates evenly spaced numbers when you need a specific count of points, whilenp.arange()is better when you need a specific step size- The
retstep=Trueparameter returns the calculated step size alongside your array, which is invaluable for numerical computations and debugging - Setting
endpoint=Falseexcludes the stop value, which is essential for periodic functions and avoiding duplicate points when concatenating arrays
Introduction to np.linspace()
NumPy’s linspace function creates arrays of evenly spaced numbers over a specified interval. The name comes from “linear spacing”—you define the start, end, and how many points you want, and NumPy calculates the exact spacing needed.
This function appears constantly in scientific computing, data visualization, and numerical analysis. When you need to plot a smooth curve, set up integration points, or create test data with predictable spacing, linspace is your tool. It eliminates the mental math of calculating step sizes and avoids the floating-point precision issues that plague alternative approaches.
Basic Syntax and Parameters
Here’s the complete function signature:
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
Let’s break down each parameter:
- start: The starting value of the sequence
- stop: The end value of the sequence (included by default)
- num: Number of samples to generate (default: 50)
- endpoint: If
True, stop is the last sample; ifFalse, it’s excluded (default:True) - retstep: If
True, return the step size between samples (default:False) - dtype: The data type of the output array (default: inferred from inputs)
- axis: The axis along which to store samples (relevant for array-like start/stop values)
The most common usage involves just the first three parameters:
import numpy as np
# Generate 5 evenly spaced numbers from 0 to 10
arr = np.linspace(0, 10, 5)
print(arr)
# Output: [ 0. 2.5 5. 7.5 10. ]
Notice that both endpoints are included, and NumPy calculated the step size (2.5) automatically.
Core Usage Examples
Let’s explore the fundamental patterns you’ll use daily.
Simple Ranges
import numpy as np
# 5 points from 0 to 10
basic = np.linspace(0, 10, 5)
print(f"Basic: {basic}")
# Basic: [ 0. 2.5 5. 7.5 10. ]
# 11 points gives nice integer spacing
integers = np.linspace(0, 10, 11)
print(f"Integers: {integers}")
# Integers: [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
# Default num=50 gives dense sampling
dense = np.linspace(0, 1)
print(f"Dense (first 5): {dense[:5]}")
print(f"Length: {len(dense)}")
# Dense (first 5): [0. 0.02040816 0.04081633 0.06122449 0.08163265]
# Length: 50
Negative Ranges
linspace handles negative numbers and reversed ranges without any special syntax:
import numpy as np
# Negative to positive
crossing_zero = np.linspace(-5, 5, 11)
print(f"Crossing zero: {crossing_zero}")
# Crossing zero: [-5. -4. -3. -2. -1. 0. 1. 2. 3. 4. 5.]
# Entirely negative
negative = np.linspace(-10, -1, 5)
print(f"Negative: {negative}")
# Negative: [-10. -7.75 -5.5 -3.25 -1. ]
# Descending order (start > stop)
descending = np.linspace(10, 0, 6)
print(f"Descending: {descending}")
# Descending: [10. 8. 6. 4. 2. 0.]
Excluding the Endpoint
Setting endpoint=False excludes the stop value. This is crucial for periodic functions and when you’re creating segments that will be concatenated:
import numpy as np
# With endpoint (default)
with_end = np.linspace(0, 1, 5, endpoint=True)
print(f"With endpoint: {with_end}")
# With endpoint: [0. 0.25 0.5 0.75 1. ]
# Without endpoint
without_end = np.linspace(0, 1, 5, endpoint=False)
print(f"Without endpoint: {without_end}")
# Without endpoint: [0. 0.2 0.4 0.6 0.8]
# Useful for periodic functions - one complete cycle without repeating 0
theta = np.linspace(0, 2 * np.pi, 8, endpoint=False)
print(f"Angles (radians): {theta}")
# Angles (radians): [0. 0.78539816 1.57079633 2.35619449
# 3.14159265 3.92699082 4.71238898 5.49778714]
The retstep Parameter
When retstep=True, linspace returns a tuple containing both the array and the calculated step size. This is invaluable for numerical methods where you need the spacing for calculations:
import numpy as np
# Get the array and step size together
arr, step = np.linspace(0, 10, 5, retstep=True)
print(f"Array: {arr}")
print(f"Step size: {step}")
# Array: [ 0. 2.5 5. 7.5 10. ]
# Step size: 2.5
# Practical use: numerical differentiation
def numerical_derivative(func, x_start, x_end, num_points):
"""Compute derivative using central differences."""
x, h = np.linspace(x_start, x_end, num_points, retstep=True)
y = func(x)
# Central difference (excluding endpoints)
dy_dx = (y[2:] - y[:-2]) / (2 * h)
x_mid = x[1:-1]
return x_mid, dy_dx
# Derivative of x^2 should be 2x
x, derivative = numerical_derivative(lambda x: x**2, 0, 5, 101)
print(f"At x=2.5, derivative = {derivative[len(derivative)//2]:.4f} (expected: 5.0)")
# At x=2.5, derivative = 5.0000 (expected: 5.0)
The step value is also useful for debugging—you can verify that your spacing is what you expected.
Practical Applications
Plotting Smooth Curves
The most common use case is generating x-values for plotting:
import numpy as np
import matplotlib.pyplot as plt
# Generate smooth x-values for plotting
x = np.linspace(0, 4 * np.pi, 200)
y_sin = np.sin(x)
y_cos = np.cos(x)
plt.figure(figsize=(10, 4))
plt.plot(x, y_sin, label='sin(x)')
plt.plot(x, y_cos, label='cos(x)')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.title('Trigonometric Functions')
plt.savefig('trig_functions.png', dpi=150)
Using 200 points ensures a smooth curve. Too few points create jagged lines; too many waste memory without visual improvement.
Numerical Integration (Trapezoidal Rule)
import numpy as np
def trapezoidal_integral(func, a, b, n):
"""Integrate func from a to b using n trapezoids."""
x, h = np.linspace(a, b, n + 1, retstep=True)
y = func(x)
# Trapezoidal rule: h/2 * (y0 + 2*y1 + 2*y2 + ... + 2*yn-1 + yn)
integral = h * (0.5 * y[0] + np.sum(y[1:-1]) + 0.5 * y[-1])
return integral
# Integrate sin(x) from 0 to pi (exact answer: 2.0)
result = trapezoidal_integral(np.sin, 0, np.pi, 100)
print(f"Integral of sin(x) from 0 to π: {result:.6f}")
print(f"Error: {abs(result - 2.0):.2e}")
# Integral of sin(x) from 0 to π: 1.999836
# Error: 1.64e-04
Creating Interpolation Points
import numpy as np
# Original sparse data
x_original = np.array([0, 1, 2, 3, 4])
y_original = np.array([0, 1, 4, 9, 16]) # y = x^2
# Create dense interpolation points
x_interp = np.linspace(0, 4, 50)
y_interp = np.interp(x_interp, x_original, y_original)
print(f"Interpolated value at x=2.5: {y_interp[np.argmin(np.abs(x_interp - 2.5))]:.2f}")
# Interpolated value at x=2.5: 6.50
linspace vs. arange
Both functions create sequences, but they solve different problems:
- Use
linspacewhen you know how many points you need - Use
arangewhen you know the step size you need
import numpy as np
# linspace: "I need exactly 5 points between 0 and 1"
ls = np.linspace(0, 1, 5)
print(f"linspace: {ls}")
# linspace: [0. 0.25 0.5 0.75 1. ]
# arange: "I need points spaced 0.25 apart"
ar = np.arange(0, 1.1, 0.25) # Note: need 1.1 to include 1.0
print(f"arange: {ar}")
# arange: [0. 0.25 0.5 0.75 1. ]
The critical difference emerges with floating-point step sizes:
import numpy as np
# Floating-point precision problem with arange
ar = np.arange(0, 1, 0.1)
print(f"arange length: {len(ar)}")
print(f"arange: {ar}")
# arange length: 10
# arange: [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
# Sometimes arange gives unexpected results
ar_problem = np.arange(0, 0.6, 0.1)
print(f"Expected 6 elements, got: {len(ar_problem)}")
print(f"Values: {ar_problem}")
# Expected 6 elements, got: 6
# Values: [0. 0.1 0.2 0.3 0.4 0.5]
# linspace is predictable
ls = np.linspace(0, 0.5, 6)
print(f"linspace: {ls}")
# linspace: [0. 0.1 0.2 0.3 0.4 0.5]
With arange, floating-point accumulation can cause the endpoint to be included or excluded unpredictably. linspace always gives you exactly the number of points you request.
Conclusion
np.linspace() is the right choice when you need a specific number of evenly spaced points. Remember these guidelines:
- Default to
linspacefor plotting—specify point count, not step size - Use
retstep=Truewhen you need the step size for calculations - Set
endpoint=Falsefor periodic functions or when concatenating arrays - Choose
arangeonly when you genuinely need a specific step size with integer or well-behaved float values
The function’s predictability makes it superior to arange for most scientific computing tasks. When you specify 100 points, you get exactly 100 points—no floating-point surprises.