Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dots misaligned in geom_dotplot #4614

Closed
Marijn1009 opened this issue Sep 14, 2021 · 4 comments · Fixed by #4734
Closed

Dots misaligned in geom_dotplot #4614

Marijn1009 opened this issue Sep 14, 2021 · 4 comments · Fixed by #4734
Labels
bug an unexpected problem or unintended behavior layers 📈

Comments

@Marijn1009
Copy link

Marijn1009 commented Sep 14, 2021

Hello!
I've ran into a problem where the dots of geom_dotplot are not aligned correctly. The problem was described here years ago, but it seems to still be here (and I couldn't find any issue about it so I assume nobody ever filed one). The link also provides a possible solution but no one seems to have a clue if this solution affects anything elsewhere.

library(ggplot2)

data <- data.frame(x = rep(seq(2018, 2021, 1), 15), 
                   y = sample(seq(3, 5, .125), 60, 
                              replace = T))

ggplot(data, aes(factor(x), y)) +
  geom_dotplot(binaxis = "y", stackdir = "center", stackratio = 1)
#> Bin width defaults to 1/30 of the range of the data. Pick better value with `binwidth`.

ggplot(data, aes(factor(x), y)) +
  geom_dotplot(binaxis = "y", stackdir = "center", stackratio = 2) #points shifted to left
#> Bin width defaults to 1/30 of the range of the data. Pick better value with `binwidth`.

ggplot(data, aes(factor(x), y)) +
  geom_dotplot(binaxis = "y", stackdir = "center", stackratio = 0.5) #points shifted to right
#> Bin width defaults to 1/30 of the range of the data. Pick better value with `binwidth`.

Created on 2021-09-14 by the reprex package (v2.0.1)

@yutannihilation
Copy link
Member

The code in question is almost 10-years old. I attempted to dive into the history, but couldn't figure out what's the right thing here...

xpos <- xmm + dotdiamm * (x$stackposition * x$stackratio + (1 - x$stackratio) / 2)

@thomasp85 thomasp85 added bug an unexpected problem or unintended behavior layers 📈 labels Oct 28, 2021
@thomasp85
Copy link
Member

I never use geom_dotplot()and the original dev cannot remember his decisions for doing it like this. I'll feel more comfortable fixing this if someone knowing all of the different behaviours of this geom came forth as a tester for a possible fix. Maybe @mjskay is that person (based on their development of a different version if I remember correctly)?

@mjskay
Copy link
Contributor

mjskay commented Nov 13, 2021

Hmmm.... FWIW, without extensive testing but just from reading the code and comparing it to the approach in ggdist, if I'm correctly understanding the meaning of stackposition here, the approach in ggdist (albeit not actually expressed exactly this way) would amount to doing xpos <- xmm + dotdiamm * x$stackposition * x$stackratio on this line. I can't really figure out a reason for the (1 - x$stackratio) / 2 bit. So in lieu of more extensive testing on geom_dotplot, I guess I can at least say that ggdist::geom_dots doesn't do anything analogous to that, and I haven't encountered any problems so far.

@mjskay
Copy link
Contributor

mjskay commented Feb 12, 2022

I was fixing a somewhat related bug in {ggdist} the other day when the solution to this bug hit me.

The problem that the (1 - x$stackratio) / 2 adjustment is solving is that when stackratio != 1, the base of the first dot in a stack will no longer touch the baseline because the stackratio expands (or contracts) the dot stack away from the origin. For example, using a modified version of geom_dotplot() without (1 - x$stackratio) / 2, notice how the base of these stacks do not touch the line at y = 0:

# using a modified geom_dotplot without the (1 - x$stackratio) / 2 adjustment
ggplot(data.frame(x = c(rep(1, 3), rep(2, 2))), aes(x)) +
  geom_dotplot(binwidth = 0.5, alpha = 0.5, stackdir = "up", stackratio = 1.5) +
  coord_fixed() +
  ylim(-2, 2) +
  xlim(0, 6)

image

The unmodified geom_dotplot() fixes this, but only for stackdir = "up":

# using the main branch of ggplot2 on github
ggplot(data.frame(x = c(rep(1, 3), rep(2, 2))), aes(x)) +
  geom_dotplot(binwidth = 0.5, alpha = 0.5, stackdir = "up", stackratio = 1.5) +
  coord_fixed() +
  ylim(-2, 2) +
  xlim(0, 6)

image

For example, here is stackdir = "down" (@Marijn1009 already provided examples of stackdir = "center" above, and "centerwhole" exhibits similar problems). Notice that the top edges of the dot stacks are not aligned with y = 0 as they should be:

# using the main branch of ggplot2 on github
ggplot(data.frame(x = c(rep(1, 3), rep(2, 2))), aes(x)) +
  geom_dotplot(binwidth = 0.5, alpha = 0.5, stackdir = "down", stackratio = 1.5) +
  coord_fixed() +
  ylim(-2, 2) +
  xlim(0, 6)

image

The solution is that the (1 - x$stackratio) / 2 adjustment on these lines:

xpos <- xmm + dotdiamm * (x$stackposition * x$stackratio + (1 - x$stackratio) / 2)

ypos <- ymm + dotdiamm * (x$stackposition * x$stackratio + (1 - x$stackratio) / 2)

Needs to depend on stackdir:

  • For "up", it should remain (1 - x$stackratio) / 2
  • For "down", it should be reversed: -(1 - x$stackratio) / 2
  • For "center" and "centerwhole", it is unnecessary, and should be 0.

I have a PR incoming shortly with this fix (and tests).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug an unexpected problem or unintended behavior layers 📈
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants