# Plotting discontinuous functions without spurious vertical segments

Consider the plot of this discontinuous function:

f[x_] := If[2 < x < 3, 0, x]
Plot[f[x], {x, 0, 5}]


I'd like to plot that without the vertical segments. Modifying the function f is not allowed.

ADDED: I should've said more about the restriction on modifying f. In the real application where this came up, f is a messy thing that should be treated as a black box. So we can't pick out the discontinuity, and probably can't invert the function either.

-

## migrated from stackoverflow.comSep 12 '12 at 11:33

This question came from our site for professional and enthusiast programmers.

These are amazing answers; thanks so much everyone! –  dreeves Dec 8 '10 at 6:54
see here for Mathematica Q&A: Excluding Points from Plots (from Wolfram) –  TomD Mar 15 '11 at 10:28

I looked for a way without redefining the function and not using explicit knowledge about it (so it can be generalized)

pl[f_, lims_] := Module[{eps = 0.05},
Off[InverseFunction::"ifun"];
Print@Plot[f[u], {u, lims[[1]], lims[[2]]},
Exclusions ->
{{f[u] == f[InverseFunction[f][u]], Abs[(f[u] - f[u + eps])] > 10 eps},
{f[u] == f[InverseFunction[f][u]], Abs[(f[u] - f[u - eps])] > 10 eps}}]
On[InverseFunction::"ifun"];
];

(* Testing *)

f[x_] := If[2 < x < 3, 0, x];
pl[f, {0, 5}];
pl[Tan, {0, 2 Pi}]


Edit

Ok, this one does not use InverseFunction, and identifies discontinuities, as far as I tested it:

(*Function Definition*)
pl[f_, lims_]:= Plot[f[u],{u, lims[[1]], lims[[2]]},Exclusions->{True, f[u] == 1}];

