# DensityPlot3D produces weird bubbles

I use DensityPlot3D to plot a 3D function with two minima R1,R2 (roughly the centers of the two blue regions). But as one can see by eyes, these two minima inside the blues are paler than the surroundings. This is unrealistic and misleading since the two minima should have the bluest color.

## Update: The problem is not yet solved at all.

Increasing PlotPoints and OpacityFunction or OpacityFunction->"Image3D", etc., can make the plot less transparent and one cannot see inside (certainly one thus no longer sees the weird pale bubbles...). The two answers below are more or less in this trap. Hiding the defect by making the plot more opaque is NOT what is needed here. I would like to have a plot that is transparent enough to see features inside the bulk but without unreal pale distortions.

w = 0.02; a0 = 1.5; a = {1, 0.9/a0, 0.6/a0};
{R1, R2} = {{-a[[1]] Sqrt[1/4 - (w/(1 - a[[3]]))^2], 0, w/(
1 - a[[3]])}, {a[[1]] Sqrt[1/4 - (w/(1 - a[[3]]))^2], 0, w/(
1 - a[[3]])}};
maxX = 1.2 R2[[1]]; maxY = 0.2; maxZ = 0.2;
V[X_, Y_, Z_] := (X^2/a[[1]] + Y^2/a[[2]] + (Z - w)^2/a[[3]]) - Sqrt[
X^2 + Y^2 + Z^2] + 0.250667;
plot = DensityPlot3D[
Evaluate@V[X, Y, Z], {X, -maxX, maxX}, {Y, -maxY, maxY}, {Z,
R1[[3]] - maxZ, R1[[3]] + maxZ}, PlotRange -> All,
PlotLegends -> Automatic, OpacityFunction -> 0.05,
LabelStyle -> Directive[20], AxesLabel -> {X, Y, Z},
ViewPoint -> {0.7, -2.6, 0.7}, ImageSize -> 700, AspectRatio -> 1/2]

