Rotating and spacing axis labels in ggplot2
Solution 1
Change the last line to
q + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
By default, the axes are aligned at the center of the text, even when rotated. When you rotate +/- 90 degrees, you usually want it to be aligned at the edge instead:
The image above is from this blog post.
Solution 2
Use coord_flip()
data(diamonds)
diamonds$cut <- paste("Super Dee-Duper",as.character(diamonds$cut))
qplot(cut, carat, data = diamonds, geom = "boxplot") +
coord_flip()
Add str_wrap()
# wrap text to no more than 15 spaces
library(stringr)
diamonds$cut2 <- str_wrap(diamonds$cut, width = 15)
qplot(cut2, carat, data = diamonds, geom = "boxplot") +
coord_flip()
In Ch 3.9 of R for Data Science, Wickham and Grolemund speak to this exact question:
coord_flip()
switches the x and y axes. This is useful (for example), if you want horizontal boxplots. It’s also useful for long labels: it’s hard to get them to fit without overlapping on the x-axis.
Solution 3
ggplot 3.3.0
fixes this by providing guide_axis(angle = 90)
(as guide
argument to scale_..
or as x
argument to guides
):
library(ggplot2)
data(diamonds)
diamonds$cut <- paste("Super Dee-Duper", as.character(diamonds$cut))
ggplot(diamonds, aes(cut, carat)) +
geom_boxplot() +
scale_x_discrete(guide = guide_axis(angle = 90)) +
# ... or, equivalently:
# guides(x = guide_axis(angle = 90)) +
NULL
From the documentation of the angle
argument:
Compared to setting the angle in theme() / element_text(), this also uses some heuristics to automatically pick the hjust and vjust that you probably want.
Alternatively, it also provides guide_axis(n.dodge = 2)
(as guide
argument to scale_..
or as x
argument to guides
) to overcome the over-plotting problem by dodging the labels vertically. It works quite well in this case:
library(ggplot2)
data(diamonds)
diamonds$cut <- paste("Super Dee-Duper",as.character(diamonds$cut))
ggplot(diamonds, aes(cut, carat)) +
geom_boxplot() +
scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
NULL
Solution 4
To make the text on the tick labels fully visible and read in the same direction as the y-axis label, change the last line to
q + theme(axis.text.x=element_text(angle=90, hjust=1))
Solution 5
I'd like to provide an alternate solution, a robust solution similar to what I am about to propose was required in the latest version of ggtern, since introducing the canvas rotation feature.
Basically, you need to determine the relative positions using trigonometry, by building a function which returns an element_text
object, given angle (ie degrees) and positioning (ie one of x,y,top or right) information.
#Load Required Libraries
library(ggplot2)
library(gridExtra)
#Build Function to Return Element Text Object
rotatedAxisElementText = function(angle,position='x'){
angle = angle[1];
position = position[1]
positions = list(x=0,y=90,top=180,right=270)
if(!position %in% names(positions))
stop(sprintf("'position' must be one of [%s]",paste(names(positions),collapse=", ")),call.=FALSE)
if(!is.numeric(angle))
stop("'angle' must be numeric",call.=FALSE)
rads = (angle - positions[[ position ]])*pi/180
hjust = 0.5*(1 - sin(rads))
vjust = 0.5*(1 + cos(rads))
element_text(angle=angle,vjust=vjust,hjust=hjust)
}
Frankly, in my opinion, I think that an 'auto' option should be made available in ggplot2
for the hjust
and vjust
arguments, when specifying the angle, anyway, lets demonstrate how the above works.
#Demonstrate Usage for a Variety of Rotations
df = data.frame(x=0.5,y=0.5)
plots = lapply(seq(0,90,length.out=4),function(a){
ggplot(df,aes(x,y)) +
geom_point() +
theme(axis.text.x = rotatedAxisElementText(a,'x'),
axis.text.y = rotatedAxisElementText(a,'y')) +
labs(title = sprintf("Rotated %s",a))
})
grid.arrange(grobs=plots)
Which produces the following:
Comments
-
Christopher DuBois over 3 years
I have a plot where the x-axis is a factor whose labels are long. While probably not an ideal visualization, for now I'd like to simply rotate these labels to be vertical. I've figured this part out with the code below, but as you can see, the labels aren't totally visible.
data(diamonds) diamonds$cut <- paste("Super Dee-Duper",as.character(diamonds$cut)) q <- qplot(cut,carat,data=diamonds,geom="boxplot") q + opts(axis.text.x=theme_text(angle=-90))
-
rnorberg over 11 yearsIn the newest version of ggplot2 the command would be:
q + theme(axis.text.x=element_text(angle = -90, hjust = 0))
-
lilster almost 11 yearsTo those for whom hjust is not behaving as described here, try
theme(axis.text.x=element_text(angle = 90, vjust = 0.5))
. As of ggplot2 0.9.3.1 this seems to be the solution. -
jupp0r over 10 yearsActually, I had to combine the two solutions above to get correctly aligned labels:
q + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
-
Admin about 10 years@jupp0r's correct.
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
IS THE ONE WORKING CURRENTLY. -
jan-glx about 9 yearsif you wanted 45° rotated labels (easier to read)
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1))
gives good results -
toto_tico over 8 yearsIn my case I have the vjust was 0.3 to really make it look centered
q + theme(axis.text.x = element_text(angle = 90, vjust = 0.3, hjust=1))
. I am usingezplot
fromez
package, and usingvjust = 0.5
produced a slightly crooked result -
asachet over 7 yearsI do not obtain the same results, for me the axis text is never well adjusted using your auto method. However, using
rads = (-angle - positions[[ position ]])*pi/180
produced better placements. Note the additional minus sign before angle. Thanks for the code anyway :) -
Filippo Mazza about 7 yearsIn case someone is looking for it, it works also with
qplot
-
skan over 6 yearsHow can I use it when I'm using the option geom_bar(stat="identity",position="dodge")? Strangely then it doesn't rotate the labels
-
eipi10 almost 4 yearsAlthough I like the dodging solution here, it's worth noting that
guide_axis(angle=90)
picks the correct vjust and hjust values, which addresses the issue in the OP. -
jan-glx almost 4 years@eipi10 Thanks, I was not aware and now added this to the answer!
-
jan-glx almost 4 yearsNowadays, you can simply use
guides(x = guide_axis(angle = 90)) +
. (see also my answer below) -
jlsecrest almost 3 yearsFor better clarity on using hjust and vjust see this excellent post: stackoverflow.com/questions/7263849/…
-
Rémy Pétremand almost 3 yearsGet idea! I wanted to adapt your function to be able to run it with any parameters of
element_text()
. So I added a parameter in the function calledelement_text_params = list()
and replaced the last line in your function byelement_text_params <- c(element_text_params, list(angle = angle, vjust = vjust, hjust = hjust))
and returnedreturn(do.call(element_text, element_text_params))
. That way I can call your function likerotatedAxisElementText(45, "y", element_text_params = list("size" = 10, "face" = "bold")
-
Olivier about 2 yearsunfortunately this solution doesn't;t play well with ggplotly function as the rotated axis label is not carried over. Only the previous theme() solution works with ggplotly