Jon
Jon

Reputation: 601

ggplot2: How to end y-axis on a tick mark?

I am making several different plots with different axis ranges, so this question does not apply to only the code I am showing here. I tried modifying the breaks and intervals of tick marks, but for some plots the y-axis always continues after the last break. But for some it just works out fine like this.

Here is my current plot, and the code. I would like to end the y-axis with a tick mark on 60:

enter image description here

# Set nucleotide sequence for x-axis labels
my_labs = c("C", "T", "A", "C", "A", "T", "A", "A", "A", "T", "A", "C", "A", "C", "A", "T", "G", "T", "C", "T", "C", "T", "G", "C", "T", "C", "G", "T", "T", "C", "G", "G", "G", "G", "G", "C", "C", "G", "G", "T", "A", "T", "G", "C", "T", "A", "C", "A", "C", "G", "G", "A", "A", "C", "G", "T", "G", "A", "G", "A", "G", "A", "C", "C", "C", "C", "T", "C", "G", "G", "A", "A", "C", "T", "G", "G", "C", "A", "T", "A", "G", "A", "C", "T", "T", "G", "T", "G", "T", "A", "T", "A", "A", "A", "A", "G", "A", "A", "T")

# Set color of each nucleotide
my_cols = c("Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Red", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Blue", "Black", "Black", "Black", "Black", "Black", "Black", "Black", "Black")

ggplot(data = miRNA2) + 
  geom_line(mapping = aes(x = Position, y = CPM), colour="red") +
  scale_y_continuous(breaks = seq(0, 60, 10)) +
  ylab("Counts per million") +
  scale_x_continuous(breaks=1:99, labels=my_labs, expand = c(0, 0)) +
  theme(axis.text.x = element_text(color = my_cols, family = "Courier", size = 6),
        panel.grid.minor.x=element_blank(), panel.grid.major.x=element_blank(), panel.grid.minor.y=element_blank(), panel.background = element_blank(),
        axis.line = element_line(colour = "black")) +
xlab("Supercontig_1.420:40270-40368") +
  ggtitle("Sar-Mir-Nov-2") +
  theme(plot.title = element_text(hjust = 0.5))

Upvotes: 4

Views: 7859

Answers (3)

nisetama
nisetama

Reputation: 8943

This sets the breaks and limits automatically, and it also makes sure that the step for the breaks is some power of 10 multiplied by 1, 2, or 5 (and not 3 or 2.5 like sometimes happens with ggplot's automatic breaks), and it draws the plot lines over the panel boundaries and not vice versa (so if there is a line that has the same value as the end of the y-axis, then half of the line doesn't get cut off):

xy=data.frame(x=0:56,y=sample(-3:68,57,replace=T))

candidates=c(sapply(c(1,2,5),\(x)x*10^c(-20:20)))
xstep=candidates[which.min(abs(candidates-max(xy$x)/7))]
xstart=xstep*floor(min(xy$x)/xstep)
xend=xstep*ceiling(max(xy$x)/xstep)
xbreak=seq(xstart,xend,xstep)
ystep=candidates[which.min(abs(candidates-max(xy$y)/5))]
ystart=ystep*floor(min(xy$y)/ystep)
yend=ystep*ceiling(max(xy$y)/ystep)
ybreak=seq(ystart,yend,ystep)

ggplot(xy,aes(x,y))+
geom_hline(yintercept=c(ystart,yend),color="gray50",linewidth=.3,lineend="square")+
geom_vline(xintercept=c(xstart,xend),color="gray50",linewidth=.3,lineend="square")+
geom_line(linewidth=.4)+
labs(x=NULL,y=NULL)+
coord_cartesian(clip="off")+ # don't clip off lines that fall on plot boundaries
scale_x_continuous(limits=c(xstart,xend),breaks=xbreak,expand=c(0,0))+
scale_y_continuous(limits=c(ystart,yend),breaks=ybreak,expand=c(0,0))+
theme(
  axis.text=element_text(size=8,color="black"),
  axis.ticks=element_line(linewidth=.3,color="gray50"),
  axis.ticks.length=unit(.2,"lines"),
  panel.background=element_rect(fill="white"),
  panel.grid=element_blank(),
  plot.margin=margin(.7,.7,.3,.3,"lines")
)

ggsave("1.png",width=5,height=3)

Upvotes: 1

Codutie
Codutie

Reputation: 1127

just add limits = c(0,60) and expand = c(0,0) to your scale_y_continuous:

scale_y_continuous(breaks = seq(0, 60, 10), 
                   limits = c(0,60), 
                   expand = c(0,0))

Upvotes: 8

Djork
Djork

Reputation: 3369

Did you want to set ylim max so that the last break shown is rounded to the nearest 10's? As well as all breaks to be in increments of 10?

You can obtain the current ylim of the ggplot by grabbing the y-range of your gg object ggplot_build(gg)$layout$panel_ranges[[1]]$y.range, and take ceiling of your ylim max to the nearest 10's and similarly set your breaks. This way you can set limits and breaks dynamically depending on the plot.

gg <- ggplot(data = miRNA2) + 
  geom_line(mapping = aes(x = Position, y = CPM), colour="red") +
  scale_y_continuous(breaks = seq(0, 60, 10)) +
  ylab("Counts per million") +
  scale_x_continuous(breaks=1:99, labels=my_labs, expand = c(0, 0)) +
  theme(axis.text.x = element_text(color = my_cols, family = "Courier", size = 6), 
  panel.grid.minor.x=element_blank(), panel.grid.major.x=element_blank(),
  panel.grid.minor.y=element_blank(), panel.background = element_blank(),
  axis.line = element_line(colour = "black")) +
  xlab("Supercontig_1.420:40270-40368") +
  ggtitle("Sar-Mir-Nov-2") +
  theme(plot.title = element_text(hjust = 0.5))


# grab y-range of current gg object
ggplot_build(gg)$layout$panel_ranges[[1]]$y.range
gg_ylim_max <- ggplot_build(gg)$layout$panel_ranges[[1]]$y.range[2]

# decide if you want to ceiling to nearest 10's or 5's
library(plyr)
round_any(gg_ylim_max, 10, f = ceiling) # ceiling 10's
round_any(gg_ylim_max, 5, f = ceiling) # ceiling 5's

Please try this, I don't have your data so I can't tell if it's working for you.

gg_ylim_max_round <- round_any(gg_ylim_max, 10, f = ceiling)
gg + scale_y_continuous(breaks = seq(0, gg_ylim_max_round, 10), limits = c(c(0, gg_ylim_max_round)))

Edited for redundancy of the limits, the code should be correct now.

Upvotes: 2

Related Questions