Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot2 graph, scale axis from a certain point on

Tags:

r

ggplot2

How do i scale an axis with ggplot2 beginning at a certain point. Let's say we have a range from 0 to 100 and most values are within the range 1 to 10 and one value is at 100.

require('data.table')
require('ggplot2')

test <- data.table(x=1:10,y=c(seq(1,9),100))

ggplot(test, aes(x=x,y=y)) + geom_point(size=5)

enter image description here

I would like to create a graph with an y-scale from 1 to 10 by 1 and afterwards by 10 so the space between the value 9 and 100 gets "smaller" in the graph.

Update:

The way of eipi10 works perfect for what i want to achieve. Just one more detail i am struggling with. How do i get rid of the 2nd legend and keep the right ratio in the final plot?

enter image description here

and the code for the plot:

test <- data.table(x=1:10,y=c(seq(1,9),100))

p1 = ggplot(test, aes(x=x,y=y,color=x)) + 
  geom_point(size=5) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(-0.1,10)) +
  scale_y_continuous(breaks=0:10) +
  theme(plot.margin=unit(c(0,0.5,0,0),"lines"))

p2 = ggplot(test, aes(x=x,y=y,color=x)) + 
  geom_point(size=5) + #geom_point(size=5,show.legend=FALSE) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(40,110)) +
  scale_y_continuous(breaks=c(50,100)) +
  theme(plot.margin=unit(c(0,0.5,-0.5,0), "lines"),
       axis.title.x=element_blank(),
       axis.ticks.x=element_blank(),
       axis.text.x=element_blank(),
       legend.position="none") +
 labs(y="")

gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)
grid.arrange(gB, gA, ncol=1, heights=c(0.15,0.85))

Update 2:

An example of the final result. Thanks again to eipi10 and his great support! enter image description here

like image 777
RandomDude Avatar asked Nov 26 '15 15:11

RandomDude


1 Answers

A log transformation will do that:

require('data.table')
require('ggplot2')
library(scales)

test <- data.table(x=1:10,y=c(seq(1,9),100))

ggplot(test, aes(x=x,y=y)) + 
  geom_point(size=5) +
  scale_y_log10(breaks=c(1,3,10,30,100))

enter image description here

UPDATE: There's no easy way to do a broken axis with ggplot2 (because ggplot2 doesn't allow you to (easily) do things that are considered bad practice), but here's a way to get what you're looking for. (Just don't tell Hadley I told you.)

library(data.table)
library(ggplot2)
library(scales)
library(grid)
library(gridExtra)

test <- data.table(x=1:10,y=c(seq(1,9),100))

The overall strategy is to make two separate plots, one for y>=10 and one for y<10 and then put them together. We'll change the plot margins in order to control the amount of space between the top of the bottom plot and the bottom of the top plot. We'll also get rid of the x-axis ticks and labels on the top plot.

Bottom plot (y < 10):

p1 = ggplot(test[test$y<10,], aes(x=x,y=y)) + 
  geom_point(size=5) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(-0.1,10)) +
  scale_y_continuous(breaks=0:10) +
  theme(plot.margin=unit(c(0,0.5,0,0),"lines"))

Top plot (y >= 10). For this one, we get rid of the x axis labels and tick marks:

p2 = ggplot(test[test$y>=10,], aes(x=x,y=y)) + 
  geom_point(size=5) +
  scale_x_continuous(limits=c(0,10)) +
  coord_cartesian(ylim=c(10.0,110)) +
  scale_y_continuous(breaks=c(50,100)) +
  theme(plot.margin=unit(c(0,0.5,-0.5,0), "lines"),
        axis.title.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.x=element_blank()) +
  labs(y="")

Left align the two plots (based on this SO answer):

gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)

Arrange both plots together. The heights argument determines the proportion of vertical space allotted to each plot:

grid.arrange(gB, gA, ncol=1, heights=c(0.15,0.85))

enter image description here

UPDATE 2: To include a legend, but also ensure that the plots are properly right justified, do the following:

1) Run the code in your updated question to create plots p1 and p2, where only p1 has a legend.

2) Extract legend as a separate grob using the function below (from this SO answer).

3) Remove the legend from p1.

4) Lay out the plots and the legend using grid.arrange and arrangeGrob.

# Function to extract the legend as a stand-alone grob
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  legend
}

# Extract the legend from p1
leg = g_legend(p1)

# Remove the legend from p1
p1 = p1 + theme(legend.position="none")

# Left justify the two plots
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)

# Lay out the plots and the legend
grid.arrange(arrangeGrob(gB, gA, ncol=1, heights=c(0.15,0.85)),
             leg, ncol=2, widths=c(0.9,0.1))

enter image description here

like image 66
eipi10 Avatar answered Sep 28 '22 22:09

eipi10