Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I use the following code to draw Arrows on Axes in 2D graphics:

Plot[Sin[x],{x,-10,10},AxesStyle->Arrowheads[Automatic]]

But such code doesn't work with Plot3D[…] and 3D graphics.

Is there any way to get Axes with Arrows on 3D graphics?

share|improve this question
1  
See this math.se question for a way to plot axes with arrows in 3D plots. I'm not posting this as an answer, because I don't think it sufficiently addresses the larger issue at hand — that of being able to conveniently use arrows while at the same time retaining all the functionality of individual axes styling, automatic tick marks, etc. that the *Style functions provide. – R. M. Mar 10 '12 at 18:35
up vote 16 down vote accepted

Here is a simple way to do this:

arrowAxes[arrowLength_] :=
  Map[{Apply[RGBColor, #], Arrow[Tube[{{0, 0, 0}, #}]]} &, 
   arrowLength IdentityMatrix[3]]

This function draws three axes with arrows. To apply it:

Graphics3D[{Sphere[], arrowAxes[3]}]

Sphere with axes

This doesn't have axis labels, though.

To add labels by leveraging the built-in axes, one compromise (to save the work of making all labels by hand) would be to do the following:

Graphics3D[{Sphere[{1, 1, 1}], arrowAxes[3]}, Axes -> True, 
 Boxed -> False, AxesOrigin -> {0, 0, 0}, AxesStyle -> Opacity[0], 
 TicksStyle -> Opacity[1]]

Image with axis labels

Edit In my attempt at a labeled set of axes above, I deliberately set the axes to be invisible but left the ticks visible. You may find it more visually consistent to keep the default axes visible, together with the new 3D arrow-axes. For this, one could replace AxesStyle above with this: AxesStyle -> MapThread[RGBColor, IdentityMatrix[3]].

share|improve this answer
1  
The ticks and labels are shining through the sphere... – Sjoerd C. de Vries Mar 10 '12 at 18:53
    
They would with the standard axes, too. It's the default... I don't like it, either. Actually, one could say that this compromise is also an "improvement" over the default because at least the axes aren't shining through, so the viewer still has the numerical information about the ticks but also gets better visual cues as to the perspective. Anyway, the other option would be to go all the way and do the labels by hand, I guess. – Jens Mar 10 '12 at 18:55
    
Is it really necessary to hide the axes? – Sjoerd C. de Vries Mar 10 '12 at 19:01
    
No, of course that's a matter of taste. I edited my answer to take your suggestion into account. – Jens Mar 10 '12 at 19:07

Jens's answer is great, and shows how to add arrow axes to a Graphics3D object, but I feel like we still need a general-purpose plotting function. Here is the straightforward implimentation:

threeDArrowPlot[func_, var1_, var2_, plotopts : OptionsPattern[]] := 
  Module[{plot, arrows, lengths},
   plot = 
    Plot3D[func, var1, var2, Boxed -> False, AxesOrigin -> {0, 0, 0}, 
     Evaluate[FilterRules[{plotopts}, Options[Plot3D]]]];
   lengths = 
    DiagonalMatrix[(Charting`get3DPlotRange@plot)[[All, 2]] // 
      Flatten];
   arrows = {RGBColor @@ #, Arrow[Tube[{{0, 0, 0}, #}]]} & /@ 
     lengths;
   Show[plot, Graphics3D@arrows]
   ];

You can add any option that normally goes to Plot3D,

Grid[{{
   threeDArrowPlot[Sin[x y], {x, -2, 2}, {y, -3, 3}], 
   threeDArrowPlot[Sin[x y], {x, -2, 2}, {y, -3, 3}, 
    ViewCenter -> {0.5, 0.5, 0.5}, ViewPoint -> {2.14, 2.2, 1.4}, 
    ViewVertical -> {0, 0, 1}, AxesStyle -> Opacity[0], 
    TicksStyle -> Opacity[1], BoxRatios -> {2, 2, 1}, 
    ImageSize -> 500]}}]

enter image description here

But it isn't as general-purpose as I would like. In particular, it fails when the axes ranges are different orders of magnitude. Consider the following plots,

threeDArrowPlot[# Exp[-x^2 - 2 y^2] Sin[x y], {x, -2, 2}, {y, -3, 3}, 
   PlotRange -> All, Mesh -> None, ImageSize -> 500] & /@ {1, 10, 100}

enter image description here

I tried to add arguments to the function that explicitly give the arrow tube radius and arrowhead size in the code pasted here but the results were no good. Any help would be appreciated.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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