2026, Jan 12 15:00
Plotting Functions with Singularities in SymPy: prevent spikes with detect_poles and y-limits
Learn why SymPy plots flatten near poles and fix them with SymPy Plotting Backends: set y-limits, enable detect_poles, and visualize discontinuities correctly.
Plotting expressions with singularities often leads to surprising results. A common case is a rational-trigonometric function that blows up at specific points, and a default plot turns into a near-flat line punctuated by spikes. Below is a practical walkthrough of why that happens in SymPy and how to obtain a correct visualization using SymPy Plotting Backends.
Problem statement
Consider the function 4*sin(2*x)/cos(2*x)^3. A straightforward attempt to plot it with SymPy’s built-in plotting produces an almost horizontal graph with occasional vertical streaks instead of the expected tangent-like shape.
from sympy import symbols, sin, cos
from sympy.plotting import plot as splot
u = symbols('u')
f = 4 * sin(2 * u) / cos(2 * u)**3
splot(f)What is going on
The expression diverges wherever cos(2x) equals zero, so it has poles at x = (n + 1/2)*pi/2. Near these points the function shoots to infinity. The default plotting routine performs autoranging on the y-axis. When extreme values dominate, the vertical scale expands to fit them, compressing everything else into a thin band. The result is a flat-looking curve with one or more large spikes, and the exact height of those spikes depends on grid sampling and numerical rounding. In short, poles plus autoranging produce misleading visuals if the plotter doesn’t explicitly account for discontinuities.
Solution with SymPy Plotting Backends
SymPy’s standard plotting module doesn’t handle poles particularly well. The SymPy Plotting Backends package addresses this with dedicated pole handling and sensible y-limits. The key is to explicitly detect singularities and bound the y-axis so the regular parts of the curve remain visible.
from sympy import symbols, sin, cos, pi
from spb import plot as pplot
v = symbols('v')
g = 4 * sin(2 * v) / cos(2 * v)**3
pplot(g, (v, -2 * pi, 2 * pi), detect_poles=True, ylim=(-3, 3))There are two critical details here. First, detect_poles=True runs an algorithm that identifies singularities and avoids drawing spurious vertical lines across them. Second, setting ylim keeps the y-axis within a sensible range; without it, the plot will again be dominated by extreme values and appear flattened elsewhere.
If you plan to adopt this workflow, the package and examples are available in the documentation: SymPy Plotting Backends. Installation instructions are provided on the installation page, and there are dedicated examples about discontinuities in the tutorial.
How pole detection works and why it’s not on by default
Pole handling is opt-in because different strategies have trade-offs. With detect_poles=False, no detection is attempted, which is why you see vertical stripes and a nearly flat baseline in challenging cases. With detect_poles=True, the backend runs a gradient-based algorithm on the sampled data. If the change between adjacent points along the x-axis exceeds a threshold, it inserts a NaN between them so the renderer breaks the line across the suspected singularity. This is effective, but very steep, finite slopes can mimic the signature of a pole, so false positives are possible. You can mitigate this by adjusting parameters such as the number of discretization points (n is 1000 by default).
There is also detect_poles="symbolic", which augments the numeric strategy with a symbolic analysis based on SymPy’s solve. Depending on the expression, solve might fail to find all singularities or take a long time. When it succeeds, the output also shows vertical dotted lines at the x-locations where singularities are detected. Because each approach has limitations, the backend keeps detect_poles disabled by default and lets you explicitly choose the strategy that fits your function.
Why this matters
Plots are often used as sanity checks in symbolic and numeric workflows. Misleading visuals created by autoranging and undetected poles can push you toward the wrong intuition about growth, symmetry, or periodicity. By detecting singularities and bounding the y-axis, you avoid artefacts like false vertical connectors and the “flat line with spikes” effect, getting a graph that reflects the actual behavior of the expression.
Takeaways
When dealing with functions that diverge, expect autoranging to hide important structure. Set an explicit x-domain, constrain the y-limits to a meaningful window, and enable pole detection in the plotting backend. If you still see suspicious breaks where there should be none, consider increasing the number of sample points, or switch to the symbolic detection mode when appropriate. With these adjustments, 4*sin(2*x)/cos(2*x)^3 looks like the horizontally compressed tangent-like curve you intended to inspect.