grid.arrange with QICharts - r

I am trying to arrange multiple charts from qicharts. With some work I got it so grid.arrange would do anything, but it just shows the last item as opposed to both.
library(qicharts)
library(grid)
library(gridExtra)
y <- rnorm(24, 12, 3)
a <- qic(y,chart="i")
b <- qic(y,chart="mr")
grid.arrange(grob(plot(a)),grob(plot(b)))

qicharts:::plot.qic suggests that it relies on base graphics, so the drawing happens immediately on the device and the plot itself is not stored. You could use base functions such as par(mfrow) to arrange multiple plots side by side, or convert those base graphics objects to grob e.g. with the gridGraphics package.
Alternatively, the trellis-based function tcc might produce similar output, and can be used with grid.arrange,
grid.arrange(tcc(rnorm(24)), tcc(rnorm(24)))

Related

Multiple plots are not rendered as described by layout.show

Using the raster package and its plot function, I want to arrange six plots of Raster* objects in 2 rows and 3 columns, by columns. Therefore I set up my layout like this:
layout(mat=matrix(1:6, nrow=2, ncol=3), heights=c(1,1), widths=c(2,1,1))
Calling layout.show(6) results in this preview, which is exactly what I want:
However, after the first plot being placed where the 1 is (as expected), the second plot is placed where the 3 is (not as expected). Why's that?
When I then call layout.show(6) again, I get this, which is NOT what I want:
Interestingly, using par(mfcol=c(2,3)) instead of layout also placed the plots by row (i.e. behaved like mfrow).
(I'm aware I could just rearrange the order of plot calls, but I want to know why this doesn't work as I expect it to.)
You cannot do this with plot(Raster*) as that sets the layout itself; thus overwriting your settings. Instead of plot(x) you could use image(x), but then you do not get a legend.
Perhaps the best approach is to use the terra package instead (terra is the replacement for raster)
f <- system.file("ex/elev.tif", package="terra")
r <- rast(f)
layout(mat=matrix(1:6, nrow=2, ncol=3), heights=c(1,1), widths=c(2,1,1))
plot(r)
plot(r*2)
plot(r*3)
plot(r*4)
plot(r*5)
plot(r*6)

Tiled Plot using plot.kmeans function

