Adjust width of panel labels on ggplot with faceting - r

I am having trouble with excessively wide panel labels on my ggplot2 faceted plot.
Here is the code that I used to generate the plot:
png(paste("/directory/", hgnc_symbol, "_", curr_gene, ".png", sep=""),
width=4, height=3, units="in", pointsize=1, res=300)
print({barplot <-
ggplot(curr_data, aes(x = condition, y = tpm, fill=condition)) +
geom_boxplot(outlier.colour=NA, lwd=0.2, color="grey18") +
stat_boxplot(geom ='errorbar', color="grey18") +
geom_jitter(size=0.8) +
facet_wrap(~target_id) +
guides(fill=FALSE) +
theme_bw() +
labs(title=paste(hgnc_symbol, "_", curr_gene, sep="")) +
labs(x="condition") + labs(y="TPM") +
theme(text = element_text(size=5), strip.background=element_rect(size = 1),
axis.text.x = element_text(angle = 90, hjust = 1, size=4.5))})
dev.off()
The plot comes out looking like this:
As you can see, the background of the panel labels is so wide, that the plots themselves are barely visible. The points plotted on the graph are also much larger than I expected them to be.
The odd thing is that I used this same exact code to produce this following plot (which looks good) just a few days ago:
What is causing this difference, and how can I fix the problem?

In ggplot, text is defined in pts, which are absolute units of measure. The plot panel is relative in size and scales according to the dimensions you specify when you save your plot. If the dimensions are small, then the text will be large relative to the panel areas. If the dimensions are large, then the text will be small relative to the panel areas. See examples below:
ggplot(diamonds, aes(x = x, y =y)) + geom_point() + facet_wrap(~ clarity)
ggsave("filepath//4x3.png", width=4, height = 3)
ggsave("filepath//8x6.png", width=8, height = 6)
The 4 x 3 in plot:
The 8 x 6 in plot:
You can edit the grobs to exert finer control on the plot dimensions (example).

Related

Reduce distance in plot X labels (R: ggplot2)

This is my dataframe:
df = data.frame(info=1:30, type=c(replicate(5,'A'), replicate(5,'B')), group= c(replicate(10,'D1'), replicate(10,'D2'), replicate(10,'D3')))
I want to make a jitter plot of my data distinguished by group (X-label) and type (colour):
ggplot()+
theme(panel.background=element_rect(colour="grey", size=0.2, fill='grey100'))+
geom_jitter(data=df, aes(x=group, y=info, color=type, shape=type), position=position_dodge(0.2), cex=2)+
scale_shape_manual(values=c(17,15,19))+
scale_color_manual(values=c(A="mediumvioletred", B="blue"))
How can I reduce the distance between the X-labels (D1, D2, D3) in the representation?
P.D. I want to do it even if I left a blank space in the graphic
Here are a few options.
# Setting up the plot
library(ggplot2)
df <- data.frame(
info=1:30,
type=c(replicate(5,'A'), replicate(5,'B')),
group= c(replicate(10,'D1'), replicate(10,'D2'), replicate(10,'D3'))
)
p <- ggplot(df, aes(group, info, colour = type, shape = type))
Option 1: increase the dodge distance. This won't put the labels closer, but it makes better use of the space available so that the labels appear less isolated.
p +
geom_point(position = position_dodge(width = 0.9))
Option 2: Expand the x-axis. Increasing the expansion factor from the default 0.5 to >0.5 increases the space at the ends of the axis, putting the labels closer.
p +
geom_point(position = position_dodge(0.2)) +
scale_x_discrete(expand = c(2, 0))
Option 3: change the aspect ratio. Depending on the plotting window size, this also visually puts the x-axis labels closer together.
p +
geom_point(position = position_dodge(0.2)) +
theme(aspect.ratio = 2)
Created on 2021-06-25 by the reprex package (v1.0.0)
Try adding coord_fixed(ratio = 0.2) and play around with the ratio.
ggplot()+
theme(panel.background=element_rect(colour="grey", size=0.2, fill='grey100'))+
geom_jitter(data=df, aes(x=group, y=info, color=type, shape=type), position=position_dodge(0.2))+
scale_shape_manual(values=c(17,15,19))+
scale_color_manual(values=c(A="mediumvioletred", B="blue")) + coord_fixed(ratio = 0.2)
The simplest solution is to resize the plot. For example if you follow your command with ggsave("my_plot.pdf", width = 3, height = 4.5) it looks like this:
Or in an Rmd file you can control the dimensions by various means: see this link.

