ggplot font size for different elements - r

I know that after I create a ggplot graph I can use theme_get() to return detail of all the theme elements. This has been very helpful in figuring out things like strip.text.x and the like. But I have two things I can't figure out:
1) In the following ggplot graphic, what is the name of the theme item representing the phrase "Percent of wood chucked by the woodchuck" as I want to resize it to a larger font:
2) How do I reformat the y axis labels to read 10%, 20, ... instead of .1, .2, ...

For 1), it is $axis.title.y
p + theme(axis.title.x = element_text(size = 25))
where p is an existing ggplot object.
I don't know about 2) off hand.

For (2) what you want is to use a formatter:
dat <- data.frame(x=1:10,y=1:10)
#For ggplot2 0.8.9
ggplot(dat,aes(x = x/10,y=y/10)) +
geom_point() +
scale_x_continuous(formatter = "percent")
#For ggplot2 0.9.0
ggplot(dat,aes(x = x/10,y=y/10)) +
geom_point() +
scale_x_continuous(labels = percent_format())

Related

ggplot2 data labels outside margins

I'm making many figures in ggplot2 using a for loop, but my data labels are extending beyond the plot margin. I've tried using expand, but it only works for some figures. When I try to use par(mar) I get this error message:
Error: Don't know how to add o to a plot.
I also tried just using ggsave to save as a really wide file, but 1) that looks odd and 2) that won't work for making so many different figures.
Does anyone know of any other workarounds? Ideally a way to have the inner plot margins automatically set per figure based on the length of the bars + data labels. Below is the code I'm using and an example figure (you can see the bar for 'x' is outside the margin). Thank you in advance!
for (i in each) {
temp_plot = ggplot(data= subset(Data, Each == i)) +
geom_bar(stat = "identity",
aes(x = reorder(Letter, +Number), y = Number, fill = factor(Category))) +
xlab("Letters") +
ggtitle(paste0("Title"), subtitle = "Subtitle") +
coord_flip() +
theme_classic() +
theme(plot.title = element_text(hjust = 0.5, size=16),
plot.subtitle = element_text(hjust = 0.5)) +
scale_fill_manual(values = c("#00358E", "#00AFD7"),
name= "Category",
labels=c("This","That")) +
geom_text(family="Verdana", size=3,
aes(label=Number2, x=reorder(Letter, +Number), y=Number),
position=position_dodge(width=0.8), hjust=-0.001) +
scale_y_continuous(labels = comma, expand = c(0.01,0)) +
scale_x_discrete(labels = letters)
ggsave(temp_plot, file=paste0("Example", i,".jpeg"))
}
I figured out a simple solution: + ylim(0, 130000)
scale_y_continuous(expand = expansion(mult = c(0, .1)) )

Removing ggplot legend symbol while retaining label

Example code and figure:
data <- data.frame( ID = c(LETTERS[1:26], paste0("A",LETTERS[1:26])),
Group = rep(c("Control","Treatment"),26),
x = rnorm(52,50,20),
y = rnorm(52,50,10))
ggplot(data, aes(y=y,x=x, label=ID, color=Group)) +
geom_text(size=8) +
scale_color_manual(values=c("blue","red")) +
theme_classic() +
theme(legend.text = element_text(color=c("blue","red")))
What I'm trying to solve is removing the legend symbols (the "a") and coloring the Group labels (Control and Treatment) as they appear in the plot (Blue and Red respectively).
I've tried:
geom_text(show_guide = F)
But that just removes the legend entirely.
To keep it simple I could just use annotate...but wondering if there's a legend specific solution.
ggplot(data, aes(y=y,x=x, label=ID, color=Group)) +
geom_text(size=8, show_guide=F) +
scale_color_manual(values=c("blue","red")) +
theme_classic() +
annotate("text",label="Control", color="blue",x=20,y=80,size=8) +
annotate("text",label="Treatment", color="Red",x=23,y=77,size=8)
Another option is to use point markers (instead of the letter "a") as the legend symbols, which you can do with the following workaround:
Remove the geom_text legend.
Add a "dummy" point geom and set the point marker size to NA, so no points are actually plotted, but a legend will be generated.
Override the size of the point markers in the legend, so that point markers will appear in the legend key to distinguish each group.
ggplot(data, aes(y=y,x=x, label=ID, color=Group)) +
geom_text(size=8, show.legend=FALSE) +
geom_point(size=NA) +
scale_color_manual(values=c("blue","red")) +
theme_classic() +
labs(colour="") +
guides(colour=guide_legend(override.aes=list(size=4)))
Beginning with ggplot2 2.3.2, you can specify the glyph used in the legend using the argument key_glyph:
ggplot(data, aes(x=x, y=y, label=ID, color=Group)) +
geom_text(size=8, key_glyph="point") +
scale_color_manual(values=c("blue", "red")) +
labs(color=NULL) +
theme_classic()
For a full list of glyphs, refer to the ggplot2 documentation for draw_key. Credit to R Data Berlin for alerting me to this simple solution. Emil Hvitfeldt also has a nice blog post showcasing the options.
As a quick fix you can tweak the legend key, by hard coding the info you want, although around the other way - keep the key and remove the label.
library(grid)
GeomText$draw_key <- function (data, params, size) {
txt <- ifelse(data$colour=="blue", "Control", "Treatment")
# change x=0 and left justify
textGrob(txt, 0, 0.5,
just="left",
gp = gpar(col = alpha(data$colour, data$alpha),
fontfamily = data$family,
fontface = data$fontface,
# also added 0.5 to reduce size
fontsize = data$size * .pt* 0.5))
}
And when you plot you suppress the legend labels, and make legend key a bit wider to fit text.
ggplot(data, aes(y=y,x=x, label=ID, color=Group)) +
geom_text(size=8) +
scale_color_manual(values=c("blue","red")) +
theme_classic() +
theme(legend.text = element_blank(),
legend.key.width = unit(1.5, "cm"))

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.

