4
$\begingroup$

The built-in function PairwiseScatterPlot has been discussed for example here: Scatterplots for subsets of multivariate data [Updated]. However, I find it not very informative to plot the identity function along the diagonal of the matrix of plots: do you guys know how to plot a more informative histogram instead? Also, it is superfluous to plot the entries above the diagonal.

Here is an example:

Needs["StatisticalPlots`"]
Needs["MultivariateStatistics`"]
data = RandomReal[MultinormalDistribution[{0, 0, 0}, {{1, 1/2, -2/3}, {1/2, 5, 2}, {-2/3, 2, 20}}], 10^3];
PairwiseScatterPlot[data, DataTicks -> Automatic, DataLabels -> {"var1", "var2", "var3"}]

enter image description here

UPDATE: I have improved the code a user wrote as a possible solution (unfortunately that user deleted that entry). Basically I have fixed a bug and the labels. Here is what it does:

pspF3 = With[{dt = #, ca = ConstantArray[Null, {#, #} &@Dimensions[#][[2]]],
opts = Sequence[AspectRatio -> 1, Frame -> True]}, 
GraphicsGrid[ReplacePart[ca, {{i_, i_} :> Histogram[dt[[All, i]], Automatic, "PDF", opts, 
     If[i == Dimensions[dt][[2]], FrameLabel -> {"var" <> ToString[i], None}, FrameLabel -> None],
PlotRange -> All, Ticks -> Automatic],
{i_, j_} /; i > j :> ListPlot[dt[[All, {j, i}]], opts,
Which[i == Dimensions[dt][[2]] && j > 1, FrameLabel -> {{None, None}, {"var" <> ToString[j], None}}, i == Dimensions[dt][[2]] && j == 1, FrameLabel -> {{"var" <> ToString[i], None}, {"var" <> ToString[j], None}}, i > 1 && j == 1, FrameLabel -> {{"var" <> ToString[i], None}, {None, None}}, i > j, FrameLabel -> {None, None}],
RotateLabel -> True,PlotRange -> All]}], ImageSize -> 600]] &;
pspF3@data

enter image description here

However, the ticks are not aligned and the labels of the ticks are repeated when not necessary (they should appear only at the very bottom and on the left). Also, the size of the various frames is not constant and ideally there should not be gaps. PairwiseScatterPlot does all this automatically. Can you improve on this solution?

$\endgroup$
  • $\begingroup$ One approach is to build your own grid of plots based on GraphicsGrid or Grid. Reproduce the six off-diagonal plots using ListPlot, and use Histogram or whatever else you like for the three diagonal plots. $\endgroup$ – bbgodfrey Dec 27 '14 at 16:31
9
$\begingroup$

Update 3: Using the function pwScatterPlot from this answer

