Reputation: 1141
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)
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?
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!
Upvotes: 5
Views: 3599
Reputation: 93761
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))
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))
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))
Upvotes: 5