Fixed height of text elements in ggplot2 - r

I want to align Plots with titles with grid.arrange so that the y-Axis of the two plots matches. If one of the plots has a Title that contains a character with a decender (g,j,y,...) and the other doesn't the plots are misaligned.
Is there an option to fix the size of the element e.g. in element_text in the theme to line heights including decenders?
An alternative would be to modify the grid-grobs directly with ggplotGrob but this seems overly complicated.
require(ggplot2)
require(gridExtra)
test <- data.frame(x=1:3, y=1:3)
plot1 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
ggtitle("asdf")
plot2 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
ggtitle("asdfg")
grid.arrange(plot1, plot1, nrow=1)
grid.arrange(plot1, plot2, nrow=1)
Notice the slight difference in the alignment of the top border of the plotting area in the second plot. In the first one both are aligned perfectly.

This hack solves the Problem, but I think it only works for one line titles.
Set the lineheight to 0 and add an empty line to every title:
require(ggplot2)
require(gridExtra)
test <- data.frame(x=1:3, y=1:3)
plot1 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
theme(
plot.title = element_text(lineheight = 0),
) +
ggtitle("asdf\n")
plot2 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
theme(
plot.title = element_text(lineheight = 0)
) +
ggtitle("asdfg\n")
grid.arrange(plot1, plot1, nrow=1)
grid.arrange(plot1, plot2, nrow=1)

Related

Margin above title in ggplot created with grid.arrange

I have two ggplots that I can created like this:
df1 = data.frame(x=1:10, y1=11:20, y2=21:30)
gg1 = ggplot(df1) + geom_point(aes(x=x, y=y1))
gg2 = ggplot(df1) + geom_point(aes(x=x, y=y2))
grid.arrange(gg1, gg2, top=textGrob("Here should be some space above",
gp=gpar(fontsize=18,
fontfamily="Times New Roman")))
Now the output looks like this:
One does not see it here as it is white on white, but I would like to create more space in the output-image above the title. And I'm not really sure on how to do it. Here is described on how to add space between the single plots Margins between plots in grid.arrange , but I did not manage to just add space above the header.
Making use of arrangeGrob you could add some margin on top of your header via a zeroGrob like so:
library(ggplot2)
library(gridExtra)
library(grid)
df1 = data.frame(x=1:10, y1=11:20, y2=21:30)
gg1 = ggplot(df1) + geom_point(aes(x=x, y=y1))
gg2 = ggplot(df1) + geom_point(aes(x=x, y=y2))
title <- textGrob("Here should be some space above",
gp=gpar(fontsize=18, fontfamily="Times New Roman"))
# Add a zeroGrob of height 2cm on top of the title
title <- arrangeGrob(zeroGrob(), title,
widths = unit(1, 'npc'),
heights = unit(c(2, 1), c('cm', 'npc')),
as.table = FALSE)
grid.arrange(gg1, gg2, top = title)
Can you live with another package?
library(patchwork)
plot_spacer()/ (gg1 + ggtitle("there is now space above")) / gg2 + plot_layout(heights = c(.5,1,1))
Or set the title margin in the first plot
gg1 = ggplot(df1) + geom_point(aes(x=x, y=y1)) +
ggtitle("there is now space above") +
theme(plot.title = element_text(margin = margin(t = 1, unit = "in")))
gg1 / gg2

ggplot2 & gridExtra: Reduce space between plots, but keep ylab of one plot

