# Switching among view points in a Manipulate expression

Edit: Some additional viewpoints were included to make it easier to test. Here's code for an alternative function, the graph of which is a bit less symmetric. Feel free to use either code set:

f = ArcCoth; Manipulate[
Plot3D[Abs[f[x + I y]], {x, -2, 2}, {y, -2, 2},
RegionFunction -> Function[{x, y, z}, x^2 + y^2 <= 4],

MeshFunctions ->
Function @@@ {{{x, y, z}, Re[f[x + I y]]}, {{x, y, z},
Im[f[x + I y]]}}, MeshStyle -> {Orange, Green},
BoxRatios -> {1, 1, 1},
ViewPoint -> Dynamic[vp]], {{vp, {5, 8, 4}, "viewpoint"}, {
{5, 8, 4} -> "mathematicians' default",
{1.3, -2.4, 2} -> "Mathematica's default",
{0, -2, 0} -> "in front",
{0, -2, 2} -> "in front and up",
{0, -2, -2} -> "in front and down",
{-2, -2, 0} -> "left-hand corner",
{2, -2, 0} -> "right-hand corner",
{0, 0, 2} -> "directly above",
{0, -Infinity, 0} -> "xz from y at -\[Infinity]",
{0, 0, Infinity} -> "xz from z at \[Infinity]"
},


It's easy to place preset ViewPoints in a PopupMenu in order to switch among them. But if I manually rotate the graphics object, the program ceases to respond to changes in the PopupMenu selection.

Is there a way to have both functionalities?: (1) the PopupMenu and (2) manual rotation.

If the answer is no, is there at least a way to turn off manual rotation?

Below is a simplified version of the code.

Manipulate[
Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2},
RegionFunction -> Function[{x, y, z}, x^2 + y^2 <= 4],
BoxRatios -> {1, 1, 1}, ViewPoint -> Dynamic@vp],
Control[{{vp, {5, 8, 4}, "viewpoint"}, {
{5, 8, 4} -> "mathematicians' default",
{1.3, -2.4, 2} -> "Mathematica's default",
{0, -2, 0} -> "in front",
{0, -2, 2} -> "in front and up",
{0, -2, -2} -> "in front and down",
{-2, -2, 0} -> "left-hand corner",
{2, -2, 0} -> "right-hand corner",
{0, 0, 2} -> "directly above",
{0, -Infinity, 0} -> "xz from y at -\[Infinity]",
{0, 0, Infinity} -> "xz from z at \[Infinity]"
},


-
Manual rotation can be switched off by Deploy@Plot... –  Kuba Jul 14 at 22:07
@Kuba Thanks. Works well. Any way to get both to work simultaneously? –  David Carraher Jul 14 at 22:14
@Kuba. In the more realistic version of the code, I found I had to use Deployed -> True as an option of Manipulate. –  David Carraher Jul 14 at 22:38
Yes, I have forgotten that we are dealing with Manipulate and this option is available. –  Kuba Jul 14 at 22:40
Thank you for taking the time to nicely simplify your code. –  m_goldberg Jul 14 at 22:59

But the answer is yes, You need Dynamic inside Plot3D

Manipulate[
Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2},
RegionFunction -> Function[{x, y, z}, x^2 + y^2 <= 4],
BoxRatios -> {1, 1, 1}, ViewPoint -> Dynamic@vp],
Control[{{vp, {5, 8, 4},""}, {{5, 8, 4} -> "xyz",
{0, -Infinity, 0} -> "xz",
{0, 0, Infinity} -> "xy"},


I'm not sure why. It looks like Manipulate is creating connection between controller and vp only in one way. I might miss something, appreciate any comments.

-
It kind of works, but in the code I'm using it runs into other issues. E.g. the standard settings don't always look the same after manual viewpoint changes. –  David Carraher Jul 14 at 22:51
@DavidCarraher You mean other elements of ViewMatrix? –  Kuba Jul 14 at 22:55
In the longer code, it may drastically shrink the size of the graphics. Or it changes some aspect of the point of view. I included some additional viewpoints to see if that might help such flaws to appear in the short code (but haven't checked yet myself). –  David Carraher Jul 14 at 23:09
@DavidCarraher I think , SphericalRegion -> True is what You are looking for :). Cooperating with fixed size: , ImageSize -> {300, 300} –  Kuba Jul 14 at 23:10
I still get major distortions with manual rotation, perhaps because my full applet uses Show with Plot3D and Graphics3D (For technical reasons I need to use both). The applet I'm making is for about 60 students, many of whom would likely find manual rotation confusing. So I think I'll probably opt for pre-set viewpoints. Thanks for your help and reminding me about the great posting elsewhere on SE (and on Wolfram's web site) about the fundamentals of three dimensional viewing. –  David Carraher Jul 14 at 23:41
show 1 more comment

As Kuba says, you can wrap the vp in Dynamic:

Manipulate[
Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2},
RegionFunction -> Function[{x, y, z}, x^2 + y^2 <= 4],
BoxRatios -> {1, 1, 1}, ViewPoint -> Dynamic[vp]],

{{vp, {5, 8, 4}, ""},
{{5, 8, 4} -> "xyz", {0, -Infinity, 0} -> "xz", {0, 0, Infinity} ->


This does what you need, but maybe because of the switching between the Infinity perspectives and regular perspectives, you will get issues with the ViewAngle if you zoom in/out. One quick fix for this is to disable zooming:

Manipulate[
Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2},
RegionFunction -> Function[{x, y, z}, x^2 + y^2 <= 4],
BoxRatios -> {1, 1, 1},
ViewAngle -> Dynamic[9 Degree, None],
ViewPoint -> Dynamic[vp]],

{{vp, {5, 8, 4}, ""},
{{5, 8, 4} -> "xyz", {0, -Infinity, 0} -> "xz", {0, 0, Infinity} ->


I know why the Dynamic works here but I'm not sure why it's required. My guess is manual adjustment of the graphics disables programmatic adjustment. Similar to when you re-evaluate a Graphics3D expression and the output figure has the same size/perspective even if it has different contents. Imagine you're fiddling with some sliders in a Manipulate and the figure keeps resetting to the original perspective even though you want to see things from your own angle. That'd be annoying.

$-$

As a general remark, putting Dynamic inside a Manipulate is not a redundancy, as you might think. For example, compare the following with and without the Dynamic:

Manipulate[Pause[2];
Graphics[{(*Dynamic@*)color, Disk[]}],
{color, ColorSlider}]


Also try removing the None in our ViewAngle setting to see that Mathematica tries to assign a value to the expression "9 Degree." This should give you an appreciation for how dynamic Dynamic really is.

-
Hi, take Your code with  ViewAngle -> Dynamic[9 Degree, None], set the last ViewPoint and try to rotate it manually. Is this behaviour planned? –  Kuba Jul 14 at 23:00
The second block of code produces some weird effects! Manual rotation sends me plunging into the middle of the magnified graphics, as if I had shrunk down to the size of an ant and been drawn into the screen. Then, when I select a pre-set viewpoint, it takes up about 1/4 the area that it did before. I don't understand what's happening. –  David Carraher Jul 14 at 23:13
The ColorSlider example appears to produce the same effect in both cases, but the one with Dynamic is much more responsive. –  David Carraher Jul 14 at 23:16
@Kuba that zoom effect always happens when you drop out of an Infinity perspective, it's not related to the Dynamic. the lack of zoom does make rotating meaningless for that perspective though. i'm not quite sure how the whole thing would be properly fixed without adding more variables and stuff. @DavidCarraher, yea, the version with Dynamic is faster because the Manipulate doesn't re-evaluate its body, so the Pause isn't run. –  amr Jul 15 at 2:02

There are two problems that have been alluded to by @Kuba and @amr.

The first is that vp needs to be wrapped in Dynamic. This is because in the graphics output the value of vp is stored, not a reference to vp itself. Dynamic takes care of this, since it has the attribute HoldFirst. The further effect of wrapping vp in Dynamic has to do with how the front end implements Dynamic with Graphics3D. It will update the values of the "visible" Dynamic parameters, such as view properties (ViewPoint etc.), when the graphics are rotated.  Just beware that some activities can overwrite the setting ViewPoint -> Dynamic@vp. For instance, Ctrl-click (or right click) on the graphic and select "Top View" from the popup menu. Your Manipulate will no longer work. The view point setting has been changed to ViewPoint -> Top, and there's no way to get it back to vp (except to reevaluate the Manipulate).

One way to avoid that is to swim into the deep end with ViewMatrix, which will override ViewPoint so that ViewPoint -> Top would be ignored; see this answer. With ViewMatrix you should probably also set ViewCenter to be a dynamic variable (start with vc = {{0.5, 0.5, 0.5}, {0.5, 0.5}}. This will allow changes due to panning (Shift-drag) to be reset.

You can also turn off aspects of interactively modifying graphics with Dynamic -- a sort of anti-dynamic use of Dynamic. For instance, ViewCenter -> Dynamic[vc, (vc = {{0.5, 0.5, 0.5}, {0.5, 0.5}}) &] prevents the value of vc being changed when trying to pan with the mouse. Thus there is no panning because vc cannot be changed. You can do something similar with ViewAngle to prevent zooming.

The second problem is rotating after setting ViewPoint -> {0, -Infinity, 0}, etc. -- that is, a view point infinitely far away. The rotation methods for graphics work only for a finite distance. The front end just reassigns the view point to be a default distance, which seems to be 2..

Turning off manual rotation

Rotation of 3D graphics can be turned off with Method -> {"RotationControl" -> None}.

Manipulate[
Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2},
RegionFunction -> Function[{x, y, z}, x^2 + y^2 <= 4],
BoxRatios -> {1, 1, 1}, ViewPoint -> vp,
Method -> {"RotationControl" -> None}],
Control[{{vp, {5, 8, 4}, ""},
{{5, 8, 4} -> "xyz", {0, -Infinity, 0} -> "xz", {0, 0, Infinity} -> "xy"},


Side views that are not infinite

Another approach worth considering is having side views, such that the distances of the view points are all the same. This makes rotating the image pleasant. So instead of Infinity, one can put Norm@N@{5, 8, 4}. (Apparently the view point has to be a vector of numbers, not just numeric quantities -- at least it didn't work with the exact value Norm@{5, 8, 4}.) I include a few other alternations as suggestions (things I like, for you to consider).

Manipulate[Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2},
RegionFunction -> Function[{x, y, z}, x^2 + y^2 <= 4],
BoxRatios -> {1, 1, 1}, ViewPoint -> Dynamic@vp,
SphericalRegion -> True],
{{vp, {5, 8, 4}, ""},
{{5, 8, 4} -> "xyz", {0, -Norm@N@{5, 8, 4}, 0} -> "xz",
{0, 0, Norm@N@{5, 8, 4}} -> "xy"},