The usual advice for data visualization is to export the chart and move on. That is how you end up with SVG bloat. I have opened dashboards where one “smooth” chart was really 250+ tiny line segments, and the browser has to parse and render every one of those coordinate points. On mobile it drags. Orthogonal Distance Fitting (ODF) is what you want if you would rather not ship path data like that.
Matplotlib is fine for research, but it approximates every curve with piecewise linear segments. That is the safe default and also the expensive one. For a dashboard that has to stay quick, Orthogonal Distance Fitting collapses those hundreds of segments into a handful of cubic Bézier curves, and the plot still looks the same.
The math behind slimmer paths
Calling it smoothing undersells what happens. It is an optimization problem: fit a Bézier curve that minimizes orthogonal distance, which is the shortest distance from any point on the target function to the curve itself. For more on frontend assets, I covered Modern CSS and SVG Favicons separately.
The algorithm runs roughly like this:
- Fit a Chebyshev series to the function first. It converges geometrically fast, so you get there with fewer terms than a cubic spline needs.
- Adjust the Bézier control points with a trust-region optimizer rather than plain gradient descent, which tends to stall at saddle points.
- If the maximum distance between the curve and the function is still over your threshold, split the domain and run it again.
Implementing orthogonal distance fitting in Python
Most of my WordPress work sits on the frontend, but when the data gets crunched on the backend, say in a small Python service, the bbai library handles this part. Here is a raw Gaussian function turned into a compact path.
from bbai.graphics import BezierPath
import numpy as np
def f(t):
return np.exp(-t * t)
# Define our destination window
path = BezierPath(dst_xmin=0, dst_xmax=10, dst_ymin=0, dst_ymax=2)
# Apply Orthogonal Distance Fitting to fit the curve
path.fit(f, -2, 2)
# Output the compact TikZ/MetaPost code
print(path.tikz_)
That prints something like this, instead of the 200+ line segments you would otherwise get:
\draw (0.000, 0.000)..controls (2.684, 0.092) and (3.273, 1.952)
.. (4.750, 2.000)..controls (6.229, 1.951) and (6.815, 0.092)
.. (9.500, 0.000);
Two segments. Scale that across a page full of hypotrochoids or roses and the file size difference stops being academic. If the Python side still feels slow afterwards, Py-Spy profiling will tell you where the time actually goes.
From TikZ to clean SVG
MetaPost turns the optimized path into the final SVG. You do not need the LuaLaTeX and DVI conversion route that most people reach for first, because MetaPost writes SVG directly through mpost, which ships with any standard TeX Live install. The MetaPost User Manual has the details, and there is also the TikZ documentation.
If this sort of thing is eating your dev hours, hand it over. I have been working with WordPress since the 4.x days, and a good part of that time goes on keeping assets from choking the server they sit on.
The short version
Bloated vector graphics are not a fixed cost of doing business. Orthogonal Distance Fitting keeps the mathematical precision and still hands you a small file, which the browser parses faster and older phones notice. On a data-heavy dashboard I would treat it as part of the build rather than an optimization you get around to later.