I would like to plot 3 graphics beside each other via the ggplot2 and gridExtra packages. The graphic on the left side has a ylab, the other 2 graphics do not. All three graphics should have the same size and the space between the graphics should be reduced as much as possible. However, due to the ylab of the graphic on the left side, I am either not able to reduce the space as much as I want; or I am cutting off the ylab.
Consider the following example in R:
library("ggplot2")
library("gridExtra")
# Example data
df <- data.frame(x = 1:10,
y = 1:10)
# Plots
ggp1 <- ggplot(df, aes(x, y)) +
geom_line() + theme_bw() +
ylab("Here is the ylab")
ggp2 <- ggplot(df, aes(x, y)) +
geom_line() + theme_bw() +
ylab("")
ggp3 <- ggplot(df, aes(x, y)) +
geom_line() + theme_bw() +
ylab("")
# Arrange grids
grid.arrange(ggp1, ggp2, ggp3, ncol = 3)
The space between the graphics should be reduced as much as possible.
All graphics should have the same size.
The ylab of the graphic on the left side should be kept.
I was trying to fix the problem with plot.margin, but unfortunately that didn't work.
I would suggest to cbind() the gtables, with the axis removed. null units automatically ensure equal panel widths.
lg <- lapply(list(ggp1,ggp2,ggp3),ggplotGrob)
rm_axis <- function(g){
lay <- g[["layout"]]
cp <- lay[lay$name == "panel",]
g[,-c(1:(cp$l-1))]
}
lg[-1] <- lapply(lg[-1], rm_axis)
grid::grid.draw(do.call(gtable_cbind, lg))
Adding theme (axis.title.y = element_blank()) to ggp2 and ggp3 will reduce the space between them.
library("ggplot2")
library("gridExtra")
# Example data
df <- data.frame(x = 1:10,
y = 1:10)
# Plots
ggp1 <- ggplot(df, aes(x, y)) +
geom_line() + theme_bw() +
ylab("Here is the ylab")
ggp2 <- ggplot(df, aes(x, y)) +
geom_line() + theme_bw() +
ylab("") + theme (axis.title.y = element_blank())
ggp3 <- ggplot(df, aes(x, y)) +
geom_line() + theme_bw() +
ylab("") + theme (axis.title.y = element_blank())
# Arrange grids
grid.arrange(ggp1, ggp2, ggp3, ncol = 3)

How to remove margins in ggplot2 chart

I am currently creating plots with ggplot2 for a latex document and discovered that ggplot2 adds many unwanted margins:
painted red by plot.background=element_rect(fill="red"):
small margin on the left
small margin between image and legend
painted violet with photoshop:
margin on the left and the right
1px margin on the bottom
Which more rules are needed to remove these margins? It's really difficult to google all these configuration options. This is my actual chart:
library(ggplot2)
library(scales)
label <- c("A", "B", "C", "D")
value <- c(61, 26, 9, 4)
values <- data.frame(label, value)
myplot <- ggplot(values, aes(x = "", y=value, fill=label))
myplot <- myplot + theme(legend.position="bottom")
myplot <- myplot + labs(fill="")
myplot <- myplot + geom_bar(stat="identity", width=1)
myplot <- myplot + geom_text(
aes(x=1.3, y=value/2+c(0, cumsum(value)[-length(value)])),
label=percent(value/100),
size=2
)
myplot <- myplot + coord_polar(theta="y")
myplot <- myplot + theme(plot.background=element_rect(fill="red"))
myplot <- myplot + theme(
plot.margin=unit(c(0,0,0,0), "mm"),
legend.margin=unit(0, "mm"),
axis.title=element_blank(),
axis.ticks=element_blank()
)
ggsave("pie.pdf")
Adjust the plot.margin settings so that the bottom and left side are negative numbers.
plot.margin=unit(c(0,0,-12,-5), "mm")
If you do get rid of the margin on the bottom, you are also sacrificing the legend.
You can remove the rest of the axis space via the theme elements axis.text and axis.tick.length.
So you'd add something like the following to your theme code:
axis.text = element_blank(), axis.ticks.length = unit(0, "mm")
In the current development version of ggplot2, ggplot2_2.1.0.9001, there is a new theme element legend.box.spacing that could also be useful here to remove all space between the legend and the plot: legend.box.spacing = unit(0, "mm").

Enlarge ggplot2 legend

