dan
dan

Reputation: 6314

Customizing the angle in a ggplot x-axis tick labels

I want to plot a heatmap using ggplot2, and I want to customize the x-axis ticks - location, text, and angle.

Here are my example data:

set.seed(1)
df <- reshape2::melt(matrix(rnorm(100*20),100,20,dimnames = list(paste0("G",1:100),paste0("S",1:20))))

I'd like to have the x-axis tick have only a single tick value, located in the middle of the axis range - 10, with the label: "X-Label", at a 90 degrees angle. In addition, I do not want an x-axis title.

Here's what I'm trying:

library(ggplot2)
ggplot(data=df,mapping=aes(x=Var2,y=Var1,fill=value))+
  geom_tile()+theme_minimal()+scale_fill_gradient2(name="Scaled Value",low="darkblue",mid="gray",high="darkred")+
  scale_x_discrete(breaks=10,labels="X-Label")+theme(axis.title.x=element_blank(),axis.text.x=element_text(angle=90,hjust=1,vjust=0.5))

enter image description here

So, obviously it's not working.

I thought that I can define the angle as part of the scale_x_discrete arguments but couldn't find that option.

Also, note that I do not want an x-axis title but only the tick text. So I'm not sure why the breaks and labels arguments in scale_x_discrete are ignored.

Here's the desired outcome using plotly:

library(plotly)
library(dplyr)
plot_ly(z=c(df$value),x=df$Var2,y=df$Var1,colors=grDevices::colorRamp(c("darkblue","gray","darkred")),type="heatmap",colorbar=list(title="Scaled Value",len=0.4)) %>%
  layout(yaxis=list(title=NULL),xaxis=list(tickangle=90,tickvals=10,ticktext="X-Label"))

enter image description here

Thanks

Upvotes: 4

Views: 5644

Answers (2)

Dave2e
Dave2e

Reputation: 24119

The breaks option inside scale_x_discrete does not specify the number of breaks but one of:

  • NULL for no breaks
  • waiver() for the default breaks computed by the transformation object
  • A character vector of breaks
  • A function that takes the limits as input and returns breaks as output

I find it easiest just to define the character vectors. In this case one half over at the 50th element.

set.seed(1)
df <- reshape2::melt(matrix(rnorm(100*20),100,20,dimnames = list(paste0("G",1:100),paste0("S",1:20))))

library(ggplot2)
ggplot(data=df,mapping=aes(x=Var1,y=Var2,fill=value))+
  geom_tile() +
  theme_minimal() +
  scale_fill_gradient2(name="Scaled Value",low="darkblue",mid="gray",high="darkred") +
  scale_x_discrete(breaks=unique(df$Var1)[50],labels="X-Label") +
  theme(axis.title.x=element_blank(), axis.text.x=element_text(angle=90,hjust=1,vjust=0.5))

#Use this line instead to label along the axis
 #scale_x_discrete(breaks=unique(df$Var1)[seq(1,100, 10)],labels=unique(df$Var1)[seq(1,100, 10)]) +

enter image description here

Hopefully this is what you are looking for.

Upvotes: 0

Gregor Thomas
Gregor Thomas

Reputation: 146030

I think that specifying breaks = 10 is causing your axis labels to go unprinted. 10 isn't one of your values, and it doesn't fit the description of a valid argument in ?scale_x_discrete, so let's use a real x-axis value instead. You say "right in the middle", so I'll use "G50" since your x-axis values range from "G1" to "G100":

ggplot(data = df,
       mapping = aes(x = Var1, y = Var2, fill = value)) +
  geom_tile() +
  theme_minimal() +
  scale_fill_gradient2(
    name = "Scaled Value",
    low = "darkblue",
    mid = "gray",
    high = "darkred"
  ) +
  scale_x_discrete(breaks = "G50", labels = "X-Label", name = "") + 
  theme(
    axis.text.x = element_text(
      angle = 90,
      hjust = 1,
      vjust = 0.5
  ))

enter image description here

I also specified name = "" in the scale function instead of using theme to disable the axis title.

If you need to dynamically calculate the middle level, it's a bit messy but this should work:

breaks = levels(df$Var1)[ceiling(length(levels(df$Var1)) / 2)]

Upvotes: 3

Related Questions