4
$\begingroup$

I know how to combine a RegionPlot3D and a ContourPlot3D, which I did (see below for details on the code I'm referring to) with

Show[regionPlot,contourPlot]

What I want is to make the ContourPlot appear and disappear switching a checkbox in the Manipulate controls. I actually managed to do this using

If[showQPlane,Show[regionPlot,contourPlot],regionPlot]

but I feel that this is not the optimal, cleaner solution.

Is it possible to conditionally append one (or more) argument(s) to the Show, with something like

Show[regionPlot,If[showQPlane,contourPlot]]

which however unfortunately does not work?

I would also like the contourPlot to not be calculated at all when not shown, if possible.


Here is the code I ended up using following the tips by LLIAMnYP and Kuba, in which I also added an option to display a 2D RegionPlot of the intersection of the RegionPlot3D and the ContourPlot3D:

U[Q_, q_] := (Q^2 + q^2 + 2 q Q^2 - 2/3 q^3)/2
Manipulate[
 regionPlot := RegionPlot3D[
   If[! invertRegion,
    p^2/2 + U[Q, q] <= energy,
    p^2/2 + U[Q, q] >= energy
    ],
   {p, -regionSize, regionSize},
   {q, -regionSize, regionSize},
   {Q, -regionSize, regionSize},
   AxesLabel -> {"p", "q", "Q"},
   PerformanceGoal -> "Quality",
   PlotRange -> {{-regionSize, regionSize}, {-regionSize, 
      regionSize}, {-regionSize, regionSize}},
   ImageSize -> 800,
   PlotPoints -> plotPoints,
   MeshFunctions -> {Function[{p, q, Q}, Q - coordQPlane]},
   Mesh -> {{0}},
   MeshStyle -> Directive[Red, Thick],
   RotationAction -> "Clip"
   ];
 If[showQPlane,
  contourPlot := ContourPlot3D[
    Q == coordQPlane,
    {p, -regionSize, regionSize},
    {q, -regionSize, regionSize},
    {Q, -regionSize, regionSize},
    Mesh -> None,
    ContourStyle -> Purple,
    RotationAction -> "Clip"
    ]
  ];
 If[showSlice,
  slicePlot := RegionPlot[
    If[! invertRegion,
     p^2/2 + U[coordQPlane, q] <= energy,
     p^2/2 + U[coordQPlane, q] >= energy
     ],
    {p, -regionSize, regionSize},
    {q, -regionSize, regionSize},
    AxesLabel -> {"p", "q"},
    PerformanceGoal -> "Quality",
    PlotRange -> {{-regionSize, regionSize}, {-regionSize, 
       regionSize}},
    ImageSize -> 800,
    PlotPoints -> plotPoints
    ]
  ];
 Dynamic@Row[{
    Dynamic@Show[
      (Pick[
         HoldComplete@{regionPlot, contourPlot},
         {{True, showQPlane}}
         ])[[1]]
      ],
    If[showSlice,
     slicePlot,
     Sequence[]
     ]
    }],
 {{energy, 0.15, "Energy"}, 0., 10., 0.01, Appearance -> "Open"},
 {{regionSize, 4., "Region Size:"}, 1., 100., 0.1, 
  Appearance -> "Open"},
 {{plotPoints, 20, "Plot Points"}, 10, 100, 1, Appearance -> "Open"},
 {{coordQPlane, 0., "Q Plane"}, -regionSize, regionSize, 0.1, 
  Appearance -> "Open"},
 {{showQPlane, True, "Show Plane"}, {False, True}},
 {{showSlice, False, "Show Slice"}, {False, True}},
 {{invertRegion, False, "Invert region"}, {False, True}},
 SynchronousUpdating -> False,
 ControlPlacement -> Left
 ]

And here is a snapshot of the output: enter image description here

$\endgroup$
8
  • $\begingroup$ @Kuba that's perfect, I didn't really think of using an empty list inside the list given to Show, thanks! Post it as an answer and I'll accept it. $\endgroup$
    – glS
    May 19 '15 at 10:02
  • $\begingroup$ Instead of Ifs, I prefer this: Show[Pick[{regionPlot, contourPlot}, {True, showQPlane}]]. Still working on suppresing evaluation though. $\endgroup$
    – LLlAMnYP
    May 19 '15 at 10:19
  • $\begingroup$ @LLlAMnYP which evaluation? $\endgroup$
    – Kuba
    May 20 '15 at 8:24
  • $\begingroup$ @Kuba the one that doesn't happen because If has HoldRest :) $\endgroup$
    – LLlAMnYP
    May 20 '15 at 8:39
  • $\begingroup$ @glance thanks for the accept, though I don't think it's a good idea to remove the original code. I found it in the revision history as I wanted to toy around with it some more, but the problem may not be clear anymore to people, who read the question in the future. $\endgroup$
    – LLlAMnYP
    May 20 '15 at 8:45
2
$\begingroup$

As in my comment, I feel, it's cleaner to use

Show[(Pick[HoldComplete[{regionPlot, contourPlot}], {{True, showQPlane}}])[[1]]]

Additionaly I use SetDelayed in the definition of contourPlot to prevent evaluation at definition and HoldComplete makes sure that first Pick is run, and only then what's left is evaluated. [[1]] strips the result of Pick of the HoldComplete head.

By the way, there's several ways to use If and your initial construct:

Show[regionPlot,If[showQPlane,contourPlot,Unevaluated@Sequence[]]]

You just needed to pass a proper return for the False condition, otherwise the return is Null and that is not a Graphics object.

This is, of course, easily extendable to multiple Ifs:

Show[regionPlot,If[showQ1,plot1,Unevaluated@Sequence[]],
                If[showQ2,plot2,Unevaluated@Sequence[]],
                If[showQ3,plot3,Unevaluated@Sequence[]],
                ...
                If[showQn,plotn,Unevaluated@Sequence[]]
    ]

Because If has the attribute HoldRest, when contourPlot isn't shown, it is accordingly not evaluated. You can check, whether or not something is being evaluated by making the definition a compound expression, e.g:

contourPlot := (Print["Evaluating"];ContourPlot[...]);

Then, for example

Pick[{regionPlot, contourPlot}, {True, False}]

Evaluating, >picture of only regionPlot but contourPlot still got evaluated<

But

Show[(Pick[HoldComplete[{regionPlot, contourPlot}], {{True, showQPlane}}])[[1]]]

just regionPlot, no evaluating message.

And the same goes for

Show[regionPlot, If[False, contourPlot, Unevaluated@Sequence[]]]
$\endgroup$
1
  • $\begingroup$ Very interesting, thanks a lot for sharing. Indeed I like these methods even more than the one proposed by Kuba. $\endgroup$
    – glS
    May 19 '15 at 19:15
1
$\begingroup$

This is a minimal example of how to do something like this:

Manipulate[ 
  plot1 = Graphics3D@Sphere[{0, 0, 0}, 1.3]; 
  If[x, Print@"Calculating plot2"; plot2 = Graphics3D@Cylinder[]]; 

  Show[{plot1, If[x, plot2, {}]}]
  , 
  {{x, True}, {True, False}}
]

Body of the Manipulate is inside Dynamic so if you want to be able to control what is sent to evaluation from there I suggest to read AdvancedDynamicFunctionality tutorial. Especially the section Nesting Dynamic.

$\endgroup$
1
  • $\begingroup$ I've read the tutorial you suggested, and tried to implement the advices. I've found however some difficulties in fully enclosing the manipulated variables in nested dynamics. For example in the code I included I also tried to wrap with Dynamic the variable coordQPlane to avoid the whole RegionPlot3D being redrawn when moving the Plane, but it doesn't seem to work. Do you have any tip on why is this so? $\endgroup$
    – glS
    May 20 '15 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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