14
$\begingroup$

How can I adjust the position of axes labels with respect to the axes they are bound? Like shifting slightly right or left. I do not what to destroy the graphics' dynamics and render it 2D.

p[r_, coupon_, n_, value_] := (coupon*value)/r (1 - 1/(1 + r)^n) + 
  value/(1 + r)^n

Plot3D[Evaluate[
  p[r/100, c, n, 1]^-1*D[p[r/100, c, n, 1], r] /. r -> 6], {n, 1, 
  20}, {c, 0, 0.1}, 
 AxesLabel -> {"years", "coupon %", 
   Rotate[ "Price change", 90 Degree]}]
$\endgroup$
2

2 Answers 2

9
$\begingroup$

How can I just directly assign positions?

You can do it manually by creating Graphics3D text objects and positioning them alongside the plot. You can specify their coordinates using Scaled coordinates,

Show[
 Plot3D[Evaluate[
   p[r/100, c, n, 1]^-1*D[p[r/100, c, n, 1], r] /. r -> 6], {n, 1, 
   20}, {c, 0, 0.1}],
 Graphics3D[Text["years", Scaled[{0.45, -.15, 0}]]],
 Graphics3D[Text["coupon %", Scaled[{-.15, .85, 1.1}]]],
 Graphics3D[
  Text[Rotate["Price Change", 90 Degree], 
   Scaled[{-0.05, -.15, 0.75}]]]]

enter image description here

Or absolute coordinates,

Show[
 Plot3D[Evaluate[
   p[r/100, c, n, 1]^-1*D[p[r/100, c, n, 1], r] /. r -> 6], {n, 1, 
   20}, {c, 0, 0.1}],
 Graphics3D[Text["years", {6, -.02, -.18}]],
 Graphics3D[Text["coupon %", {-2, .07, 0.04}]],
 Graphics3D[
  Text[Rotate["Price Change", 90 Degree], {-1, -.02, -.03}]]]

enter image description here

Interestingly, the normal trick of using Epilog->Inset[....] will not work here. It's possible to put the text in the graphics this way, but when you go to rotate the graphics with your mouse, the text stays in the same place.

$\endgroup$
1
  • $\begingroup$ is there a way to make the alignment of labels along the axis? $\endgroup$
    – Al Guy
    Commented Apr 16, 2016 at 12:45
16
$\begingroup$

Edit in response to the comment about Dynamic Rotating (1/3/17)

Make a function with three angles as its arguments. The three angles control the rotation of the three axis labels.

f[xangle_, yangle_, zangle_] := 
Module[{}, 
labelx = Style[Rotate["years", xangle], FontFamily -> "Arial", Bold,
 12];
 labely = 
 Style[Rotate["coupon %", yangle], FontFamily -> "Arial", Bold, 12];
 labelz = 
Style[Rotate["Price change", zangle], FontFamily -> "Arial", Bold, 
 12];

 fig = Overlay[{plot, 
 Graphics[{}, AspectRatio -> (h + b + t)/(w + l + r1), 
  ImageSize -> {w + l + r1, h + b + t}, ImagePadding -> 0, 
  Epilog -> {Dynamic[Locator[Dynamic[pt], labelx]], 
    Dynamic[Locator[Dynamic[pt1], labelz]], 
    Dynamic[Locator[Dynamic[pt2], labely]]}]}, All, 2]
 ]

Now make three slider that can dynamically rotate the above three angles

Slider[Dynamic[xangle], {0 Degree, 360 Degree, 0.5 Degree}]
Slider[Dynamic[yangle], {0 Degree, 360 Degree, 0.5 Degree}]
Slider[Dynamic[zangle], {0 Degree, 360 Degree, 0.5 Degree}]

Then call the function with the same dynamic argument. Now you also have control over the rotation. Use the slider to set up the angles as shown below.

enter image description here

Freeze the final image after you have set everything as before by using

finalFig = 
fig /. Locator[x_, y_] :> Inset[y, x] /. Dynamic :> Identity