I have this plot made in R with ggplot2
which is drawn by the following code:
ggplot(mtcars) +
geom_smooth(fill='grey', alpha=0.3, span=0.1, aes(x=mpg, y=hp, color='AAA',linetype='AAA')) +
geom_smooth(fill='grey', alpha=0.3, span=0.9, aes(x=mpg, y=hp, color='BBB',linetype='BBB')) +
scale_colour_manual(name='test', values=c('AAA'='chocolate', 'BBB'='yellow')) +
scale_linetype_manual(name='test', values=c('AAA'='dashed','BBB'='solid')) +
theme_minimal() +theme(legend.position = "top")
Problem: from the legend, it is not easy to understand that the "AAA" line is dashed, since the box is too small.
How can I enlarge it?
I would love to have something similar to:
Try
# create your legend guide
myguide <- guide_legend(keywidth = unit(3, "cm"))
# now create your graph
ggplot(mtcars) +
geom_smooth(fill='grey', alpha=0.3, span=0.1,
aes(x=mpg, y=hp, color='AAA',linetype='AAA')) +
geom_smooth(fill='grey', alpha=0.3, span=0.9,
aes(x=mpg, y=hp, color='BBB',linetype='BBB')) +
scale_colour_manual(name='test',
values=c('AAA'='chocolate', 'BBB'='yellow'),
guide = myguide) +
scale_linetype_manual(name='test',
values=c('AAA'='dashed','BBB'='solid'),
guide = myguide) +
theme_minimal() + theme(legend.position = "top")
See ?guide_legend and here.
This will give you
You can use keywidth and keyheight to manipulate how much the key "stretches" into both directions. With title.position, direction, etc you can further finetune the legend.
Note that since you have multiple legends that are merged, you need to specify the guide to all merged scales. I simplified this by creating the guide outside as an object first.

Gridlines between discrete values

When using a discrete values ggplot2 provides a gridline at the tick value at the centre of the value
library(reshape2)
ggplot(data=tips, aes(x=time, y=total_bill, fill=sex)) +
geom_bar(stat="identity", position=position_dodge())
How can I set the grid line from the x axis to appear between the discrete values (i.e. between 'Dinner' and 'Lunch')
I have tried to set panel.grid.minor.x however (I think) as it is discrete this does not work ... this is not a minor value for it to plot the girdline on.
ggplot(data=tips, aes(x=time, y=total_bill, fill=sex)) +
geom_bar(stat="identity", position=position_dodge()) +
theme(panel.grid.minor.x = element_line())
You can add a vertical line that will act as a grid line as follows:
geom_vline(xintercept=1.5, colour='white')
You can, of course, alter line width, colour, style, etc. as needed, and add multiple lines in the appropriate locations if you have several groups of bars that need to be separated by grid lines. For example, using some fake data:
set.seed(1)
dat = data.frame(total_bill=rnorm(100,80,10),
sex=rep(c("Male","Female"),50),
time=sample(c("Breakfast","Brunch","Lunch","Afternoon Tea","Dinner"),
100, replace=TRUE))
dat$time = factor(dat$time,
levels=c("Breakfast","Brunch","Lunch","Afternoon Tea","Dinner"),
ordered=TRUE)
ggplot(data=dat, aes(x=time, y=total_bill, fill=sex)) +
geom_bar(stat="identity", position=position_dodge()) +
geom_vline(xintercept=seq(1.5, length(unique(dat$time))-0.5, 1),
lwd=1, colour="black")
Had the same problem. My solution was to make the grid line bigger ..
set.seed(1)
dat = data.frame(total_bill=rnorm(100,80,10),
sex=rep(c("Male","Female"),50),
time=sample(c("Breakfast","Brunch","Lunch","Afternoon Tea","Dinner"),
100, replace=TRUE))
dat$time = factor(dat$time,
levels=c("Breakfast","Brunch","Lunch","Afternoon Tea","Dinner"),
ordered=TRUE)
ggplot(data=dat, aes(x=time, y=total_bill, color=sex)) +
geom_point(stat="identity", position=position_dodge()) +
theme(panel.grid.major.x = element_line(color = "white", size = 20))

Resources