How to plot zeros of a function as a thin stripe?

Use NSolve to calculate f=0 points

f[x_] := Cos[x] + 2 Cos[2 x];

points = {#[[1, 2]], 4} & /@ NSolve[f[x] == 0 && 0 < x < 20, x];
(*Out: {{0.935929, 4}, {2.57376, 4}, ...} *)

Use Prolog to draw points on plot + increase the PlotRange to make sure you can see the points:

Plot[f[x], {x, 0, 20}, 
 PlotStyle -> Directive[Black, CapForm["Butt"], Opacity[1], Thickness[.001]],

 Prolog -> Point[points],
 PlotRange -> {Automatic, {-2.5, 4.5}}
 ]

enter image description here


Define a function that draws short lines at the given positions p.

marker[p_] := Line[{p - {0, .1}, p + {0, .1}}]; 

f[x_] := Cos[x] + 2 Cos[2 x];
points = {#[[1, 2]], 4} & /@ NSolve[f[x] == 0 && 0 < x < 20, x];

Plot[f[x], {x, 0, 20}, 
 PlotStyle -> 
  Directive[Black, CapForm["Butt"], Opacity[1], Thickness[.001]], 
 Prolog -> marker /@ points, PlotRange -> {Automatic, {-2.5, 4.5}}]

enter image description here


My own preference is to use the MeshFunctions option of Plot[] to get the positions of the stripes (which avoids a separate use of Solve[]/NSolve[]), and then post-process accordingly:

Show[Normal[Plot[Cos[x] + 2 Cos[2 x], {x, 0, 20}, Mesh -> {{0}}, 
                 MeshFunctions -> {#2 &}, 
                 MeshStyle -> Directive[Black, CapForm["Butt"],
                                        Opacity[1], Thickness[0.001]]]] /. 
     Point[{x_, y_}] :> Line[{Scaled[{0., -0.01}, {x, 4.}], Scaled[{0., 0.01}, {x, 4.}]}], 
     PlotRange -> All]

zero-dashed plot