ClearAll[addHistograms, pwScatterPlot]       
addHistograms = Module[{diag = Diagonal[Partition[Cases[#, {dir_, ___Point} :> dir, All], 
    Round @ PlotRange[#][[1, 2]]]]}, 
 # /. {c : Alternatives @@ diag, p__Point} :> Module[{xy = Cases[{p}, Point[x_] :> x]}, 
   Inset[Histogram[xy[[All, 1]], ChartStyle->c, AspectRatio->1/GoldenRatio, Axes -> False], 
     Min /@ Transpose@xy, {Left, Bottom}, {.9, .9}]]] &; 

Needs["StatisticalPlots`"]
pwScatterPlot = addHistograms @* PairwiseScatterPlot;

To use this function on an input data with n series we need to use an n-by-n matrix of styles where the diagonal entries are different from off-diagonal entries.

data2 = RandomReal[MultinormalDistribution[{0, 1, 2}, 
    {{1, 1/2, 1/3}, {1/2, 2, 1/3}, {1/3, 1/3, 3}}], 10^3];
labels2 = "var" <> ToString[#] & /@ {1, 2, 3};
colors2 = {{Red, Blue, Green}, {Blue, Orange, Magenta}, {Green, Magenta, Purple}};

pwScatterPlot[data2, DataSpacing -> .1, DataTicks -> Automatic, 
   DataLabels -> labels2, ImageSize -> 500, PlotStyle -> colors2]

enter image description here

Original answer:

pspF = With[{dt=#,ca=ConstantArray[1,{#,#}&@Dimensions[#][[2]]],
             opts=Sequence[Axes->False,AspectRatio->1]},
           Grid[ReplacePart[ca, {{i_,i_}:>Histogram[dt[[All,i]],opts],
                {i_,j_}:>ListPlot[dt[[All,{i,j}]],opts]}],
               Dividers->All]]&;

 data1 = RandomReal[MultinormalDistribution[{0, 0}, {{1, 1/2}, {1/2, 1}}], 10^2];
 pspF@data1

enter image description here

data2 = RandomReal[MultinormalDistribution[{0, 0,0}, 
                   {{1, 1/2,1/3}, {1/2, 2,1/3},{1/3,1/3,3}}], 10^3];

pspF@data2

enter image description here

Update 1: Using DensityHistogram with the option Method -> {"DistributionAxes"->True}:

dhF=With[{dt=#,ca=ConstantArray[1,{#,#}&@Dimensions[#][[2]]],
          opts=Sequence[Axes->False,AspectRatio->1]},
       Grid[ReplacePart[ca, {{i_,i_}:>Histogram[dt[[All,i]],opts],
            {i_,j_}:>DensityHistogram[dt[[All,{i,j}]],opts,
                      Frame->False,Method->{"DistributionAxes"->True},
                      ChartElementFunction->"Point"]}],
            Dividers->All]]&; 

data2 = RandomReal[MultinormalDistribution[{0, 0,0},
                   {{1, 1/2,1/3}, {1/2, 2,1/3},{1/3,1/3,3}}], 10^3];

dhF@data2

enter image description here

Note: You can also use "BoxWhisker", "Histogram" or "SmoothHistogram" as the setting for the suboption "DistributionAxes".

Update 2: To include PlotLabels, FrameLabels, FrameTicks etc, add these options to Histogram and/or to ListPlot:

pspF2 = With[{dt = #, ca = ConstantArray[1, {#, #} &@Dimensions[#][[2]]], 
     pr = Through[{Min, Max}[#]], opts = Sequence[AspectRatio -> 1, Frame -> True]}, 
    Grid[ReplacePart[ca, 
        {{i_, i_} :> Histogram[dt[[All, i]], Automatic, "Count", opts, 
         PlotRange -> {pr, Automatic},
         FrameLabel -> {{"Count", None}, {"var" <> ToString[i], None}},
         PlotLabel -> ("var" <> ToString[i])], {i_, j_} :> 
        ListPlot[dt[[All, {i, j}]], opts, PlotRange -> {pr, pr}, 
         FrameLabel -> {{"var" <> ToString[i], None}, {"var" <> ToString[j], None}}, 
         PlotLabel -> ("var" <> ToString[i] <> "     versus   var" <> 
            ToString[j])]}], Dividers -> All]] &;

data2 = RandomReal[MultinormalDistribution[{0, 1, 2}, 
          {{1, 1/2, 1/3}, {1/2, 2, 1/3}, {1/3, 1/3, 3}}], 10^3];

pspF2@data2

enter image description here

$\endgroup$
  • $\begingroup$ thanks! Is it possible to also include DataLabels and DataTicks? $\endgroup$ – Valerio Dec 28 '14 at 23:09
  • $\begingroup$ @Valerio, please see the update. $\endgroup$ – kglr Dec 28 '14 at 23:46
  • $\begingroup$ thanks but the labels should appear only on the outer frames and so the numbers associated with the ticks (see my updated plot). Also, if I test pspF2 with data of my example (I've changed the covariance matrix to make obvious which is var1 and which is var2) I get the wrong ordering, that is the columns do not have the same variables for the various x-axes: to have the right ordering I have to transpose the matrix. $\endgroup$ – Valerio Dec 29 '14 at 23:40
  • $\begingroup$ @Valerio, just saw your update with a specific example of what you need. I am afraid we need a more elaborate function than pspF to get a full-fledged trellis display like the example in the linked article. Deleting for now until I find a better approach. $\endgroup$ – kglr Dec 29 '14 at 23:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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