Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a function $f:\mathbb{C}\rightarrow\mathbb{C}$ which I would like to visualize by by plotting $|f|$ with Plot3D using $\operatorname{Arg}f$ as the ColorFunction.

I use

DensityPlot[Arg[f[a + I b]], {a, -5, 5}, {b, -5, 5}, PlotPoints -> 35,
            WorkingPrecision -> 50, ColorFunction -> "DarkRainbow"]

and get the following:

nice

which looks pretty nice. However then when I use

Plot3D[Abs[f[a + I b]], {a, -5, 5}, {b, -5, 5}, PlotPoints -> 35, 
      WorkingPrecision -> 50, 
      ColorFunction -> (ColorData[{"DarkRainbow", {-\[Pi], \[Pi]}}][Arg[f[#1 + I #2]]] &), 
      ColorFunctionScaling -> False, 
      PerformanceGoal -> "Quality", Mesh -> None]

I get

awful

The quality of $\operatorname{Arg}f$ was fine in the DensityPlot using the same quality parameters, but it's awful when I make it a ColorFunction. I suppose this is because the surface mesh is made from $|f|$ in the Plot3D and not from $\operatorname{Arg}f$ as it was in the DensityPlot, and $|f|$ isn't changing very much around the important parts of $\operatorname{Arg}f$ which is why it looks so choppy and noticable.

So, how do I fix this? Is there a way to give the ColorFunction more PlotPoints than the actual surface, or perhaps a different mesh? If possible I want to avoid just increasing PlotPoints for the overall plot, as I am happy with the quality of $|f|$ here, and it can be very slow to render as it is.

share|improve this question
    
You don't give f. Is it intentional ? –  andre Feb 5 '13 at 21:07
    
Well, here f[z_] := BesselI[0, 2 Sqrt[z]]/(1 - z), but I plan to do this with a lot of functions so I am really interested in a general method. –  Alexander Gruber Feb 5 '13 at 21:09

3 Answers 3

up vote 22 down vote accepted

There is indeed an alternative which you might should consider. You almost got it yourself by the given analysis of the situation in your question. While Plot3D does only care of a good resolution of the function you plot and not the function you use for coloring, DensityPlot uses your color function from the beginning and tries to resolve this as best as possible.

Therefore, one possible way is to use the DensityPlot image as texture on your surface.

f[z_] := BesselI[0, 2 Sqrt[z]]/(1 - z)
img =
 Rasterize[
  DensityPlot[Arg[f[a + I b]], {a, -5, 5}, {b, -5, 5}, 
   PlotPoints -> 30, 
   ColorFunction -> (ColorData[{"DarkRainbow", {-Pi, Pi}}][#] &),
   ColorFunctionScaling -> False, Frame -> False, 
   PlotRangePadding -> 0, ImageMargins -> 0], "Image", 
  RasterSize -> 512];

Plot3D[Abs[f[a + I b]], {a, -5, 5}, {b, -5, 5}, 
 PlotStyle -> Texture[img], Mesh -> None, Lighting -> "Neutral"]

Mathematica graphics

share|improve this answer
    
Perfect, exactly what I was looking for. Thanks. –  Alexander Gruber Feb 6 '13 at 13:20

Similar to halirutans answer you can let DensityPlot determine the "good points", and then ListPlot3D those:

ptsdp = Reap[
    DensityPlot[Arg[f[a + I b]], {a, -5, 5}, {b, -5, 5}, 
     PlotPoints -> 25, ColorFunction -> "DarkRainbow", 
     EvaluationMonitor :> Sow[{a, b}]]][[-1, 1]];
ListPlot3D[({#[[1]], #[[2]], Abs@f[Complex @@ #]}) & /@ ptsdp,
  ColorFunction -> (ColorData[{"DarkRainbow", {-\[Pi], \[Pi]}}][Arg[f[#1 + I #2]]] &),
  ColorFunctionScaling -> False]

This generally has the drawback that the 3D sample points wont get refined further when need be. One possibility would be to Join the points with the ones Plot3D picks.

I was going to use this trick but couldn't figure out the syntax for Plot3D

share|improve this answer
1  
Needs more votes! The fact that you don't have to Rasterize and Texture is, IMO, a major advantage of this approach. –  Oleksandr R. Feb 8 '13 at 0:52

You can add Arg[f] explicitly in the function to plot with ridiculously small coefficient. Then Mathematica will render points as you wish. Also it is good idea to put ExclusionStyle->Automatic to get rid of white lines. Below is your code with these corrections:

Block[{f = BesselI[0, 2 Sqrt[#]]/(1 - #) &},
  Plot3D[Abs[f[a + I b]] + 10^-50 Arg[f[a + I b]] // Evaluate, {a, -5, 
  5}, {b, -5, 5}, PlotPoints -> 35, 
  ColorFunction -> (ColorData[{"DarkRainbow", {-\[Pi], \[Pi]}}][
  Arg[f[#1 + I #2]]] &), ColorFunctionScaling -> False,  
  Mesh -> None, 
  ExclusionsStyle -> Automatic]
]

I also added Evaluate command, then result is plotted slightly faster. No need to increase WorkingPrecision or set up Performance goal. The output is:

enter image description here

There is a little flaw behind the peak, at the cross of blue and red regions. It is cured by increasing the number of PlotPoints, the cost is time of plotting.

share|improve this answer
    
Hey, that's a pretty smart trick. :) +1 –  Alexander Gruber Aug 5 '13 at 4:36

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.