9
$\begingroup$

I want to make an exclusion plot with Mathematica using ContourPlot. So I have a two dimensional function, everything higher then a certain value is excluded. In order to indicate which side is excluded, I would like to attach a light/hatched band to the contour on the side which is excluded. As an example, my function could be something like

P = ContourPlot[Cos[x] + Cos[y], {x, 0, 2.3}, {y, 2.5, 9}, 
 Contours -> {.5}, ContourStyle -> Black, ContourShading -> None]

which gives me this black parabola shaped curve in the picture. I now want a light band attached to it on one side - this I tried to show in the picture:

this is what I want

Note that I don't want the total contour to be shaded, as this would make the plot too crowded.

Actually I want something like this ROOT function does:

https://root.cern.ch/doc/v608/classTGraphPainter.html#GP02

Mathematica graphics

Any ideas how this can be done? Kind regards

Update: thank you very much for your ideas! While your proposals really look nice, the problem I see with them is, that the width of the band of course depends on the function, and so the thickness may vary along the contour, which is not exactly what I want. I have been trying a little bit myself, but I was not really able to come up with a good solution.

I tried the following:
Getting the points of the ContourPlot with

Points = Cases[Normal@P, Line[x_] :> x, Infinity][[1]];

then shift them perpendicular to the Contour by a factor k