I am trying to create a tiled plot using plot.kmeans functions from the package "useful". This can be done very easily for base plot function using par() or layout(), or in ggplot using facests. I want to visualize results of various runs of kmeans with different number of clusters using plot or plot.kmeans function from the package "useful". I have tried par() and layout(), but I only get one plot not multiple plots.
Consider the following code segment:
results1 <- kmeans(x=dataset1,centers=5,nstart = 25)
results2 <- kmeans(x=dataset2,centers=5,nstart = 25)
par(mfrow=c(2,1))
plot.kmeans(results1,dataset1)
plot.kmeans(results2,dataset2)
I have two datasets and apply kmeans on them separately. I want to draw results of both datasets side by side. plot.kmeans is good function to see results of clustering. But somehow i feel that we cannot two or more plots side by side like we do in case of base plotting facility. If instead of plot.kmeans, I use base plot functions it will work. So thats my problem in brief.
Thanks.
The function plot.kmeans from the package "useful" (not to be confused with general qualifier 'a useful package) returns a ggplot2 object. These do not work with par() or layout().
Look instead at grid.arrange from the "gridExtra" package:
results1 <- kmeans(x=dataset1,centers=5,nstart = 25)
results2 <- kmeans(x=dataset2,centers=5,nstart = 25)
library(gridExtra)
p1 <- plot.kmeans(results1,dataset1)
p2 <- plot.kmeans(results2,dataset2)
grid.arrange(p1, p2, ncol=2)

Unexpected behavior using cbind with edited ggplotGrobs

I've been trying to edit some plots created by ggplot2 using the functions provided by the packages grid and gridExtra. I realize that ggplot2 alone can make some really nice multifaceted plots. However, in some instances I like to create individual plots and then combine then together later on. While trying to do just that, I came across some unexpected behavior using cbind() with grid.draw() or grid.arrange() when using a ggplot2 graph that had been edited. Below is the code for an MWE:
#Load libraries
library(ggplot2); library(gridExtra)
#Load data
data(mtcars)
#Ggplot
p = qplot(wt,mpg,data=mtcars,color=cyl)
grob = ggplotGrob(p)
#Bold xlabel
grobEdited = editGrob(grid.force(grob),gPath("xlab","GRID.text"),grep=TRUE,gp=gpar(fontface="bold"))
#Visualize
grid.newpage()
grid.draw(grobEdited)
It worked as expected. Now to illustrate the issue, lets cbind() two of the same edited ggplot2 graphs:
#Cbind example with edited graphs
grid.newpage()
grid.draw(cbind(grobEdited,grobEdited))
It didn't work as expected! Now test cbind() on the unedited graphs:
#Cbind example with grob
grid.newpage()
grid.draw(cbind(grob,grob))
Works as expected. I'm new to gridded figures, so is there something I'm doing wrong?
I'm posting an answer following the comment from #user20650. The easiest workaround is to cbind() the ggplot2 graphs before editing them using the editing functions provided by grid or gridExtra:
#Edit after cbind()
grobEdited = editGrob(grid.force(cbind(grob,grob)),gPath("xlab","GRID.text"),global=TRUE,grep=TRUE,gp=gpar(fontface="bold"))
#Visualize
grid.newpage()
grid.draw(grobEdited)

Saving a graph with ggsave after using ggplot_build and ggplot_gtable

I am modifying a graph built with ggplot by altering the data produced by ggplot_build (for a reason similar to Include space for missing factor level used in fill aesthetics in geom_boxplot). As far as I understand the help I found on this topic, I should be able to save the result by applying ggplot_gtable and arrangeGrob before calling ggsave on the results (Saving grid.arrange() plot to file).
However I obtain an error "plot should be a ggplot2 plot", also with this simple reproductible example:
require('ggplot2')
require('gridExtra')
df <- data.frame(f1=factor(rbinom(100, 1, 0.45), label=c("m","w")),
f2=factor(rbinom(100, 1, 0.45), label=c("young","old")),
boxthis=rnorm(100))
g <- ggplot(aes(y = boxthis, x = f2, fill = f1), data = df) + geom_boxplot()
dd <- ggplot_build(g)
# Printing the graph works:
print(arrangeGrob(ggplot_gtable(dd)))
# Saving the graph doesn't:
ggsave('test.png',arrangeGrob(ggplot_gtable(dd)))
Can anybody explain why this does not work ? Is there a way to use ggsave after modifying the data by using ggplot_build() ?
(My version of the packages are gridExtra_0.9.1 and ggplot2_0.9.3.1)
it does not work because ggsave wants an object of class ggplot, while you're passing a grob. arrangeGrob will sometimes trick ggsave in pretending inheritance from ggplot, but only when at least one of the grobs belongs to this class; here, however, you're only passing a gtable.
Perhaps the easiest workaround is to clone ggsave and bypass the class check,
ggsave <- ggplot2::ggsave; body(ggsave) <- body(ggplot2::ggsave)[-2]
Edit: The dev version of ggplot2 no longer requires this hack*, as ggsave now works with any grob.
*PS: this hack works no longer, as arrangeGrob now returns a gtable, and its print method does not draw on a device.
A work around is to plot the gtable object with grid.draw() and then use dev.copy() to transfer the plot to a file.
Remember to use also dev.off() just afterward.

Kernel density plots on a single figure

I have been trying to plot simple density plots using R as:
plot(density(Data$X1),col="red")
plot(density(Data$X2),col="green")
Since I want to compare, I'd like to plot both in one figure. But 'matplot' doesn't work!! I also tried with ggplot2 as:
library(ggplot2)
qplot(Data$X1, geom="density")
qplot(Data$X2, add = TRUE, geom="density")
Also in this case, plots appear separately (though I wrote add=TRUE)!! Can anyone come up with an easy solution to the problem, please?
In ggplot2 or lattice you need to reshape the data to seupose them.
For example :
dat <- data.frame(X1= rnorm(100),X2=rbeta(100,1,1))
library(reshape2)
dat.m <- melt(dat)
Using ``lattice`
densityplot(~value , groups = variable, data=dat.m,auto.key = T)
Using ``ggplot2`
ggplot(data=dat.m)+geom_density(aes(x=value, color=variable))
EDIT add X1+X2
Using lattice and the extended formua interface, it is extremely easy to do this:
densityplot(~X1+X2+I(X1+X2) , data=dat) ## no need to reshape data!!
You can try:
plot(density(Data$X1),col="red")
points(density(Data$X2),col="green")
I must add that the xlim and ylim values should ideally be set to include ranges of both X1 and X2, which could be done as follows:
foo <- density(Data$X1)
bar <- density(Data$X2)
plot(foo,col="red", xlim=c(min(foo$x,bar$x),max(foo$x,bar$x)) ylim=c(min(foo$y,bar$y),max(foo$y,bar$y))
points(bar,col="green")
In base graphics you can overlay density plots if you keep the ranges identical and use par(new=TRUE) between them. I think add=TRUE is a base graphics strategy that some functions but not all will honor.
If you specify n, from, and to in the calls to density and make sure that they match between the 2 calls then you should be able to use matplot to plot both in one step (you will need to bind the 2 sets of y values into a single matrix).

Resources