(*--------Test--------*)
flist = {
If[Abs@Sin@# > .5, 1, 0] &,
If[2 < # < 3, 0, #] &,
1/Sin@# + 1 &,
Tan};
pk = Table[{Plot[fun[x], {x, 0, 10}], pl[fun, {0, 10}]}, {fun, flist}];
GraphicsGrid[pk]


Here are side by side the results from Plot (without Options) and from this function:

Edit 2

Found a counterexample, and perhaps some comprehension about what is going on there.

   f = If[Abs@Sin@# > .5, 2, 5] &


Does not work. Why? It's easy ... the discontinuity does not cross f[u]==1 ...

Doing a Reap-Sow on the Plot (as in @rcollyer's answer) I saw that adding the Exclusions with f[u]==1 adds a few points to the trace just around f[u]==1 and seems that that is the trigger for excluding the discontinuities from the domain.

Now trying to find a way to change the f[u]==1 for something that works better ...

Edit 3

Found a way with a discrete derivative, a tricky thing.

Like this:

(*Function Definition*)
pl[f_, lims_]  :=  Plot[f[u], {u, lims[[1]], lims[[2]]},
Exclusions -> {(f[u] - f[u + .1])/.1 == 10,
(f[u] - f[u + .1])/.1 == -10}];


Note two issues:

1. I had to remove the "True" or "Automatic" option from the Exlusions
2. Taking Abs[] for joining the two Exclusion equalities does not work since it's monitoring the evolution of the lhs ...
-
Okay, simple question: why does the addition of f[u]==1 help? Exclusions -> True, alone, does not work, so why does the addition of the function work? I'm honestly confused. BTW: +1, simple and clever. –  rcollyer Dec 8 '10 at 12:28
Wow, this seems like a definitive improvement to Plot itself. My only reservation about it is what happens when the function is not invertible... –  dreeves Dec 8 '10 at 15:37
@dreeves I am not using InverseFunction anymore. And trig functions are not invertible ... I am still trying to find a counterexample where this doesn't work, since I am not blind-confident about the method. –  belisarius Dec 8 '10 at 20:10
@rcollyer I was experimenting a lot. I really do not understand why this work, but I am still not able to find a counter-example. –  belisarius Dec 8 '10 at 20:12
@belisarius, per edit 2, changed the exclusion to f[u]==u and it only excluded the second and third discontinuity. So, you're definitely on to something. My thinking is that you'll need to know a little about the domain/range of your function in order to properly set up the exclusions, i.e. plot it without the exclusions first. –  rcollyer Dec 9 '10 at 4:36

The answer is Exclusions as follows:

In this case, your excluding the points where there are discontinuities. It will also accept functional definitions.

Edit: Since you state you can't pick out the exclusions, I assume you mean that unlike the example you gave the exclusions are not known a priori. And, assuming that InverseFunction does not work for you, as per belisarius's solution, then you will have to generate them "by hand". The best bet would be to use EvaluationMonitor to acquire the points Plot uses, like in the example

data = Reap[Plot[Sin[x], {x, 0, 2 Pi}, EvaluationMonitor :> Sow[{x, Sin[x]}]] ][[-1, 1]]


and compare the numerical derivatives on both sides of each point

der = (Subtract@@#[[All,2]])/(Subtract@@#[[All,1]])
Select[Partition[data, 3, 1], Abs[ der@#[[{1,2}]] - der@#[[{2,3}]] ] > tol& ]


where the difference exceeds some tolerance. You'll need to then pull out the offending point, but it should be the only one that exists in 3 consecutive sublists. This then gives you your exclusions.

Edit, part 2: In the continuing jockeying for the "correct" solution to this, I found in the Applications section of the Plot documentation a method that is effective for all of the inital tests used by @belisarius: Exclusions -> {1/f[x] == 0}, and Exclusions -> {1/D[f,x] == 0} works for my pathological example of Sin[1/x^2]. Unfortunately, both still fail for If[Abs@Sin@# > .5, 2, 5]&. Additionally, the use of the derivative fails for all of the initial tests and spuriously removes pieces when combined with 1/f[x]==0.

-
Here is another nice way to find the discontinuities forums.wolfram.com/mathgroup/archive/2009/Aug/msg00387.html. The first function def lacks the "==" sign before the "z" –  belisarius Dec 8 '10 at 6:40
It should be noted that Select is calculating something close to the second derivative (en.wikipedia.org/wiki/…), and it may be simpler to think of it in those terms. –  rcollyer Dec 8 '10 at 12:23

As pointed out by Wolfram, the following will also work. Not as powerful as Exclusions or Piecewise, of course:

f[x_] := If[2 < x < 3, 0, x]
Plot[f[x], {x, 0, 2, 3, 5}]

-
+1 One of those features I usually forget about ... –  belisarius Dec 9 '10 at 18:35
+1 I cannot recall seeing this before. –  Mr.Wizard Mar 4 '11 at 9:37
Checking back,I found out about this in the following Mathmergency video. Not, as I thought, a Wolfram presentation. –  TomD Mar 4 '11 at 16:40

This works:

f[x_] := Piecewise[{{x, x < 2}, {0, x < 3}, {x, x > 3}}]
Plot[f[x], {x, 0, 5}]


and you also have the advantage that Piecewise is derivable (see docs).

EDIT: But if you can not change f, then you can do this:

Plot[ f[x], {x, 0, 5}, Exclusions -> {2, 3} ]

-
Thanks, good answer, though note the restriction that I don't want to modify the function f. –  dreeves Dec 8 '10 at 0:49
Oops. rcollyer posted his answer while I added Exclusions to mine. :-) –  Gustavo Delfino Dec 8 '10 at 0:54
@gdelfino: it took me a few moments to find it and generate the graphs. –  rcollyer Dec 8 '10 at 0:56
@gdelfino, I was trying to imply that if it hadn't taken me that long, I would have posted it much sooner. But, it seems that I completely missed that point in my comment. –  rcollyer Dec 8 '10 at 20:40
@rcollyer Thank's fine. It is incredible how fast people answer good questions in stackoverflow. –  Gustavo Delfino Dec 9 '10 at 12:24

To answer your original question, (I assume you have your reasons for not using the Piecewise solution given by gdelfino)

f[x_]:=If[2<x<3,0,x]
Plot[f[x],{x,0,5},Exclusions->{2,3}]

-