R: Remove border when plotting with ggplot2 + ggExtra + cowplot - r

I couldn't find the way not to plot the outer frame when combining graphs through ggplot2 + ggExtra + cowplot. I am not sure where I have to tell R, but suspect the issue to lie in ggExtra. Here is an example:
require(ggplot2)
require(cowplot)
require(ggExtra)
# Creat a graph
A <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) + geom_point(size = 2.5)
# Add marginal histogram
B <- ggExtra::ggMarginal(A,type = 'histogram', margins = 'x', size = 9)
# Combine through cowplot
combo <- plot_grid(B,B,labels=c("A","B"))
plot(combo) # looks fine
# Re-combine through cowplot
plot_grid(B,combo,ncol=1,rel_heights = c(2,3)) # that's where I got an unwanted nasty frame around 'combo'
Any hint would be greatly appreciated!

p <- plot_grid(B,combo,ncol=1,rel_heights = c(2,3))
p <- p + panel_border(remove = TRUE)
https://rdrr.io/cran/cowplot/man/panel_border.html

Related

Combining two graphs with different x axis in R

I'm trying to combine a bar chart and line chart by using ggplot. The problem is, the x axis of bar chart is shop names while the x axis of line chart is date. Graphs look like this:
g1 <- ggplot(plot_data, aes(x=shop, y=conversion_rate)) +
geom_bar(stat="identity", position=position_dodge())
g2 <- ggplot() + geom_line(plot_data_mean, mapping = aes(x=date, y=conversion_rate_average))
Is there a way to combine these two graphs?
You can use the cowplot package to achieve this. Especially the cowplot::plot_grid() function allows for many customizations of the output plot
library(ggplot2)
library(cowplot)
p1 <- ggplot() +
geom_point(aes(x = runif(n = 10), y = runif(n = 10)))
p2 <- ggplot() +
geom_line(aes(x = runif(n = 10), y = runif(n = 10)))
p_combined <- cowplot::plot_grid(p1, p2, labels = c("A)", "B)"))

Removing the borders in geom_boxplot in ggplot2

This should seem relatively straightforward but I can't find an argument which would allow me to do this and I've searched Google and Stack for an answer.
Sample code:
library(ggplot2)
library(plotly)
dat <- data.frame(cond = factor(rep(c("A","B"), each=200)), rating = c(rnorm(200),rnorm(200, mean=.8)))
p <- ggplot(dat, aes(x=cond, y=rating, fill=cond)) + geom_boxplot()
p <- ggplotly(p)
This outputs the first graph, I would want something like the second.
I tried including colour=cond but that gets rid of the median.
Two possible hacks for consideration, using the same dataset as Marco Sandri's answer.
Hack 1. If you don't really need it to work in plotly, just static ggplot image:
ggplot(dat, aes(x=cond, y=rating, fill=cond)) +
geom_boxplot() +
geom_boxplot(aes(color = cond),
fatten = NULL, fill = NA, coef = 0, outlier.alpha = 0,
show.legend = F)
This overlays the original boxplot with a version that's essentially an outline of the outer box, hiding the median (fatten = NULL), fill colour (fill = NA), whiskers (coef = 0) & outliers (outlier.alpha = 0).
However, it doesn't appear to work well with plotly. I've tested it with the dev version of ggplot2 (as recommended by plotly) to no avail. See output below:
Hack 2. If you need it to work in plotly:
ggplot(dat %>%
group_by(cond) %>%
mutate(rating.IQR = case_when(rating <= quantile(rating, 0.3) ~ quantile(rating, 0.25),
TRUE ~ quantile(rating, 0.75))),
aes(x=cond, y=rating, fill=cond)) +
geom_boxplot() +
geom_boxplot(aes(color = cond, y = rating.IQR),
fatten = NULL, fill = NA)
(ggplot output is same as above)
plotly doesn't seem to understand the coef = 0 & output.alpha = 0 commands, so this hack creates a modified version of the y variable, such that everything below P30 is set to P25, and everything above is set to P75. This creates a boxplot with no outliers, no whiskers, and the median sits together with the upper box limit at P75.
It's more cumbersome, but it works in plotly:
Here is an inelegant solution based on grobs:
set.seed(1)
dat <- data.frame(cond = factor(rep(c("A","B"), each=200)),
rating = c(rnorm(200),rnorm(200, mean=.8)))
library(ggplot2)
library(plotly)
p <- ggplot(dat, aes(x=cond, y=rating, fill=cond)) + geom_boxplot()
# Generate a ggplot2 plot grob
g <- ggplotGrob(p)
# The first box-and-whiskers grob
box_whisk1 <- g$grobs[[6]]$children[[3]]$children[[1]]
pos.box1 <- which(grepl("geom_crossbar",names(box_whisk1$children)))
g$grobs[[6]]$children[[3]]$children[[1]]$children[[pos.box1]]$children[[1]]$gp$col <-
g$grobs[[6]]$children[[3]]$children[[1]]$children[[pos.box1]]$children[[1]]$gp$fill
# The second box-and-whiskers grob
box_whisk2 <- g$grobs[[6]]$children[[3]]$children[[2]]
pos.box2 <- which(grepl("geom_crossbar",names(box_whisk2$children)))
g$grobs[[6]]$children[[3]]$children[[2]]$children[[pos.box2]]$children[[1]]$gp$col <-
g$grobs[[6]]$children[[3]]$children[[2]]$children[[pos.box2]]$children[[1]]$gp$fill
library(grid)
grid.draw(g)
P.S. To my knowledge, the above code cannot be used for generating plotly graphs.

How to number a figure using ggplot2

