incorporate standalone legend in ggpairs (take 2)
<p><strong>tl;dr</strong> can't get a standalone legend (describing common colours across the whole plot) in <code>ggpairs</code> to my satisfaction.</p>

<p>Sorry for length.</p>

<p>I'm trying to draw a (lower-triangular) pairs plot using <code>GGally::ggpairs</code> (an extension package for drawing various kinds of plot matrices with <code>ggplot2</code>).  This is essentially the same question as <a href="https://stackoverflow.com/questions/22945702/how-to-add-an-external-legend-to-ggpairs">How to add an external legend to ggpairs()?</a> , but I'm not satisfied with the answer to that question aesthetically, so I'm posting this as an extension (if suggested/recommended by commenters, I will delete this question and offer a bounty on that question instead).  In particular, I would like the legend to appear <em>outside</em> the sub-plot frame, either putting it within one virtual subplot but allowing additional width to hold it, or (ideally) putting it in a separate (empty) subplot.  As I show below, both of my partial solutions have problems.</p>

<p>Fake data:</p>

<pre><code>set.seed(101)
dd &lt;- data.frame(x=rnorm(100),
                 y=rnorm(100),
                 z=rnorm(100),
                 f=sample(c("a","b"),size=100,replace=TRUE))
library(GGally)
</code></pre>

<p>Base plot function:</p>

<pre><code>ggfun &lt;- function(...) {
   ggpairs(dd,mapping = ggplot2::aes(color = f),
    columns=1:3,
    lower=list(continuous="points"),
    diag=list(continuous="blankDiag"),
    upper=list(continuous="blank"),
    ...)
}
</code></pre>

<p>Function to trim top/right column:</p>

<pre><code>trim_gg &lt;- function(gg) {
    n &lt;- gg$nrow
    gg$nrow &lt;- gg$ncol &lt;- n-1
    v &lt;- 1:n^2
    gg$plots &lt;- gg$plots[v&gt;n &amp; v%%n!=0]
    gg$xAxisLabels &lt;- gg$xAxisLabels[-n]
    gg$yAxisLabels &lt;- gg$yAxisLabels[-1]
    return(gg)
}

gg0 &lt;- trim_gg(ggfun(legends=TRUE))
</code></pre>

<p>Get rid of legends in left column (as in the linked question above):</p>

<pre><code>library(ggplot2)  ## for theme()
for (i in 1:2) {
   inner &lt;- getPlot(gg0,i,1)
   inner &lt;- inner + theme(legend.position="none")
   gg0 &lt;- putPlot(gg0,inner,i,1)
}
inner &lt;- getPlot(gg0,2,2)
inner &lt;- inner + theme(legend.position="right")
gg0 &lt;- putPlot(gg0,inner,2,2)
</code></pre>

<p><a href="https://i.stack.imgur.com/WOUua.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/WOUua.png" alt="enter image description here"></a></p>

<p><strong>Problems</strong>:</p>

<ul>
<li>the blank panel behind the legend is actually masking some points; I don't know why it's not outside the panel as usual, I assume that's something that <code>ggpairs</code> is doing</li>
<li>if it were outside the panel (on top or to the right), I would want to make sure to leave some extra space so the panels themselves were all the same size. However, <code>ggmatrix</code>/<code>ggpairs</code> looks very inflexible about this.</li>
</ul>

<p>The only alternative I've been able to try to far is following <a href="https://stackoverflow.com/questions/12539348/ggplot-separate-legend-and-plot">ggplot separate legend and plot</a> by extracting the legend and using <code>gridExtra::grid.arrange()</code>:</p>

<pre><code>g_legend &lt;- function(a.gplot){
   tmp &lt;- ggplot_gtable(ggplot_build(a.gplot))
   leg &lt;- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
   legend &lt;- tmp$grobs[[leg]]
   return(legend)
}

library(gridExtra)
grid.arrange(getPlot(gg0,1,1),
             g_legend(getPlot(gg0,2,2)),
             getPlot(gg0,2,1),
             getPlot(gg0,2,2)+theme(legend.position="none"),
   nrow=2)
</code></pre>

<p><a href="https://i.stack.imgur.com/AE7dL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AE7dL.png" alt="enter image description here"></a></p>

<p><strong>Problems</strong>:</p>

<ul>
<li>the axes and labels suppressed by <code>ggpairs</code> are back ...</li>
</ul>

<p>I also considered creating a panel with a special plot that contained only the legend (i.e. trying to use <code>theme(SOMETHING=element.blank)</code> to suppress the plot itself, but couldn't figure out how to do it.</p>

<p>As a last resort, I could trim the axes where appropriate myself, but this is practically reinventing what <code>ggpairs</code> is doing in the first place ...</p>