tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.39k stars 2k forks source link

Wrong x range when using coord_cartesian() with zero range xlim and expand=FALSE #3531

Open wch opened 4 years ago

wch commented 4 years ago

When coord_cartesian() is called a zero-range xlim and expand=FALSE, the x value appears to be treated as a factor, and all points are in the plot.

ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  coord_cartesian(xlim = c(5, 5), expand = FALSE)

image

thomasp85 commented 4 years ago

I agree the current situation is not good, but how would you envision showing a zero-range scale with no expansion?

wch commented 4 years ago

Hm, that's a good question. Maybe it would be reasonable to use a tiny value for expand?

For a context, this issue came up in this shiny app: https://gallery.shinyapps.io/105-plot-interaction-zoom/ In the middle plot, if you select a zero-width rectangle, the right plot looks like the one I included above. It's easiest to create a zero-width rectangle if you first create a rectangle (and release the mouse button), then drag one of the sides to meet the other one.

yutannihilation commented 4 years ago

Maybe it would be reasonable to use a tiny value for expand?

I understand it would be useful if ggplot2 does this, but I think it's not easy for a coord to know how tiny is tiny enough.

expand = FALSE + zero-width range can be detected when setting view scales:

https://github.com/tidyverse/ggplot2/blob/6f5ffea70e80ce3aa076fb9da8a6b0ec7ebfbc51/R/layout.R#L199-L213

https://github.com/tidyverse/ggplot2/blob/6f5ffea70e80ce3aa076fb9da8a6b0ec7ebfbc51/R/coord-cartesian-.r#L99-L104

or more precisely here:

https://github.com/tidyverse/ggplot2/blob/6f5ffea70e80ce3aa076fb9da8a6b0ec7ebfbc51/R/scale-expansion.r#L156-L158

So, we might be able to add some expansion here, but, since Layout and Coord have no acccess to the data (or the range of the data) here, the proper width cannot be determined.

On the other hand, a view scale can know both the range and the data on rendering, so resolution(x) can be used for adjusting the limit.

https://github.com/tidyverse/ggplot2/blob/6f5ffea70e80ce3aa076fb9da8a6b0ec7ebfbc51/R/scale-view.r#L130-L132

But, the problem is it's difficult to warn with a meaningful message because a view scale doesn't know it's context, iirc...

# c.f. https://github.com/tidyverse/ggplot2/commit/16e34032d1951f51c31d8fd109c4fb5bb3622444
devtools::load_all("~/repo/ggplot2")
#> Loading ggplot2

ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  coord_cartesian(xlim = c(5, 5), expand = FALSE)
#> Warning: A zero-width range is specified for coord

#> Warning: A zero-width range is specified for coord

#> Warning: A zero-width range is specified for coord

#> Warning: A zero-width range is specified for coord

Created on 2019-10-27 by the reprex package (v0.3.0)

teunbrand commented 4 months ago

Just as a small note, the rescale() function declares anything with zero-range to be mean(to), which is why all points show up halfway the x-axis in the first example.

scales::rescale(1:10, to = c(0, 1), from = c(5, 5))
#>  [1] 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5

Created on 2024-02-20 with reprex v2.1.0