Weird bug when plotting step function

First I define two step functions:

julia> f(x)=floor(5x)-floor(2x)-floor(3x)
f (generic function with 1 method)
julia> g(x)=f(2x)-f(x)
g (generic function with 1 method)

and then I plot g:

julia> using Plots
julia> gr()
Plots.GRBackend()
julia> plot(g,0,1,ylim=(-1.2,1.2))

plot1

So far, so good. Because g is periodic with period 1, I try:

julia> plot(g,0,2,ylim=(-1.2,1.2))

plot2
The plotted graph is that of the zero function for x between 0 and 1, and is correct for x between 1 and 2 !!! To get the right graph, I must use something like

julia> plot(g,0:0.001:2,ylim=(-1.2,1.2))

plot3

Puzzling!

I don’t know how Plots chooses the sample points when you just give it endpoints, but all that’s happening is that its samples happen to miss all of the non-zero values in your function in [0, 1]. Try scatter() instead of plot() to see this:

Clearly the sample choice happened to miss the regions of interest for your particular function (inevitably there will be some clever function like yours for which their sample selection algorithm fails). Your solution of manually specifying the sample points seems like a good one.

1 Like

I wrote the algorithm for choosing sample points when given a function (without really knowing what I was doing, so I’m sure improvements are possible). However, I think there will always be some tricky functions where you can fool the algorithm that the function is constant on an interval. Explicitly specifying the points in those cases seems reasonable.

2 Likes

It’d be interesting to try this example in Mathematica, as Plots uses a very similar algorithm to select the x values on which to plot. The algorithm, from my understanding, goes more or less as follows:

  • Start with a few points
  • For each two consecutive points, estimate whether the function between those two points is approximately linear: if it isn’t, add points in the middle
  • Repeat

I can imagine that the algorithm started by sampling only points with value 0, got convinced that the linear approximation (constant equal to 0) was good and stopped there. Definitely worth opening an issue on the Plots repository (or PlotUtils, where the algorithm is implemented).

EDIT: I’ve just seen @kristoffer.carlsson 's reply and agree in principle but it is still good to see if this case can be fixed easily (maybe just starting the algorithm with more points)

What puzzles me about the sampling algorithm is that it fails for x between 0 and 1, and succeeds for x between 1 and 2, for a periodic function with period 1. The scatter plot of rdeits looks very significant.

I think you are just a bit unlucky with where the initial sample points happen to go. The algorithm should not be sensitive to the specific x values. It does a small amount of “wiggling” to try to avoid aliasing but if two neighboring initial samples have the same function value, then it will assume the function is constant there and not refine that interval. The only remedy would be to increase the number of sample points.

For example, if I slightly shift the interval:

12

By the way, giving a step function with narrow steps to an adaptive plotting algorithm is probably the most evil input :stuck_out_tongue:

4 Likes

Sorry, it wasn’t on purpose :slight_smile:

1 Like

If anyone is interested in improving the algorithm, taking into account explicit y-limits would be a nice improvement. Refining regions where the function values are outside the y-limits is useless.