Change size (width) of plot in ggplot

I am a newbie attempting to change the width of a ggplot, so that I am can arrange different plots(heatmap and dotplot) in the same figure. However, after hours of trying to reduce the width of the dotplot, I am about to give up.
Code for heatmap (maybe not relevant):
heatmap_GO_NES_1<-ggplot(data=long_frame_GO_NES_1) +
geom_tile(mapping = aes(
x = factor(timepoint,levels = c("6h","12h","24h")),
y =bio_process,fill = NES)) +
ylab(label="Biological process") +
theme(axis.title.x=element_blank()) +
scale_fill_gradient(low="red",high="green")+
facet_grid( group ~. , scales="free",space="free")+
theme(axis.text.x = element_text(angle = 90))+
theme(strip.text.y = element_text(size = 8))
heatmap_GO_NES_1
Code for dotplot:
dot_GO_NES_1<- ggplot(data=long_frame_GO_NES_2)+
geom_count(mapping=aes(x=timepoint, y =bio_process, size=setsize))+
theme(axis.title.x=element_blank(), axis.text.x=element_blank(),
axis.ticks.x=element_blank(),axis.title.y=element_blank(),
axis.text.y=element_blank(),axis.ticks.y=element_blank())
dot_GO_NES_1
Code for figure:
plot_grid(heatmap_GO_NES_1,dot_GO_NES_1)
Obviously, the dotplot is stealing all the figure space, so that my heatmap does not show up in the figure.
TL;DR - you need to use the rel_widths= argument of plot_grid(). Let me illustrate with an example using mtcars:
# Plots to display
p1 <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
p2 <- ggplot(mtcars, aes(x='X', y=disp)) + geom_point(aes(size=cyl))
Here are the plots, where you see p2 is like your plot... should not be too wide or it looks ridiculous. This is the default behavior of plot_grid(), which makes both plots the same width/relative size:
plot_grid(p1,p2)
Adjust the relative width of the plots using rel_widths=:
plot_grid(p1,p2, rel_widths=c(1,0.3))

How to set automatic label position based on box height

