ggplot2 icon indicating copy to clipboard operation
ggplot2 copied to clipboard

When x values contain 0, using coord_trans("sqrt") removes the axis line

Open kdarras opened this issue 1 year ago • 4 comments

ggplot(iris,aes(Petal.Length,Sepal.Width))+
  geom_point()+
  coord_trans(x="sqrt")+
  theme(axis.line.x = element_line(color="black"))

image

iris$Petal.Length[1]=0
ggplot(iris,aes(Petal.Length,Sepal.Width))+
  geom_point()+
  coord_trans(x="sqrt")+
  theme(axis.line.x = element_line(color="black"))

image

I believe the axis line should stay preserved, since sqrt(0)=0, or is there a conceptual error in my reasoning?

kdarras avatar May 30 '24 14:05 kdarras

You're right that the axis should be preserved. I think it probably has an issue with calculating the left-most side of the axis that is smaller than 0. I'll have to dig a little bit to see what is going on.

teunbrand avatar May 30 '24 14:05 teunbrand

This isn't an issue with the axis, it happens as well with regular lines. Notice how the line disappears when 0 is included in the limits.

library(ggplot2)

p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  coord_trans(x = "sqrt")

p + annotate("line", x = c(-Inf, 4), y = 30, colour = "red", linewidth = 5)

last_plot() +
  xlim(c(0, NA))

Created on 2024-05-31 with reprex v2.1.0

It is most likely a coord munching artefact.

teunbrand avatar May 31 '24 07:05 teunbrand

I can't currently see an elegant solution to this problem. Essentially, the scale expension produces negative values that cannot be transformed properly. We faced this in scale_x_sqrt() break calculations too, but for coord transforms we cannot simply squish the limits to the domain of the tranformation.

Instead, I'll suggest the following workaround, where we make a new transformation that will just be sqrt() for all positive values, but sign-preserves sqrt(abs(x)) for negative values. This was previously suggested here as well.

library(ggplot2)
library(scales)

sqrt2 <- new_transform(
  "sqrt2",
  transform = \(x) sign(x) * sqrt(abs(x)),
  inverse = \(x) sign(x) * abs(x)^2
)

plot(sqrt2, xlim = c(-5, 5))

ggplot(iris,aes(Petal.Length,Sepal.Width))+
  geom_point()+
  coord_trans(x=sqrt2, xlim = c(0, NA))+
  theme(axis.line.x = element_line(color="black"))

Created on 2024-06-03 with reprex v2.1.0

teunbrand avatar Jun 03 '24 08:06 teunbrand

This did the trick, thanks Teun!

kdarras avatar Jun 04 '24 14:06 kdarras