# 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... – J. M. Jun 16 '13 at 6:25
@0x4A4D with 2D histograms on the sides and 3D histogram in the middle? – Alex Jun 16 '13 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. – J. M. Jun 16 '13 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 – bill s Jun 16 '13 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 Jun 16 '13 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... – J. M. Jun 16 '13 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 Jun 16 '13 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 Jun 16 '13 at 15:43
I do agree with You. I just wanted to show it isn't so bad as one could think. – Kuba Jun 16 '13 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 Jun 18 '13 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 Jun 16 '13 at 10:36
About Z scale if we are going to have the "Probability" then it would be alright?Right? – Alex Jun 16 '13 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 Jun 16 '13 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 Jun 16 '13 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 Jun 16 '13 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.

-