• For any type of plot if you use the default PlotPoints you may miss or obscure features. Try PlotPoints -> 120. However, trying to do analysis based on subtle differences of color shading is likely to be futile. – Bob Hanlon May 24 at 20:30
• You also said OpacityFunction->0.05 and Opacity plays tricks on the eyes. You can see that the default OpacityFunction shows the structure you expect. Moreover, the function will be sampled differently (unless using PlotPoints as @BobHanlon suggests) and this opacity will really screw you over. – b3m2a1 May 24 at 21:12
• @BobHanlon @b3m2a1 Actually I've tried more PlotPoints, but it makes the plot less transparent and one cannot see the feature inside the bulk, which is not good for the visualization purpose. The default OpacityFunction has the same problem. And with more PlotPoints, once you further reduce OpacityFunction, the unrealistic small pale ball reappears. – xiaohuamao May 24 at 21:17
• I'm afraid I don't understand why all of you are using a constant OpacityFunction. What if you use e.g. OpacityFunction -> "Image3D" or OpacityFunction -> (Exp[-9 #] &), if you want a quickly decaying opacity? – J. M.'s technical difficulties May 25 at 17:54
• @J.M.'stechnicaldifficulties Because the ones you suggested are too opaque to see inside. Reduce opacity, you see the defect again. – xiaohuamao May 25 at 18:18

I'm not quite sure what the reason is, but it looks like neither PlotRange -> All nor PlotRange -> Full are correctly capturing the real plot range. It's especially weird to me since the legend seems to say that the range goes from 0 to 0.25.

First I tried SliceDensityPlot3D with PlotPoints -> 120 and PlotRange -> Full to try and see what was happening at those minima.

w = 0.02;
a0 = 1.5;
a = {1, 0.9/a0, 0.6/a0};
{R1, R2} = {
{-a[[1]] Sqrt[1/4 - (w/(1 - a[[3]]))^2], 0, w/(1 - a[[3]])},
{a[[1]] Sqrt[1/4 - (w/(1 - a[[3]]))^2], 0, w/(1 - a[[3]])}
};
maxX = 1.2 R2[[1]];
maxY = 0.2;
maxZ = 0.2;
V[X_, Y_, Z_] := (X^2/a[[1]] + Y^2/a[[2]] + (Z - w)^2/a[[3]]) -
Sqrt[X^2 + Y^2 + Z^2] + 0.250667;
SliceDensityPlot3D[
V[X, Y, Z],
"CenterPlanes",
{X, -maxX, maxX},
{Y, -maxY, maxY},
{Z, R1[[3]] - maxZ, R1[[3]] + maxZ},
PlotPoints -> 120,
MaxRecursion -> 5,
PlotRange -> Full,
PlotLegends -> Automatic,
LabelStyle -> Directive[20],
AxesLabel -> {"X", "Y", "Z"},
ViewPoint -> {0.7, -2.6, 0.7},
ImageSize -> 700,
AspectRatio -> 1/2
]


This shows that the function has 3 holes in it (if you rotate the plot you can see an additional one hidden close to the origin. Your function is looks well-behaved, so it shouldn't have anywhere that evaluates to a complex number or infinity or anything.

So I tried manually specifying PlotRange -> {0, 0.25}. I actually got rid of the PlotPoints because there was one very small point in the orange/white area near the origin that seemed to be excluded. It looks like the maximum occurs at (0, 0, 0) and is about 0.2516667. If you want high plot points, you'll have to extend the plot range a bit further too.

SliceDensityPlot3D[
V[X, Y, Z],
"CenterPlanes",
{X, -maxX, maxX},
{Y, -maxY, maxY},
{Z, R1[[3]] - maxZ, R1[[3]] + maxZ},
MaxRecursion -> 5,
PlotRange -> {0, 0.25},
PlotLegends -> Automatic,
LabelStyle -> Directive[20],
AxesLabel -> {"X", "Y", "Z"},
ViewPoint -> {0.7, -2.6, 0.7},
ImageSize -> 700,
AspectRatio -> 1/2
]


If we apply this same fixe to the original plot:

plot = DensityPlot3D[
Evaluate@V[X, Y, Z],
{X, -maxX, maxX},
{Y, -maxY, maxY},
{Z, R1[[3]] - maxZ, R1[[3]] + maxZ},
PlotRange -> {0, 0.25},
PlotLegends -> Automatic,
PlotPoints -> 120,
OpacityFunction -> 0.05,
LabelStyle -> Directive[20],
AxesLabel -> {X, Y, Z},
ViewPoint -> {0.7, -2.6, 0.7},
ImageSize -> 700,
AspectRatio -> 1/2]


That seems to fix it. The reason it was less blue in the original is because it wasn't plotting anything due to the holes. So the optical density through that part of the graph really was less.

If you haven't checked it out yet, SliceDensityPlot3D and SliceCountourPlot3D have some really cool options in terms of stacked planes, diagonal planes, spheres with octants cut out, or custom surfaces to plot over. I think in a lot of cases, it maybe be more intuitive for understanding 4D plots. They may not be what you need for this particular plot since you are already plotting some other curves along with it, but I think they're worth using when possible!

• The 'fix' doesn't fix anything in DensityPlot3D. You don't see the pales small balls only because PlotPoints -> 120 is high, which makes the plot not quite transparent. You can reduce PlotPoints and see the pale balls again. As I mentioned, I need to see inside the bulk. – xiaohuamao May 25 at 1:39
• @xiaohuamao Oh, dang, I didn't realize that it was so thick I just couldn't see into the centre. I still think the issue might be to do with the PlotRange somehow since that seems to fix the slice plots, but I'm not sure how to force it to display there. – MassDefect May 25 at 1:49
• Yes. Your observation seems quite relevant. Thanks for pointing it out. We really need a fix here... Probably you want to edit your answer or hopefully you can make it work. – xiaohuamao May 25 at 1:53
• @xiaohuamao My other thought was to try ListDensityPlot3D and force it to sample those points by building my own list of points. It has the exact same problem even though my grid is tight enough to sample that area many times. It kinda seems like it might be a bug to me. I don't see any reason it should fail to plot that area. – MassDefect May 25 at 2:14
• This seems to work. data = Flatten[Table[{X, Y, Z, V[X, Y, Z]}, {X, -maxX, maxX, maxX/50}, {Y, -maxY, maxY, maxY/50}, {Z, R1[[3]] - maxZ, R1[[3]] + maxZ, maxZ/50}], 2]; ListDensityPlot3D[data, PlotRange -> {(1/3)*10^-6, 0.251667}, PlotLegends -> Automatic, OpacityFunction -> 0.25, LabelStyle -> Directive[16], AxesLabel -> {X, Y, Z}, ViewPoint -> {0.7, -2.6, 0.7}, ImageSize -> 700, AspectRatio -> 1/2] – Bob Hanlon May 25 at 3:01

If you want to see inside a 3D object, I recommend that you peal back the object to the depth of interest using Manipulate.

Clear["Global*"]

w = 0.02; a0 = 1.5; a = {1, 0.9/a0, 0.6/a0};
{R1, R2} = {{-a[[1]] Sqrt[1/4 - (w/(1 - a[[3]]))^2], 0,
w/(1 - a[[3]])}, {a[[1]] Sqrt[1/4 - (w/(1 - a[[3]]))^2], 0,
w/(1 - a[[3]])}};
maxX = 1.2 R2[[1]]; maxY = 0.2; maxZ = 0.2;
V[X_, Y_, Z_] := (X^2/a[[1]] + Y^2/a[[2]] + (Z - w)^2/a[[3]]) -
Sqrt[X^2 + Y^2 + Z^2] + 0.250667;

Manipulate[
plot = DensityPlot3D[Evaluate@V[X, Y, Z],
{X, -maxX, maxX}, {Y, ymin, maxY}, {Z, R1[[3]] - maxZ, R1[[3]] + maxZ},
PlotRange -> {{-maxX, maxX}, {-maxY, maxY}, {R1[[3]] - maxZ,
R1[[3]] + maxZ}},
PlotLegends -> Automatic,
OpacityFunction -> opac,
LabelStyle -> Directive[16],
AxesLabel -> {X, Y, Z},
ViewPoint -> {0.7, -2.6, 0.7},
ImageSize -> 500,
AspectRatio -> 1/2,
PlotPoints -> 120],
{{opac, 0.75, "OpacityFunction"}, 0, 1, 0.05, Appearance -> "Labeled"},
{{ymin, 0}, -maxY, 0.9 maxY, 0.1 maxY, Appearance -> "Labeled"},
SynchronousUpdating -> False]


• Thanks for this good idea! The problem is I actually have other 3D curves in this plot. I can hardly display them with half of the bulk cut off. – xiaohuamao May 24 at 22:16
• "half of the bulk cut off." The Manipulate enables you to dynamically adjust the depth of inspection, it is not fixed. Also, if appropriate to your needs, you can add controls in the x and z dimensions to provide additional flexibility to inspect different aspects of the structure. – Bob Hanlon May 24 at 22:24
• As far as I've tried, I don't see the pale ball removed by cutting some portion off, as long as the plot is relatively transparent. Your example is a rather opaque case with large PlotPoints`. – xiaohuamao May 24 at 23:51