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.

• These are amazing answers; thanks so much everyone! Dec 8 '10 at 6:54
• see here for Mathematica Q&A: Excluding Points from Plots (from Wolfram) Mar 15 '11 at 10:28
• Is this the community's first question? Dec 23 '17 at 7:18

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. 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... 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. 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. 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. 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" 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. Dec 8 '10 at 12:23
• Can something like this be adapted for a ListPlot, where you have discrete samples of the function? I want to exclude points that are near a discontinuity (because the samples here are very unreliable) Mar 16 '17 at 0:06
• @becko you'll have to mask them yourself. Although, I'd exchange the problematic points for Missing[] as ListPlot will produce something similar to Exclusions in that case. Mar 16 '17 at 15:00

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. Dec 8 '10 at 0:49
• Oops. rcollyer posted his answer while I added Exclusions to mine. :-) Dec 8 '10 at 0:54
• @gdelfino: it took me a few moments to find it and generate the graphs. 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. Dec 8 '10 at 20:40
• @rcollyer Thank's fine. It is incredible how fast people answer good questions in stackoverflow. Dec 9 '10 at 12:24

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}]


Update: This code might have worked in earlier versions of Mathematica. As of version 11, it does not work anymore.

• +1 One of those features I usually forget about ... Dec 9 '10 at 18:35
• +1 I cannot recall seeing this before. 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. Mar 4 '11 at 16:40
• @Mr.Wizard Does this still work? On v11 I get a weird output: SystemProtoPlotDumpiPlot[Plot, SystemProtoPlotDumpobj\$1974, f[x], {x, 0, 2, 3, 5}] Mar 16 '17 at 0:08
• @becko It fails in version 10.1 as well. Likely it was experimental syntax that was rejected. Mar 16 '17 at 5:53

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}]


Maybe I am getting late here, but in Mathematica 11 (and perhaps earlier versions) the ExclusionsStyle option would do the job, also for arbitrary functions...

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


Another example that also works

f[x_] := Tan[x]
Plot[f[x], {x, 0, 2 \[Pi]}, ExclusionsStyle -> None, PlotRange -> {-20, 20}]


This definitely comes late, but I think another elegant solution is to use in place of Plot[f[x], {x, 0, 5}] the instruction

DiscretePlot[f[x], {x, 0, 5, 0.1}, PlotStyle -> "LineColor" -> None]


I know it doesn't exactly answer the question, but for illustrative purposes it may be more than enough. For functions defined via NIntegrate[] and not known in closed form, moreover, all the above solutions fail because conditions like Exclusions -> {1/f[x] == 0} do not work.