how to change vertical position of ggplot title without altering axis label justification

Edit: The problem was due to my incorrectly attempting to alter theme(title = element_text()), when I needed to alter theme(plot.title(element_text()). I would have noticed this had I more carefully scrutinized the theme() documentation.
Original Post:
Changing the title vertical justification alters the position of the x and y axis labels as well. Is this a bug? Or am I misinterpreting the function of theme()? I am running ggplot2 version 0.9.3.1
Minimal reproducible example.
require(ggplot2)
set.seed(12345)
x <- rnorm(100,10,0.5)
y <- x * 3 + rnorm(100)
df <- data.frame(y,y)
The default title is too close to the graph for my taste....
ggplot(df,aes(x,y)) +
geom_point() +
labs(title="My Nice Graph")
When I try to move the title, the axis labels move also, and illegibly plot on the graph.
ggplot(df,aes(x,y)) +
geom_point() +
labs(title="My Nice Graph") +
theme(title = element_text(vjust=2))
You want plot.title not title:
labs(title="My Nice Graph") + theme(plot.title = element_text(vjust=2))
Alternate quick fix is adding a line break:
labs(title="My Nice Graph\n")
vjust does not work for me (I also think values should be in [0, 1]). I use
... +
theme(
plot.title = element_text(margin=margin(b = 10, unit = "pt"))
)

Plot with a grid

I am looking for a type of plot that is essentially a grid. For example, there will be 10 columns and 50 rows. For example, something like this:
Each of the boxes (in this case, 10*50 = 500) will have a unique value that I will be providing via a data frame. Based on the unique values, I'll have a function that will assign a colour to each box. So then it becomes a grid to visualize "the range" of each box. I'd also need to label each of the columns (probably vertically so all labels fit) and rows (horizontally).
I just don't know what kind of plot that will be and I don't know if any libraries do this. I'm just looking for some help in finding something that does this. I'd appreciate some help if possible.
How about heatmap?
m=matrix(runif(12),3,4)
rownames(m)=c("Me","You","Him")
colnames(m)=c("We","Us","Them","I")
heatmap(m,NA,NA)
Note that it works on a matrix and not a data frame because all the values have to be numbers, and data frames are row-oriented records.
See the help for other options.
Look at the image function in the graphics package, or the rasterImage function if you want more control.
You could also build the plot up from scratch using the rect function.
I would go to ggplot2 for this as it allows a high degree of flexibility. In particular geom_tile is useful. If you actually want the panel lines you can comment out the theme(panel.grid.major = element_blank()) + and theme(panel.grid.minor = element_blank()) + lines and of course you can specify the colours as well. The text in each cell is optional; comment out the geom_text call if you don't need that. Note that you can control the size of the plot (rows and columns) simply by resizing the plot window or - if you want to output to a file using png() - by specifying the width and height arguments.
library(ggplot2)
library(reshape)
library(scales)
set.seed(1234)
num.els <- 5
mydf <- data.frame(category1 = rep(LETTERS[1:num.els], 1, each = num.els),
category2 = rep(1:num.els, num.els),
value = runif(num.els^2, 0, 100))
p <- ggplot(mydf, aes(x = category1,
y = category2,
fill = value)) +
geom_tile() +
geom_text(label = round(mydf$value, 2), size = 4, colour = "black") +
scale_fill_gradient2(low = "blue", high = "red",
limits = c(min(mydf$value), max(mydf$value)),
midpoint = median(mydf$value)) +
scale_x_discrete(expand = c(0,0)) +
scale_y_reverse() +
theme(panel.grid.minor = element_blank()) +
theme(panel.grid.major = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(panel.background = element_rect(fill = "transparent"))+
theme(legend.position = "none") +
theme()
print(p)
Output:
And resized:
Lets say you have a dataframe with "x" and "y" coordinates per each cell of the grid, and a variable "z" for each cell, and you loaded this dataframe in R called "intlgrid":
head(intlgrid)
x y z
243.742 6783.367 0.0035285
244.242 6783.367 0.0037111
244.742 6783.367 0.0039073
"..."
"so on..."
With ggplot2 package you can easily plot your raster. So:
install.packages("ggplot2")
once installed ggplot2, you just call it
library(ggplot2)
Now the code:
ggplot(intlgrid, aes(x,y, fill = z)) + geom_raster() + coord_equal()
And then you get your grid plotted.

Resources