# Visualization of Bivariate Distributions

I know it is perfectly possible to show the bivariate probability distributions in MMA. But my question is can we show each dimension of distribution in 2D dimension while we are showing the 3D plot? The same as here:

How we can have the 2D histograms in the sides and 3D histogram in between?

• Look up MarginalDistribution[], among other things... Commented Jun 16, 2013 at 6:25
• @0x4A4D with 2D histograms on the sides and 3D histogram in the middle?
– Alex
Commented Jun 16, 2013 at 8:15
• Well, you can use RandomVariate[] to generate random variates from your bivariate distribution, yes, then use Histogram[] on each component of the variates. I'm seeing no 3D histogram, tho; just a point cloud, an enclosing ellipse, and nothing more. Commented Jun 16, 2013 at 8:18
• The more I stare at this plot, the more unstable it becomes -- it keeps flipping in 3D perspective like a Necker cube en.wikipedia.org/wiki/Necker_cube Commented Jun 16, 2013 at 8:52
• In case of 3D histogram important question is: what do You want z-scale to show. Maybe You want different scales for marginal distributions and main 2D distribution, that could be reasonable for clarity of plot.
– Kuba
Commented Jun 16, 2013 at 10:07

You can also try this:

Generate yor data:

data = RandomVariate[\[ScriptD] =
MultinormalDistribution[{0, 0}, {{1, 0.9}, {0.9, 2}}], 10^4];


To improve a little bit the final image, you might want to introduce lighting vectors:

lightSources = {
{"Directional", White,Scaled[{1, 0, 1}]},
{"Directional", White,Scaled[{1, .5, 1}]},
{"Directional", White, Scaled[{.5, 0, 1}]}
};


Create the 3D histogram

G1 = Histogram3D[data, {0.25}, "PDF", ColorFunction -> "Rainbow",
PlotRange -> {{-4, 4}, {-4, 4}, All}, ImageSize -> Medium,
Boxed -> False, Lighting -> lightSources]


Create the individual histograms

G3 = Histogram[Transpose[data][[1]], {-4, 4, .25}, "Probability",
ColorFunction -> Function[{height}, ColorData["Rainbow"][height]],
Axes -> False]
G4 = Histogram[Transpose[data][[2]], {-4, 4, .25}, "Probability",
ColorFunction -> Function[{height}, ColorData["Rainbow"][height]],
Axes -> False]


Show them all together:

G5 = Graphics3D[{EdgeForm[], Texture[G3],
Polygon[{{4, 4, 0}, {-4, 4, 0}, {-4, 4, 0.2}, {4, 4, 0.2}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]},
Axes -> False, Boxed -> False];
G6 = Graphics3D[{EdgeForm[], Texture[G4],
Polygon[{{-4, 4, 0}, {-4, -4, 0}, {-4, -4, 0.2}, {-4, 4, 0.2}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]},
Axes -> False, Boxed -> False];
Show[G1, G5, G6]


EDITED

If you want a strict 2D representation of the data you can try this:

DH = DensityHistogram[data, {-4, 4, .25}, ColorFunction -> "Rainbow", Frame -> False];
GraphicsGrid[{{G3,}, {DH, Rotate[G4, -.5 Pi]}}]


Don't do it!

3D plots on a 2D surface are an anti-pattern for data visualization. The perspective mapping taints the free perceptual processing you get from your visual cortex. Angles are no longer what they seem. The 3D histogram makes things even worse by the way foreground bars obscure other bars -- not only is the data poorly represented: some of it is invisible!

For example, @RodLm's answer shows exactly what you asked for, but can you tell the 3D histogram distribution represents an ellipse?

A couple links on 3D chart junk angle, infovis-wiki peltiertech, and a 2D pic (not from Mathematica).

• ...and now, an answer I can get behind with... Commented Jun 16, 2013 at 15:23
• @xan You can easily show the elliptical relation between the variables by using the CountourPlot[] of your data... You could also use Plot3D[PDF[\[ScriptD], {x, y}], {x, -4, 4}, {y, -4, 4}] to see the continuous version of the plot...
– Rod
Commented Jun 16, 2013 at 15:30
• @Kuba, The question didn't mention interactive use either. I assume you are referring to how through interaction one can tilt and rotate a 3D view to see hidden elements and how movement helps reduce the mental translation of 2D to 3D. Even so, there is some cost to requiring the viewer to interrogate the graphic instead of having a graphic that can speak for itself.
– xan
Commented Jun 16, 2013 at 15:43
• I do agree with You. I just wanted to show it isn't so bad as one could think.
– Kuba
Commented Jun 16, 2013 at 15:58
• Surely there are many other ways besides 3D to view the interaction. A blended point cloud, a heat map (as shown in RodLm's updated answer), a 2D contour plot, a non-parametric density plot, ...
– xan
Commented Jun 18, 2013 at 1:41

I'm going to show method of displaying marginal distributions based on Histogram3D, it has disadvantages, but also a couple of advantages (concise code, tooltip preserved, etc.)

hist[data_, rx_, ry_] :=Show[{
ListPointPlot3D[{##, 0} & @@@ data],
Histogram3D[{#1, ry} & @@@ data, {.2}],
Histogram3D[{-rx, #2} & @@@ data, {.2}, ChartStyle -> Red]},
PlotRange -> {{-rx, rx}, {-7, 7}, All}, AxesEdge -> {{-1, -1}, {1, -1}, {-1, 1}},
FaceGrids -> {{-1, 0, 0}, {0, 0, -1}, {0, 1, 0}},Boxed -> False]

data = RandomVariate[BinormalDistribution[{1, 2}, .8], 10^3];
hist[data, 4, 7]


The most important thing is xan's answer. I agree with that point but I do not consider Alex's question useless.

The issue discussed in comments was about z-scale. Marginal distributions are 1D while real data distribution is 2D. Integrals/bin counting/counts per bin differ for them. So the question is, what do we want to show.

I could set "Count" for each, z-scale tells the truth but Histogram3D looks a little bit flat:

Histogram/Histogram3D gives us ability to manage bins/values through PureFunctions in place of 2nd and 3rd argument of them (details in Help). We can rescale number of counts:

Histogram3D[data, {.2}, Function[{x, y, z}, t z] (*t is scale factor*)


Caution: z axis now is related to marginal distributions only! What I wanted to show is this functionality.

At the end I decided that if we want to focus on shapes of distributions the best solution is to normalize each distribution at bin with maximum value of counts. It can be easily applied with previous functionality with function:

Function[{x, y, z}, z/Max@z]


One should keep in mind that normalization factor is different for each distribution.

• nice job with less code.Thank you all cause I am learning a lot.
– Alex
Commented Jun 16, 2013 at 10:36
• About Z scale if we are going to have the "Probability" then it would be alright?Right?
– Alex
Commented Jun 16, 2013 at 14:36
• @Alex No I don't think so. Take a look at simpler case of uniform distrubution. If we divide it on 10x10 bins then each bin will have value 1/100 for "Probability" while marginal distributions would have 1x10 bins -> 1/10 for each, so the scale is different.
– Kuba
Commented Jun 16, 2013 at 14:46
• Yes.but look at the Rod Lm response.It shows the probability on the axes.Yours code shows the number of data in histogram not "Probability".Then your case from scale point of view is more complicated.Am I right?
– Alex
Commented Jun 16, 2013 at 14:52
• @Alex z-axis on his plot is related to Histogram3D. Marginal distributions fit to it because texture which they are is rescaled to fit the box. Try , Axes -> True in G3 and G4 and see the real values. So the plot looks good at the end but it would be hard to name z-axis related to those histograms.
– Kuba
Commented Jun 16, 2013 at 15:10

First you determine the binormal distribution of the data:

data = RandomVariate[BinormalDistribution[{1, 0}, {2.5, 5}, 0], 10^4];
dataX = data[[All, 1]];
dataY = data[[All, 2]];
dist = EstimatedDistribution[data,
BinormalDistribution[{Subscript[μ, 1], Subscript[μ,
2]}, {Subscript[σ, 1], Subscript[σ, 2]}, ρ]]
distX = EstimatedDistribution[dataX,
NormalDistribution[μ, σ]]
distY = EstimatedDistribution[dataY,
NormalDistribution[μ, σ]]


Then you draw the plots for $x$ and $y$ distribution and the contour plot:

x = Show[
Histogram[dataX, 20, "PDF", PlotRange -> {{-20, 20}, {-.005, .25}},
Axes -> False, PlotRangePadding -> 0, AspectRatio -> 1/2],
Plot[PDF[distX, x], {x, -20, 20},
PlotStyle -> Directive[{Thick, Blue}]]]
y = Show[
Histogram[dataY, 20, "PDF", PlotRange -> {{-20, 20}, {-.005, .25}},
Axes -> False, PlotRangePadding -> 0, AspectRatio -> 1/2],
Plot[PDF[distY, x], {x, -20, 20},
PlotStyle -> Directive[{Thick, Red}]]]
c = ContourPlot[
PDF[dist, {x, y}] == .00001, {x, -20, 20}, {y, -20, 20},
Epilog -> {PointSize[Small], Point /@ data}, PlotPoints -> 50,
Frame -> False, ContourStyle -> Directive[{Thick, Green}]]


Finally, combine it all together:

pp1 = Graphics3D[{EdgeForm[], Texture[x],
Polygon[{{-20, 20, 0}, {20, 20, 0}, {20, 20, .25}, {-20,
20, .25}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}];
pp2 = Graphics3D[{EdgeForm[], Texture[y],
Polygon[{{-20, -20, 0}, {-20, 20, 0}, {-20,
20, .25}, {-20, -20, .25}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}];
pp3 = Graphics3D[{EdgeForm[], Texture[c],
Polygon[{{-20, -20, 0}, {20, -20, 0}, {20, 20, 0}, {-20, 20, 0}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}];

Graphics3D[{pp1[[1]], pp2[[1]], pp3[[1]]},
Lighting -> {{"Ambient", White}}, BoxRatios -> {1, 1, 1/2},
Boxed -> False, Axes -> True, PlotRangePadding -> 0,
ViewPoint -> {2, -2, 1}, ImageSize -> 600]


The result:

I'm not sure if MMA can do isometric projections.