17
$\begingroup$

I am doing a plot where I have multiple shaded regions, and I want the line that separates the two regions to be dashed with dashes being alternating colors (so the demarcation stands out from both regions).

For example, say I am plotting the two regions shown here

Plot[{1, Abs[BesselJ[1, x]]}, {x, 0, 20}, Filling -> Axis]

enter image description here

The only way I could think to add the dashing was using ColorFunction, but it doesn't give what I'm looking for:

bgplot = Plot[{1, Abs[BesselJ[1, x]]}, {x, 0, 20},
  Filling -> Axis, PlotStyle -> {Automatic, None}];
dashplot = Plot[Abs[BesselJ[1, x]], {x, 0, 20},
  PlotStyle -> Thickness[.01], 
  ColorFunction -> (If[EvenQ[Floor[#]], Black, White]&),
  ColorFunctionScaling -> False, PlotPoints -> 500];
Show[bgplot, dashplot]

enter image description here

This is almost what I want, but the dashes are all the same length in the x-coordinate, whereas I'd prefer they be the same total length. Also, I have to have PlotPoints set to an unreasonably high value to avoid any gray regions.

Any ideas how to do this better?

$\endgroup$
0

4 Answers 4

17
$\begingroup$

A simple but flexible approach might be to plot the function twice, as in this example, with a solid color the first time overlaid by a dashed line the second:

f[x_] := Abs[BesselJ[1, x]];
Plot[{f[x], f[x]}, {x, -10, 10}, 
 PlotStyle -> {Directive[Thick, White], 
   Directive[Thick, Dashing[{0.1, 0.1}]]}, Background -> LightGray]

Plot

$\endgroup$
2
  • $\begingroup$ Filling is optional... $\endgroup$
    – whuber
    Nov 22, 2012 at 0:14
  • $\begingroup$ Thanks a bunch! The plot above is now written Plot[{1, Abs[BesselJ[1, x]], Abs[BesselJ[1, x]]}, {x, 0, 20}, Filling -> {1 -> {2}, {2 -> Axis}}, PlotStyle -> {Automatic, {Thickness[.01], Black}, {Dashing[.05], White, Thickness[.01]}}] $\endgroup$
    – user4368
    Nov 22, 2012 at 0:27
8
$\begingroup$

Here's one possibility (incorporating Mike's enhancements):

Plot[Abs[BesselJ[1, x]], {x, 0, 20},
     Filling -> {1 -> Axis, 1 -> Top},
     FillingStyle -> {Opacity[1/5, ColorData[1, 1]], Opacity[1/5, ColorData[1, 2]]},
     Mesh -> Full, MeshFunctions -> {#1 &}, MeshShading -> {Red, Blue}, MeshStyle -> None,
     PlotRange -> {0, 1}, PlotStyle -> Directive[AbsoluteThickness[2]]]

plot with alternating colors

Alternatively:

Plot[Abs[BesselJ[1, x]], {x, 0, 20},
     Filling -> {1 -> Axis, 1 -> Top},
     FillingStyle -> {Opacity[1/5, ColorData[1, 1]], Opacity[1/5, ColorData[1, 2]]},
     Mesh -> 90, MeshFunctions -> {Norm[{#1, #2}] &},
     MeshShading -> {Red, Blue}, MeshStyle -> None,
     PlotRange -> {0, 1}, PlotStyle -> Directive[AbsoluteThickness[2]]]

plot with "uniform" alternating colors

$\endgroup$
4
  • $\begingroup$ That is nice, but it suffers from the same problem as my own solution. That is, each dash has the same size along the x coordinate only. Notice that the first two dashes are much longer than the fourth and fifth. $\endgroup$
    – user4368
    Nov 22, 2012 at 0:14
  • $\begingroup$ Is the second version more suitable, @Jason? $\endgroup$ Nov 22, 2012 at 0:19
  • $\begingroup$ I was unaware of how to use Mesh, and I'm still pretty ignorant about it. I'm not quite sure what it's doing in this example. Using {#1&} as the mesh function, gives mesh points equally spaced along the x-coordinate. But {Norm[{#1, #2}] &} gives mesh based on the distance from the origin, which is better but not quite what I want. Notice there are still uneven sizes for the dashes. Mesh is definitely less clunky than the ColorFunction option I used. $\endgroup$
    – user4368
    Nov 22, 2012 at 0:27
  • 2
    $\begingroup$ Oh well, gave it a college try at least... $\endgroup$ Nov 22, 2012 at 0:33
5
$\begingroup$

Here's a way to use the "ArcLength" setting to get equal-length segments. One has to scale the coordinates so the arc length in the coordinate geometry is proportional to the arc length in the screen geometry. This can be done with ScalingFunctions, if the PlotRange is known; otherwise, the plot range will need to be computed and the plot redrawn.

Plot[Abs[BesselJ[1, x]],
 {x, 0, 20},
 Filling -> {1 -> Axis, 1 -> Top},
 FillingStyle -> {Opacity[1/5, ColorData[1, 1]], Opacity[1/5, ColorData[1, 2]]},
 PlotRange -> {0, 1}, PlotStyle -> Thickness[.01],
 Mesh -> 18, MeshStyle -> None, MeshShading -> {Black, White}, 
 MeshFunctions -> {"ArcLength"}, 
 ScalingFunctions ->
   {{GoldenRatio #/20 &, 20 #/GoldenRatio &},  (* scale by plot range & aspect ratios *)
    None} 
 ]

Mathematica graphics

Here's a two-pass function that computes the plot range and aspect ratio and inserts the appropriate scaling functions:

ClearAll[arclengthmesh];
SetAttributes[arclengthmesh, HoldAll];
arclengthmesh[plot_] := Module[{p, pr, ar},
  p = plot;
  pr = Ratios[Differences /@ PlotRange@p][[1, 1]];
  ar = AspectRatio /. Options[p, AspectRatio] /. Automatic -> 1/GoldenRatio;
  ReleaseHold[
   Insert[
    Hold[plot],
    {MeshFunctions -> {"ArcLength"}, 
     ScalingFunctions -> {{pr*#/ar &, ar*#/pr &}, None}},
    {1, 3}
    ]]
  ]

arclengthmesh@
 Plot[Abs[BesselJ[1, x]],
  {x, 0, 20},
  Filling -> {1 -> Axis, 1 -> Top},
  FillingStyle -> {Opacity[1/5, ColorData[1, 1]], 
    Opacity[1/5, ColorData[1, 2]]},
  PlotRange -> {0, 1}, PlotStyle -> Thickness[.01],
  Mesh -> 18, MeshStyle -> None, MeshShading -> {Black, White}, 
  AspectRatio -> 1/3]

Mathematica graphics

$\endgroup$
1
  • $\begingroup$ Clever! I hope this gets more votes. $\endgroup$
    – Mr.Wizard
    Mar 14, 2017 at 12:45
1
$\begingroup$

Like this?

Plot[Evaluate[{Sin[2 \[Pi] x], Sin[2 \[Pi] x]}], {x, 0, 1}, 
 PlotStyle -> {{Dashing[{0.1, 0.1, 1*^-12, 1*^-12}], 
    Red}, {Dashing[{1*^-12, 0.1, 0.1, 1*^-12}], Black}}, 
 ImageSize -> 500]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.