Regarding saving the image you should be able to export it cleanly with Export command. But before exporting it is good habit to initialize the saving directory to the current notebook directory. I always use the following initialization in all my notebooks.

 SetDirectory[NotebookDirectory[]];
 SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
 $HistoryLength = 0;

Now the exported image will be saved in the same directory where your notebook is saved.

 Export["1.jpg", finalFig, ImageResolution -> 300]

Original Answer

There's a easier way to position elements by using Dynamic locator.

Let us define some constants to be used later.

pt = Scaled[{0.5, 0.5}];    (*initial position of label1*)
pt1 = Scaled[{0.5, 0.5}];   (*initial position of label2*)
pt2 = Scaled[{0.5, 0.5}];   (*initial position of label3*)
{w, h} = {400, 250};        (*width & height*)
{{l, r1}, {b, t}} = {{80, 40}, {60, 10}};    (*padding controls*)

Plot the function without any label.

plot = Plot3D[Evaluate[p[r/100, c, n, 1]^-1*D[p[r/100, c, n, 1], r] /. 
r -> 6], {n, 1, 20}, {c, 0, 0.1}, 
ImageSize -> {w + l + r1, h + b + t}, ImagePadding -> {{l, r1}, {b, t}}]

Create the labels separately with controls over its styling.

labelx = Style["years", FontFamily -> "Arial", Bold, 12];
labely = Style["coupon %", FontFamily -> "Arial", Bold, 12];
labelz = Style[Rotate["Price change", 90 Degree], FontFamily -> "Arial", Bold, 12];

Now we can Overlay the plot and labels including Dynamic locator so that we can move all the labels independently to any desired location as seen in the following gif.

  fig = Overlay[{plot, 
  Graphics[{}, AspectRatio -> (h + b + t)/(w + l + r1), 
  ImageSize -> {w + l + r1, h + b + t}, ImagePadding -> 0,
  Epilog -> {Dynamic[Locator[Dynamic[pt], labelx]], 
  Dynamic[Locator[Dynamic[pt1], labelz]], 
  Dynamic[Locator[Dynamic[pt2], labely]]}]}, All, 2]

enter image description here

After you have placed all the labels to your satisfaction you can then freeze their final position.

 finalFig = fig /. Locator[x_, y_] :> Inset[y, x] /. Dynamic :> Identity
$\endgroup$
6
  • $\begingroup$ This is a neat trick. You should note that if you want to resize or rotate the 3D figure, you need to do that before applying the dynamic stuff, since Overlay makes it so you can't do that stuff anymore. $\endgroup$
    – Jason B.
    Commented Feb 5, 2016 at 9:21
  • $\begingroup$ Yes that's true but I rotated the plot and choose a particular orientation and then again ran the plot but the orientation didn't carry through to the Overlay part. The only way I see is to first rotate the figure to your liking, then cut it and paste it inside AbsoluteOptions["paste figure here", ViewPoint]. Then set the value you just found inside the Plot3D command. $\endgroup$
    – Hubble07
    Commented Feb 5, 2016 at 9:39
  • $\begingroup$ I find that I can just copy and paste the graphic into the fig=Overlay[{____,... command in place of the word plot, and if I make adjustments there they carry through to the output. $\endgroup$
    – Jason B.
    Commented Feb 5, 2016 at 9:50
  • 1
    $\begingroup$ Yep that works. But I was thinking about dynamically updating this as well and found this : http://mathematica.stackexchange.com/questions/5375/extract-current-viewing-parameters-from-a-3d-view. You define vp = Options[Plot3D, ViewPoint][[1, 2]] and set option ViewPoint -> Dynamic[vp] inside the Plot3D. This is effortless. $\endgroup$
    – Hubble07
    Commented Feb 5, 2016 at 10:10
  • $\begingroup$ Great answer to a quite annoying problem. However, I cannot save the graphic in any format (right click on graphic --> save graphic as ...). I just end up with a white plot. Strangely, the axes are shown. In addition, it would be cool to be also able to rotate each axes label so that they are parallel to the axes. Is there a possibility to incorporate that here? $\endgroup$
    – Niki
    Commented Mar 1, 2017 at 14:40

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.