k = 0.5;
ShiftPoints = #[[1]]  + 
     k/Norm[#[[1]] - #[[2]]]*Cross[#[[1]] - #[[2]]] & /@ 
   Partition[Points, 2, 2];

then add the shifted points and the original to a Polygon and show them:

g = Graphics[{Gray, Opacity[0.2], 
    Polygon[Join[Points, Reverse[ShiftPoints]]]}];
Show[P, g]

enter image description here

which is kind of ok, but it gets deformed for a different Plotscale. I think it would work better, if one could get the points from the ContourPlots in terms of the "image coordinates" instead of the real ones.
Maybe one of you has an idea how to improve on that?


Key words: hatched filling, custom filling

$\endgroup$

3 Answers 3

14
$\begingroup$

Update 2: In version 12.1 you can use the directives PatternFilling or HatchFilling for MeshShading:

ParametricPlot[
 Evaluate[v f[x] + (1 - v) shiftF[f][x, .2, ar prr]], {x, 0, 1}, {v, 0, 1}, 
  MeshFunctions -> { #4 &}, 
  MeshShading -> {None, HatchFilling[]},
  Mesh -> { {{1,Directive[Thick, Opacity[1],Red]},{0, White}}}, 
  AspectRatio -> ar, ImageSize -> 400, Evaluate @ opts]

enter image description here

With MeshShading -> {None, PatternFilling["Diamond", ImageScaled[1/50]]} we get

enter image description here

Update: a function to produce parallel-looking shifts:

ClearAll[shiftF, f]
shiftF [f_] := f[#] + {{0, #2}, {-#2/#3, 0}}.Normalize[f'[t] /. t -> #] &;

where the second argument controls the amount of "shift" and the third argument can be used to adjust for distortions caused by aspect ratio and plot range.

Examples:

cp = ContourPlot[Cos[x] + Cos[y], {x, 0, 3}, {y, 2.5, 9}, 
   Contours -> {.5}, ContourStyle -> Directive[Blue, Thick], 
   ContourShading -> {None, None}, PlotRange -> {{0, 3}, {3, 9}}];
f = BSplineFunction[Cases[Normal@cp, Line[x_] :> x, ∞][[1]], SplineClosed -> False];
opts = Sequence[Frame -> True, Axes -> False, PerformanceGoal -> "Quality", 
   BoundaryStyle -> None, PlotRangePadding -> .1, PlotStyle -> None];
prr = Divide @@ First @ Differences @ PlotRange @ cp;
ar = 1;

ParametricPlot[Evaluate[v f[x] + (1 - v) shiftF[f][x, .2, ar prr]],
 {x, 0, 1}, {v, 0, 1}, MeshFunctions -> {# + .5 #2 &, # - .5 #2 &, #4 &}, 
 MeshStyle -> {GrayLevel[.5], GrayLevel[.5], Directive[Thick, Red]}, MeshShading -> None, 
 Mesh -> {80, 80, {1}}, AspectRatio -> ar, ImageSize -> 400, Evaluate@opts]

enter image description here

Change the shift parameter to -.2 to get

enter image description here

With ar = 6/4 and .2 as the second argument in shiftF[f] we get

enter image description here

and with ar = 1/2 and .1 as the second argument in shiftF[f] we get

enter image description here

cp2 = ContourPlot[{Cos[x] + Cos[y] == .5, (x - 2)^2 + ((y - 5)/2)^2 == 1}, 
  {x, 0, 3}, {y, 2.5, 9}, 
  ContourStyle -> {Directive[Blue, Thick], Directive[Red, Thick]}, 
  ContourShading -> None, PlotRange -> {{0, 3}, {3, 9}}];
pnts = Cases[Normal@cp2, Line[x_] :> x, Infinity];
{fa1, fb1} = BSplineFunction[#, SplineClosed -> False] & /@ pnts;
cols = {Red, Green}; mfs = {# + .5 #2 &, #2 &}; mns = {80, 60};
i = 1;
Show[(j = i++; color = cols[[j]]; mf = mfs[[j]]; mn = mns[[j]]; 
  ParametricPlot[#, {x, 0, 1}, {v, 0, 1}, Axes -> False, MeshFunctions -> {mf, #4 &}, 
     MeshStyle -> {Directive[Opacity[.5, color], Thin], Directive[Thick, color]}, 
     MeshShading -> None,  Mesh -> {mn, {1}}, Evaluate@ opts]) & /@ 
  {v fa1[x] + (1 - v) shiftF[fa1][x, .2, 1/2],
   v fb1[x] + (1 - v) shiftF[fb1][x, .2, 1/2]}, PlotRange -> All]

enter image description here

fa = { Sin[4 #], Sin[3  #]} &;
ar = 5/4;
opts = Sequence[Frame -> True, PerformanceGoal -> "Quality", 
   BoundaryStyle -> None, PlotStyle -> None, Axes -> False, 
   PlotPoints -> 50, ImageSize -> 400, PlotRangePadding -> .2, 
   AspectRatio -> ar, PlotRange -> All];

ParametricPlot[Evaluate[v fa[u] + (1 - v) shiftF[fa][u, .1, ar]], 
 {u, 0, 2 Pi}, {v, 0, 1}, 
 MeshFunctions -> {# - .5 #2 &, # + .5 #2 &, #4 &}, 
 MeshStyle -> {GrayLevel[.5], GrayLevel[.5], Directive[Thick, Red]}, 
 MeshShading -> None, Mesh -> {70, 70, {1}}, Evaluate@opts]

enter image description here

With ar = 1/2 we get

enter image description here

Related:


Original answer:

You can use RegionFunction to specify the shaded region and MeshFunctions to create hatched shading:

ContourPlot[Cos[x] + Cos[y], {x, 0, 3}, {y, 2.5, 9}, Contours -> {.5},
 ContourStyle -> Directive[Blue, Thick], 
 ContourShading -> {None, None}, PlotRange -> {{0, 3}, {3, 9}}, 
 PlotPoints -> 100, Mesh -> 50, MeshFunctions -> { #1&, #2 &}, 
 MeshStyle -> Directive[Thin, Gray],
 RegionFunction -> (.2 <= Cos[#] + Cos[#2] <= .501 &)]

Mathematica graphics

Alternatively, you can use RegionPlot with MeshFunctions to produce hatched or cross-hatched regions and use it as Prolog in ContourPlot:

ContourPlot[Cos[x] + Cos[y], {x, 0, 3}, {y, 2.5, 9}, Contours -> {.5},
  ContourStyle -> Directive[Black, Thick], ContourShading -> None, 
 PlotRange -> {{0, 3}, {3, 9}}, 
 Prolog -> RegionPlot[.2 <= Cos[x] + Cos[y] <= .5, {x, 0, 4}, {y, 2.5, 10}, 
    Mesh -> 60, BoundaryStyle -> None, 
    MeshFunctions -> {5 #1 - #2 &, 5 #1 + #2 &}, 
    MeshStyle -> Directive[Thin, Gray], PlotStyle -> None, 
    PlotPoints -> 100, PlotRange -> {{0, 3}, {0, 10}}][[1]]]

Mathematica graphics

You get the same picture using ContourPlot[...][[1]] as Epilog in RegionPlot

RegionPlot[.2 <= Cos[x] + Cos[y] <= .5, {x, 0, 4}, {y, 2.5, 10}, 
 Mesh -> 60, BoundaryStyle -> None, 
 MeshFunctions -> {5 #1 - #2 &, 5 #1 + #2 &}, 
 MeshStyle -> Directive[Thin, Gray], PlotStyle -> None, 
 PlotPoints -> 100, PlotRange -> {{0, 3}, {3, 9}}, 
 Epilog -> ContourPlot[Cos[x] + Cos[y], {x, 0, 3}, {y, 2.5, 9}, 
    Contours -> {.5}, ContourStyle -> Directive[Black, Thick], 
    ContourShading -> None][[1]]]

Mathematica graphics

Variations:

ContourPlot[{Cos[x] + Cos[y] == .5, Sin[x] Sin[y/2] == .5}, {x, 0, 3}, {y, 2.5, 9}, 
 ContourStyle -> {Directive[Blue, Thick], Directive[Red, Thick]}, 
 ContourShading -> None, PlotRange -> {{0, 3}, {3, 9}}, 
 Epilog -> {RegionPlot[.2 <= Cos[x] + Cos[y] <= .5, {x, 0, 4}, {y, 2.5, 10},
     Mesh -> 80, BoundaryStyle -> None, 
     MeshFunctions -> {5 #1 - #2 &, 5 #1 + #2 &}, 
     MeshStyle -> Directive[Thin, Blue], PlotStyle -> None, 
     PlotPoints -> 100, PlotRange -> {{0, 3}, {0, 10}}][[1]], 
   RegionPlot[.2 <= Sin[x] Sin[y/2] <= .5, {x, 0, 4}, {y, 2.5, 10}, 
     Mesh -> 100, BoundaryStyle -> None, 
     MeshFunctions -> {5 #1 - #2 &, 5 #1 + #2 &}, 
     MeshStyle -> Directive[Thin, Pink], PlotStyle -> None, 
     PlotPoints -> 100, PlotRange -> {{0, 3}, {0, 10}}][[1]]}]

Mathematica graphics

Use MeshFunctions -> {5 #1 - #2 &} in the first RegionPlot and MeshFunctions -> {5 #1 + #2 &} in the second to get

Mathematica graphics

Finally, rather surprising shading patterns with random MeshFunctions:

ContourPlot[{Cos[x] + Cos[y] == .5, Sin[x] Sin[y/2] == .5}, {x, 0, 3}, {y, 2.5, 9}, 
 ContourStyle -> {Directive[Blue, Thick], Directive[Red, Thick]}, 
 ContourShading -> None, PlotRange -> {{0, 3}, {3, 9}}, 
 Prolog -> (RegionPlot[.2 <= #[[1]] <= .5, {u, 0, 4}, {v, 2.5, 10}, 
   Mesh -> #[[2]], BoundaryStyle -> None, 
   MeshShading -> {Directive[Opacity[.3], Hue[RandomReal[]]], White}, 
   MeshFunctions -> {RandomInteger[{-1, 1}] #1 + RandomInteger[{-1, 1}] #2 &}, 
   MeshStyle -> Directive[Thin, Gray], PlotStyle -> None, PlotPoints -> 50, 
   PlotRange -> {{0, 3}, {0, 10}}][[1]] & /@ 
     {{Cos[u] + Cos[v], 10}, {Sin[u] Sin[v/2], 10}})]

Mathematica graphics

$\endgroup$
2
  • $\begingroup$ Very nice use of meshes. (+1) $\endgroup$
    – Edmund
    Commented Mar 4, 2017 at 2:30
  • $\begingroup$ This is a really well written answer $\endgroup$
    – Avrana
    Commented Aug 16, 2020 at 3:48
3
$\begingroup$

You may specify additional Contours and related ContourStyle and ContourShading.

ContourPlot[Cos[x] + Cos[y], {x, 0, 2.3}, {y, 2.5, 9},
 Contours -> {.5, 0.4},
 ContourStyle -> {None, Black},
 ContourShading -> {None, LightBlue}]

Mathematica graphics

Hope this helps.

$\endgroup$
0
$\begingroup$

with a handle on approximate contour width

ContourPlot[Sin[x] Sin[y], {x, 0, Pi}, {y, 0, Pi},Contours -> {.2,.3, 12}]

enter image description here

$\endgroup$

Your Answer

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

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