In a previous question, I asked about moving the label position of a barplot outside of the bar if the bar was too small. I was provided this following example:
library(ggplot2)
options(scipen=2)
dataset <- data.frame(Riserva_Riv_Fine_Periodo = 1:10 * 10^6 + 1,
Anno = 1:10)
ggplot(data = dataset,
aes(x = Anno,
y = Riserva_Riv_Fine_Periodo)) +
geom_bar(stat = "identity",
width=0.8,
position="dodge") +
geom_text(aes( y = Riserva_Riv_Fine_Periodo,
label = round(Riserva_Riv_Fine_Periodo, 0),
angle=90,
hjust= ifelse(Riserva_Riv_Fine_Periodo < 3000000, -0.1, 1.2)),
col="red",
size=4,
position = position_dodge(0.9))
And I obtain this graph:
The problem with the example is that the value at which the label is moved must be hard-coded into the plot, and an ifelse statement is used to reposition the label. Is there a way to automatically extract the value to cut?
A slightly better option might be to base the test and the positioning of the labels on the height of the bar relative to the height of the highest bar. That way, the cutoff value and label-shift are scaled to the actual vertical range of the plot. For example:
ydiff = max(dataset$Riserva_Riv_Fine_Periodo)
ggplot(dataset, aes(x = Anno, y = Riserva_Riv_Fine_Periodo)) +
geom_bar(stat = "identity", width=0.8) +
geom_text(aes(label = round(Riserva_Riv_Fine_Periodo, 0), angle=90,
y = ifelse(Riserva_Riv_Fine_Periodo < 0.3*ydiff,
Riserva_Riv_Fine_Periodo + 0.1*ydiff,
Riserva_Riv_Fine_Periodo - 0.1*ydiff)),
col="red", size=4)
You would still need to tweak the fractional cutoff in the test condition (I've used 0.3 in this case), depending on the physical size at which you render the plot. But you could package the code into a function to make the any manual adjustments a bit easier.
It's probably possible to automate this by determining the actual sizes of the various grobs that make up the plot and setting the condition and the positioning based on those sizes, but I'm not sure how to do that.
Just as an editorial comment, a plot with labels inside some bars and above others risks confusing the visual mapping of magnitudes to bar heights. I think it would be better to find a way to shrink, abbreviate, recode, or otherwise tweak the labels so that they contain the information you want to convey while being able to have all the labels inside the bars. Maybe something like this:
library(scales)
ggplot(dataset, aes(x = Anno, y = Riserva_Riv_Fine_Periodo/1000)) +
geom_col(width=0.8, fill="grey30") +
geom_text(aes(label = format(Riserva_Riv_Fine_Periodo/1000, big.mark=",", digits=0),
y = 0.5*Riserva_Riv_Fine_Periodo/1000),
col="white", size=3) +
scale_y_continuous(label=dollar, expand=c(0,1e2)) +
theme_classic() +
labs(y="Riserva (thousands)")
Or maybe go with a line plot instead of bars:
ggplot(dataset, aes(Anno, Riserva_Riv_Fine_Periodo/1e3)) +
geom_line(linetype="11", size=0.3, colour="grey50") +
geom_text(aes(label=format(Riserva_Riv_Fine_Periodo/1e3, big.mark=",", digits=0)),
size=3) +
theme_classic() +
scale_y_continuous(label=dollar, expand=c(0,1e2)) +
expand_limits(y=0) +
labs(y="Riserva (thousands)")

ggplot geom_text font size control

I tried to change the font to 10 for the labels of my bar plot in ggplot2 by doing something like this:
ggplot(data=file,aes(x=V1,y=V3,fill=V2)) +
geom_bar(stat="identity",position="dodge",colour="white") +
geom_text(aes(label=V2),position=position_dodge(width=0.9),
hjust=1.5,colour="white") +
theme_bw()+theme(element_text(size=10))
ggsave(filename="barplot.pdf",width=4,height=4)
but the resulting image has super big font size for the bar plot labels.
Then I thought of modifying in geom_text() with this:
geom_text(size=10,aes(label=V2),position=position_dodge(width=0.9),
hjust=1.5,colour="white")
The label font is even bigger...
I can change the size within geom_text to something like 3 and now it looks like font 10, similar to the axis labels.
I'm wondering what's going on? Does theme(text=element_text(size=10)) doesn't apply to labels?
And why size of 10 in geom_text() is different from that in theme(text=element_text()) ?
Here are a few options for changing text / label sizes
library(ggplot2)
# Example data using mtcars
a <- aggregate(mpg ~ vs + am , mtcars, function(i) round(mean(i)))
p <- ggplot(mtcars, aes(factor(vs), y=mpg, fill=factor(am))) +
geom_bar(stat="identity",position="dodge") +
geom_text(data = a, aes(label = mpg),
position = position_dodge(width=0.9), size=20)
The size in the geom_text changes the size of the geom_text labels.
p <- p + theme(axis.text = element_text(size = 15)) # changes axis labels
p <- p + theme(axis.title = element_text(size = 25)) # change axis titles
p <- p + theme(text = element_text(size = 10)) # this will change all text size
# (except geom_text)
For this And why size of 10 in geom_text() is different from that in theme(text=element_text()) ?
Yes, they are different. I did a quick manual check and they appear to be in the ratio of ~ (14/5) for geom_text sizes to theme sizes.
So a horrible fix for uniform sizes is to scale by this ratio
geom.text.size = 7
theme.size = (14/5) * geom.text.size
ggplot(mtcars, aes(factor(vs), y=mpg, fill=factor(am))) +
geom_bar(stat="identity",position="dodge") +
geom_text(data = a, aes(label = mpg),
position = position_dodge(width=0.9), size=geom.text.size) +
theme(axis.text = element_text(size = theme.size, colour="black"))
This of course doesn't explain why? and is a pita (and i assume there is a more sensible way to do this)
Take a look at the relevant entry in ggplot2's customization FAQ: https://ggplot2.tidyverse.org/articles/faq-customising.html#what-is-the-default-size-of-geom_text-and-how-can-i-change-the-font-size-of-geom_text
You can modify the default size of geom_text() by placing update_geom_defaults("text", list(size = X), where X is your choice of new size, at the beginning of your script.

Add a footnote citation outside of plot area in R?

I'd like to add a footnote citation to my 3-panel facet grid plot produced in R. It's a footnote to credit the data source. I'd ideally like to have it below and external to all three axes---preferably in the lower left.
I'm using ggplot2 and also ggsave(). This means I can't use grid.text()-based solutions, because that only draws on the x11() window, and can't be added to the ggplot object.
Using instead png() ...code... dev.off() does not appear to be an option because I need ggsave's resizing parameters, and find this command produces better, clearer prints (that are also much faster, because I'm not printing to the screen).
Here's my basic code:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle)
print(p1)
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
I've tried:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle)
print(p1)
grid.text(unit(0.1,"npc"),0.025,label = "Data courtesy of Me")
grid.gedit("GRID.text", gp=gpar(fontsize=7))
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
This appropriately puts the footnote in the lower left corner on the x11() display, external to the plots, but unfortunately, since it isn't applied to the p1 object, it isn't saved by the ggsave command.
I've also tried:
p1 <- ggplot(data, aes(date, value))
facet_grid(variable ~ .) + geom_point(aes(y =value), size=1) +
theme_bw() +
opts(title=mytitle) +
annotate("text", label = "Footnote", x = 0, y = 10, size = 5, colour = "black") +
print(p1)
ggsave("FILE.png",width=mywidth, height=myheight, p1, dpi=90)
This successfully prints using ggsave, however it has the following problems:
It is repeated 3 times, in each of the 3 facets, rather than 1 time.
It is contained within the plots, rather than external to them.
Text is difficult to place---seems to be using plot units (my x-axis is date, so 0 puts it around 1970).
The text size doesn't seem to change despite my size parameter.
A couple of related links from when I explored this...
ggplot2 footnote
(doesn't work with ggsave)
How to label the barplot in ggplot with the labels in another test result?
(is inside the plot, not external/below plot)
Different font faces and sizes within label text entries in ggplot2
(doesn't work with ggsave)
problem saving pdf file in R with ggplot2
ggplot2 now has this ability natively with no need for additional packages. ... + labs(caption = "footnote", ...)
library(ggplot2)
ggplot(diamonds, aes(carat, price, color = clarity)) +
geom_point() +
labs(title = "Diamonds are forever...",
subtitle = "Carat weight by Price",
caption = "H. Wickham. ggplot2: Elegant Graphics for Data Analysis Springer-Verlag New York, 2009.")
library(gridExtra)
library(grid)
library(ggplot2)
g <- grid.arrange(qplot(1:10, 1:10, colour=1:10) + labs(caption="ggplot2 caption"),
bottom = textGrob("grid caption", x = 1,
hjust = 1, gp = gpar(fontface = 3L, fontsize = 9)))
ggsave("plot.pdf", g)
Edit: note that this solution is somewhat complementary to the recent caption argument added to ggplot2, since the textGrob can here be aligned with respect to the whole figure, not just the plot panel.
Adding to the answer of Brandon Bertelsen: if you want to have the caption in the left corner, add
theme(plot.caption = element_text(hjust = 0))

Resources