Reputation: 15
I want to create a plot with custom axis tick spacing. What I want to achieve is similar to this plot:
I can specify axis tick locations using breaks argument, but I can't change the distance between them.
dat <- data.frame(x = runif(100), y = runif(100))
ggplot(dat, aes(x,y)) + geom_point() + scale_x_continuous(breaks=c(0,0.1,0.2,0.4,0.8,1)) + scale_y_continuous(breaks=c(0,0.1,0.2,0.4,0.8,1))
What I essentially want is to focus on a specific interval (say 0:0.2) and have bigger spacing for this interval and squish the rest (0.2:1). Right now I do that by creating two graphs for my desired intervals, and glue them together with grid.arrange, but I was wondering if there was a solution that enables me to generate the plot in one go.
This is my current solution:
q1<-ggplot(dat, aes(x,y)) + geom_point() + ylim(c(0.2,1)) + xlim(c(0,0.2))+ theme(axis.text.x = element_blank(), axis.title.x = element_blank(), axis.ticks.x=element_blank())
q2<-ggplot(dat, aes(x,y)) + geom_point() + ylim(c(0.2,1)) + xlim(c(0.2,1))+ theme(axis.text = element_blank(), axis.title = element_blank(), axis.ticks=element_blank())
q3<-ggplot(dat, aes(x,y)) + geom_point() + ylim(c(0,0.2)) + xlim(c(0,0.2))
q4<-ggplot(dat, aes(x,y)) + geom_point() + ylim(c(0.2,1)) + xlim(c(0.2,1))+ theme(axis.text.y = element_blank(), axis.title.y = element_blank(), axis.ticks.y=element_blank())
grid.arrange(q1,q2,q3,q4)
Upvotes: 0
Views: 1589
Reputation: 405
dat <- data.frame(x = runif(100), y = runif(100))
ggplot(dat, aes(x,y)) +
geom_point() +
scale_x_continuous(breaks=c(0,0.1,0.2,0.4,0.8,1)) +
scale_y_continuous(breaks=c(0,0.1,0.2,0.4,0.8,1))
dat$condx <- ifelse(dat$x > 0.2, "x2", "x1")
dat$condy <- ifelse(dat$y > 0.2, "y1", "y2")
dat$condxy <- paste(dat$condx, dat$condy)
ggplot(dat, aes(x, y, group=condxy)) +
geom_point() +
scale_x_continuous(breaks=c(0,0.05,0.1,0.15,0.2,0.4,0.6,0.8,1)) +
scale_y_continuous(breaks=c(0,0.05,0.1,0.15,0.2,0.4,0.6,0.8,1)) +
facet_grid(condy~condx, scales="free")
(Related to Two scales in the same axis)
Regards,
Upvotes: 0
Reputation: 38063
Ok first I'll have to make the obligatory comment that squishing part of the data in a way that disconnects the position on the plot from a direct connection to the data is not a good idea in general.
That said, here is how you can do it. We can make a function factory that produces a transformation object with the scales factor. The function factory accepts a range it should squish and a factor by how much to squish the data. I haven't tested it exhaustively, but I think it works correctly.
library(ggplot2)
library(scales)
squish_trans <- function(range, factor = 10) {
force(range)
force(factor)
forward <- function(x) {
test_between <- x > range[1] & x < range[2]
test_over <- x >= range[2]
between <- ((x - range[1]) / factor) + range[1]
over <- (x - range[2] + diff(range) / factor) + range[1]
ifelse(test_over, over,
ifelse(test_between, between, x))
}
reverse <- function(x) {
test_between <- x > range[1] & x < range[1] + diff(range) / factor
test_over <- x >= range[1] + diff(range) / factor
between <- ((x - range[1]) * factor) + range[1]
over <- (x - range[1]) - diff(range) / factor + range[2]
ifelse(test_over, over,
ifelse(test_between, between, x))
}
trans_new(
"squish_trans",
transform = forward,
inverse = reverse
)
}
Now we simply run the function factory as trans
argument with the range you want to squish. You can notice that the 0.2-1 range (80% of data range) is now 0.08/0.28 ~= 0.28 (~28%) of the axis range because we squish with a factor 10.
dat <- data.frame(x = runif(100), y = runif(100))
ggplot(dat, aes(x,y)) + geom_point() +
scale_x_continuous(breaks=c(0,0.1,0.2,0.4,0.8,1),
trans = squish_trans(c(0.2, Inf))) +
scale_y_continuous(breaks=c(0,0.1,0.2,0.4,0.8,1),
trans = squish_trans(c(0.2, Inf)))
Created on 2021-02-05 by the reprex package (v1.0.0)
Upvotes: 1