2

I generate a boxplot with code below:

boxplot(top10threads$affect ~ top10threads$ThreadID[], data = top10threads, xlab = "10 biggest Threads", ylab = "Affect", col=(c("gold","darkgreen")), srt=45)

But as you may notice that some labels in x-axis are missing, so I want to rotate them into 45 degrees. I added srt=45, but it doesn't work.

By setting las=2 can rotate them vertically, but it's not exactly I need.

How could I do that? Thanks.

enter image description here

Darren Tsai
  • 32,117
  • 5
  • 21
  • 51
ah bon
  • 9,293
  • 12
  • 65
  • 148
  • Even though this question is much better titled, this was also answered here: https://stackoverflow.com/questions/18670795/r-boxplot-tilted-labels-x-axis – Chema_arguez Jan 30 '23 at 13:44

2 Answers2

6

First, store the output of boxplot() as a object. It contains names of the groups. You can use $names to get them. Then use text() to add labels on the axis. The argument srt works on text().

bp <- boxplot(y ~ x, data = df, col = c("gold", "darkgreen"), xaxt = "n")
tick <- seq_along(bp$names)
axis(1, at = tick, labels = FALSE)
text(tick, par("usr")[3] - 0.3, bp$names, srt = 45, xpd = TRUE)

Data

df <- data.frame(x = sample(100:110, 100, TRUE), y = rnorm(100))
Darren Tsai
  • 32,117
  • 5
  • 21
  • 51
  • It works, but labels are inside of plot, how could I set them outside? – ah bon May 08 '20 at 10:08
  • @ahbon you can adjust labels to any positions by subtracting a number from `par("usr")[3]`. In my example, I subtract `0.3`. That number depends on the range of your data. – Darren Tsai May 08 '20 at 10:13
  • I use `par("usr")[3]-0.1`, but it seems didn't change anything. – ah bon May 08 '20 at 10:15
  • 2
    @ahbon the range of my data is about 4, but yours is about 40. So the number subtracted will be 5~10 in your case. I.e. `par("usr")[3] - 5` ~ `par("usr")[3] - 10`. – Darren Tsai May 08 '20 at 10:20
2

Some test data:

mydata=lapply(1:5,function(i) rnorm(100,mean=i))
names(mydata)=c("first","second","third","fourth","fifth")

First, plot the boxplot with no x-axis:

boxplot(mydata,xaxt="n",xlab="")

Then, we make a function to add textual x-axis labels:

x_axis_labels=function(labels,every_nth=1,...) {
    axis(side=1,at=seq_along(labels),labels=F)
    text(x=(seq_along(labels))[seq_len(every_nth)==1],
        y=par("usr")[3]-0.075*(par("usr")[4]-par("usr")[3]),
        labels=labels[seq_len(every_nth)==1],xpd=TRUE,...)
}
# axis() draws the axis with ticks at positions specified by at.  Again, we don't plot the labels yet.
# text() plots the labels at positions given by x and y.
# We estimate the y-positions from the values of the y-axis (using par("usr")),
# and specify xpd=TRUE to indicate that we don't want to crop plotting to within the plot area
# Note that we select the [seq_len(every_nth)==1] elements of both the x positions and the labels, 
# so we can easily skip labels if there would be too many to cram in otherwise.  
# Finally, we leave a ... in the function so we can pass additional arguments to text()

Finally, we call the new function to plot the axis tick labels:

x_axis_labels(labels=names(mydata),every_nth=1,adj=1,srt=45)

Here we take advantage of the ... in the function to pass the rotation/justification parameters: adj=1 specifies to right-justify the text labels, and srt=45 indicates to rotate them by 45 degrees.

  • emm, it seems complicated, so maybe I should use `las = 2` – ah bon May 08 '20 at 09:58
  • 2
    once you've defined the ```x_axis_labels``` function, it isn't at all complicated: just call ```boxplot()``` for the plot and ```x_axis_labels()``` for the labels: 2 lines of code. – Dominic van Essen May 08 '20 at 10:02
  • 2
    possibly the function definition seems complicated because it contains extra 'work' to try to solve the problem of the vertical label pacement, which isn't always straightforward using ```text()```, as it can depend on the y-axis range of the plot... – Dominic van Essen May 08 '20 at 10:29