Matplotlib draws a best-fit curve, but it does not estimate the curve’s parameters. Choose a function that represents the relationship you want to model, fit its parameters with a numerical method such as SciPy’s curve_fit, then plot the predictions alongside your measured data.
What “best fit” means here
A best-fit curve is the output of a model-fitting method, not a special Matplotlib setting. The model describes how you think y depends on x; the fitting method estimates parameter values from paired observations. With ordinary least squares, curve_fit minimizes squared residuals for the supplied function. Its assumptions and results depend on that chosen function, so there is no universally best curve for every dataset.
For a straight-line relationship, a linear regression method is usually the direct choice; SciPy’s curve_fit documentation points to scipy.stats.linregress for this case. For a custom nonlinear function, curve_fit provides a direct fitting API. See the SciPy curve_fit reference.
Fit and plot a nonlinear curve
This example fits an exponential-decay model with an offset. Replace the sample model and starting values with ones that make sense for your question and data.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# xdata and ydata are paired measured values.
xdata = np.asarray(xdata, dtype=float)
ydata = np.asarray(ydata, dtype=float)
if xdata.ndim != 1 or ydata.ndim != 1 or xdata.size != ydata.size:
raise ValueError("xdata and ydata must be aligned one-dimensional arrays")
if xdata.size == 0 or not np.isfinite(xdata).all() or not np.isfinite(ydata).all():
raise ValueError("xdata and ydata must be non-empty and finite")
def model(x, a, b, c):
return a * np.exp(-b * x) + c
# p0 supplies initial parameter estimates; choose them for your data.
popt, pcov = curve_fit(model, xdata, ydata, p0=(2.0, 1.0, 0.5))
# Evaluate the fitted model at many ordered x positions for a smooth line.
xfit = np.linspace(xdata.min(), xdata.max(), 300)
yfit = model(xfit, *popt)
fig, ax = plt.subplots()
ax.scatter(xdata, ydata, label="Observed data")
ax.plot(xfit, yfit, color="tab:red", label="Nonlinear least-squares fit")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
plt.show()
print("Fitted parameters:", popt)
The function signature matters: the independent variable comes first, followed by the parameters to estimate. curve_fit returns popt, the estimated parameter values, and pcov, an approximate covariance matrix. This follows SciPy’s description: “Use non-linear least squares to fit a function, f, to data.” The API details are in the official curve_fit documentation.
The plotted line is generated by evaluating the fitted function on a dense set of x coordinates; it is not a line through every observation. Matplotlib’s plot draws y versus x as lines and/or markers, and scatter is suited to displaying the paired observations. See the Matplotlib plot reference and scatter reference.
Rank #2
Choose a model and fitting method that suit the data
Linear or nonlinear model
Use a linear model when a straight-line relationship is a defensible description of the data. Use a nonlinear function when the underlying relationship calls for one, such as the exponential example above. A more complicated curve is not automatically better: parameters that the observations cannot distinguish may lead to unstable estimates.
Starting values and parameter bounds
For difficult nonlinear fits, provide plausible initial estimates with p0. Starting values can affect whether the optimizer finds a useful solution. Supply bounds only when the parameter limits are justified by the problem—for example, known physical constraints—not simply to force the curve to look appealing. The SciPy API reference documents these options.
Free tools Windows power users keep installed
One-click scans. No signup required.
Ordinary least squares or robust loss
Ordinary least squares squares residuals, so large residuals can have substantial influence. If outliers are a meaningful concern, SciPy’s least_squares optimization API includes robust losses such as soft_l1 and cauchy. That is a different fitting route from a basic curve_fit call; choose it when the loss function matches the problem rather than assuming ordinary least squares is outlier-resistant. See the SciPy least_squares reference.
Unweighted or uncertainty-weighted fitting
If you know the measurement uncertainty in y, curve_fit accepts it through sigma: a one-dimensional array of standard deviations or a two-dimensional covariance matrix. With the default absolute_sigma=False, SciPy scales the returned parameter covariance according to the residual variance. Set absolute_sigma=True when the supplied uncertainty values should be treated as absolute. The meaning of pcov depends on this choice and the fit assumptions; it is not a guaranteed confidence interval. SciPy notes that the covariance estimate uses a linear approximation near the optimum. Details are in the curve_fit reference.
Check whether the fit is trustworthy
A smooth-looking line alone does not show that a model is appropriate. Inspect how the model’s predictions differ from observed values, and check whether the function makes sense for the data-generating question. A fitted regression curve generally estimates a trend rather than passing through every observation; that distinguishes regression from interpolation.
- Look for redundant parameters or a model that is too complex for the available data.
- Watch for poorly scaled parameters, a singular Jacobian, or a covariance matrix with a large condition number; these can make parameter estimates and uncertainty summaries unreliable.
- If estimates are unstable, reconsider the model and parameterization, use appropriate parameter scaling, or simplify parameters that cannot be identified from the data.
- Do not rely on an unqualified R-squared value as the sole test of a fit. Consider residual behavior and whether the fitted relationship is plausible.
These numerical limitations and the covariance caveats are documented in SciPy’s curve_fit reference.
Best Value
Use Matplotlib’s plotting interface
The example uses Matplotlib’s object-oriented Axes methods after creating a figure with plt.subplots(). This keeps the observations, fitted line, labels, and legend attached to a specific axes. The pyplot interface is convenient for simple interactive plotting; Matplotlib recommends the object-oriented Figure/Axes approach for more complex plots. See the Matplotlib API interfaces guide.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