For the general plot in R, legend is used to number a figure.
set.seed(100)
Mydata=rnorm(65)
Year=1950:2014
plot(x=Year,y=Mydata,type = "l")
legend("topleft","(a)",bty = "n")
I wonder how we can do the same thing using ggplot2. Thanks.
Using grid it can be done independently of the data:
library(ggplot2)
qplot(Year, Mydata, geom = "line")
library(grid)
grid.text("(a)", 0.15, 0.85)
As of version 2.2.0, ggplot2 allows to plot subtitles and captions which can be utilized for this purpose.
subtitle (top left)
# create data frame as required by ggplot2
mydf <- data.frame(Year, Mydata)
library(ggplot2)
p <- ggplot(mydf, aes(Year, Mydata)) +
geom_line()
# plot subtitle (top left)
p + labs(subtitle = "(a)")
caption (bottom right)
# plot caption (bottom right)
p + labs(caption = "(a)")
A way with annotate:
library(ggplot2)
set.seed(100)
Mydata=rnorm(65)
Year=1950:2014
data <- data.frame(Mydata = Mydata, Year = Year)
#plot
ggplot(data, aes(Year, Mydata)) +
geom_line() +
annotate('text', x = 1960, y = 2, label = '(a)')
Output:

Setting width in gtable object collapses plot; this used to work but it doesn't anymore.

The following code used to work but doesn't anymore. Does anybody have an idea what's going on? It must be some change in the underlying gtable code.
require(cowplot) # for plot_grid()
require(grid) # for unit_max()
# make two plots
plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() + facet_grid(. ~ Species) + stat_smooth(method = "lm") +
background_grid(major = 'y', minor = "none") +
panel_border()
plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) +
geom_point(size=2.5)
g.iris <- ggplotGrob(plot.iris) # convert to gtable
g.mpg <- ggplotGrob(plot.mpg) # convert to gtable
iris.widths <- g.iris$widths[1:3] # extract the first three widths,
# corresponding to left margin, y lab, and y axis
mpg.widths <- g.mpg$widths[1:3] # same for mpg plot
max.widths <- unit.pmax(iris.widths, mpg.widths) # calculate maximum widths
g.iris$widths[1:3] <- max.widths # assign max. widths to iris gtable
g.mpg$widths[1:3] <- max.widths # assign max widths to mpg gtable
plot_grid(g.iris, g.mpg, labels = "AUTO", ncol = 1)
The resulting plot is the following:
What it should look like is this (with the y axis lines perfectly aligned vertically):
The error seems to happen in this line:
g.iris$widths[1:3] <- max.widths
Any insight would be appreciated.
Note that similar solutions have been used for a long time, see e.g. here. And the plot_grid() function in cowplot uses code like this also to align plots, and it still works. So this has me completely mystified.
Edit
With grid version 3.3.0, this is no longer an issue. That is, the lines of code containing grid:::unit.list() below can be deleted.
The issue is to do with the way units are set. Look at g.iris$widths. You'll notice that the numerals are there but the units have been dropped. See this question and answer, and this one. After converting the plots to gtables, you need: g.iris$widths = grid:::unit.list(g.iris$widths)
require(grid) # for unit_max()
require(cowplot)
# make two plots
plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() + facet_grid(. ~ Species) + stat_smooth(method = "lm") +
background_grid(major = 'y', minor = "none") +
panel_border()
plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) +
geom_point(size=2.5)
g.iris <- ggplotGrob(plot.iris) # convert to gtable
g.mpg <- ggplotGrob(plot.mpg) # convert to gtable
g.iris$widths = grid:::unit.list(g.iris$widths)
g.mpg$widths = grid:::unit.list(g.mpg$widths)
iris.widths <- g.iris$widths[1:3] # extract the first three widths,
# corresponding to left margin, y lab, and y axis
mpg.widths <- g.mpg$widths[1:3] # same for mpg plot
max.widths <- unit.pmax(iris.widths, mpg.widths) # calculate maximum widths
g.iris$widths[1:3] <- max.widths # assign max. widths to iris gtable
g.mpg$widths[1:3] <- max.widths # assign max widths to mpg gtable
plot_grid(g.iris, g.mpg, labels = "AUTO", ncol = 1)

ggplot2 Scatter Plot Labels

I'm trying to use ggplot2 to create and label a scatterplot. The variables that I am plotting are both scaled such that the horizontal and the vertical axis are plotted in units of standard deviation (1,2,3,4,...ect from the mean). What I would like to be able to do is label ONLY those elements that are beyond a certain limit of standard deviations from the mean. Ideally, this labeling would be based off of another column of data.
Is there a way to do this?
I've looked through the online manual, but I haven't been able to find anything about defining labels for plotted data.
Help is appreciated!
Thanks!
BEB
Use subsetting:
library(ggplot2)
x <- data.frame(a=1:10, b=rnorm(10))
x$lab <- letters[1:10]
ggplot(data=x, aes(a, b, label=lab)) +
geom_point() +
geom_text(data = subset(x, abs(b) > 0.2), vjust=0)
The labeling can be done in the following way:
library("ggplot2")
x <- data.frame(a=1:10, b=rnorm(10))
x$lab <- rep("", 10) # create empty labels
x$lab[c(1,3,4,5)] <- LETTERS[1:4] # some labels
ggplot(data=x, aes(x=a, y=b, label=lab)) + geom_point() + geom_text(vjust=0)
Subsetting outside of the ggplot function:
library(ggplot2)
set.seed(1)
x <- data.frame(a = 1:10, b = rnorm(10))
x$lab <- letters[1:10]
x$lab[!(abs(x$b) > 0.5)] <- NA
ggplot(data = x, aes(a, b, label = lab)) +
geom_point() +
geom_text(vjust = 0)
Using qplot:
qplot(a, b, data = x, label = lab, geom = c('point','text'))

Resources