Adaptive Sampling of Function Values for Plotting#
Situations to Handle#
Regions near singularities where the value changes sharply (e.g. singularities of the Gamma function).
Edges of the domain (e.g. the edges of
asin,acos).Regions of rapid oscillation (e.g. functions like
sin(1/x)).Regions with a jump discontinuity (e.g. the
floorfunction).
The basic approach is to sample at a fixed resolution in x first,
then insert additional points between samples as needed to satisfy the required accuracy.
Criteria for Adding a Point Between Two Samples#
The change in coordinates between two adjacent points is large.
A threshold is set on the change in the
ycoordinate.The threshold is a value relative to the range of
yshown in the plot.
The change across three consecutive points is large.
The slope between each pair of adjacent points is computed, and a threshold is set on the change in slope.
The threshold is specified relative to the plot area: the slope is computed as the ratio of the change in
yto the change inx, each normalized by the plot area.
A point inside the plot range is adjacent to a point that is
infornan.Without an inserted point, the line would be cut off instead of connecting to the edge of the plot.
Criteria for Not Adding a Point#
Both of two adjacent points are outside the plot range, or are
infornan.If only one of the two is inside the range, a point is still added (see above).
The
xdistance between two adjacent points is already too small.This prevents an infinite loop of repeatedly subdividing around a singularity.
This threshold is set relative to the range of
x.
A lower bound is set on this threshold to limit the number of recursions (roughly 1/1000 of the size of the domain).
Whether to connect the two points with a line when this threshold is reached needs further consideration:
When the change in
yis large, the function is likely piecewise, so the points should not be connected with a line (this is handled in the plotting step). However, this resulted in discontinuities of the line in many cases where the function is actually continuous, so not implemented for now.
The total number of points becomes too large.
Even after applying the criteria above, a maximum point count is set as a last resort to give up further subdivision.
A feature to warn the user when this limit is reached would be useful.
Constraints#
A spike within an extremely narrow range cannot be handled reliably.
Handling this in general would require prior knowledge of the function, so instead the number of initial samples is made tunable, leaving the trade-off to the user.
Requirements for the Algorithm#
Keep processing time low.
Repeatedly inserting points into the middle of a
vectorthat already holds many elements is slow. Therefore, the initial sampling is kept in a separatevectorfrom the finalvectorthat includes the inserted points, to reduce the amount of copying within avector.