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

Feature request: Add position argument to geom_vline and geom_hline #4285

Closed
billdenney opened this issue Dec 4, 2020 · 12 comments · Fixed by #5965
Closed

Feature request: Add position argument to geom_vline and geom_hline #4285

billdenney opened this issue Dec 4, 2020 · 12 comments · Fixed by #5965
Labels
feature a feature request or enhancement layers 📈

Comments

@billdenney
Copy link
Contributor

When working with a discrete scale, I'd like to be able to nudge a vline a bit. But, geom_vline() doesn't use the position argument that I would have expected. It would be helpful to add a position argument to geom_vline() and geom_hline() to allow nudging the position.

In this example, I'd like to have the red vertical line go between the "1" and "2" on the horizontal axis.

library(ggplot2)
mydata <-
  data.frame(
    x=factor(c("1", "2")),
    y=3:4
  )
ggplot(mydata, aes(x=x, y=y)) +
  geom_point() +
  geom_vline(xintercept="2", colour="red")

ggplot(mydata, aes(x=x, y=y)) +
  geom_point() +
  geom_vline(xintercept="2", colour="red", position=position_nudge(x=-0.5))
#> Warning: Ignoring unknown parameters: position

Created on 2020-12-04 by the reprex package (v0.3.0)

@has2k1
Copy link
Contributor

has2k1 commented Dec 4, 2020 via email

@yutannihilation
Copy link
Member

yutannihilation commented Dec 6, 2020

I'm for adding position argument to geom_vline() and geom_hline(). I don't see any reason to prohibit tweaking on the position, even if not so many people need this.

Use after_scale mapping evaluation.

I think it doesn't work. Values mapped to a discrete scale is still discrete.

library(ggplot2)

mydata <-
  data.frame(
    x=factor(c("1", "2")),
    y=3:4
  )

ggplot(mydata, aes(x, y)) +
  geom_point() +
  geom_vline(
    aes(xintercept = stage(x, after_scale = xintercept - 0.5)),
    data = data.frame(x = "2"),
    colour = "red"
  )
#> Error in xintercept - 0.5: non-numeric argument to binary operator

@billdenney
Copy link
Contributor Author

I hadn't heard of after_scale() before this. Thanks for pointing it out. Also, the first way that I thought would work didn't. What is incorrect about using after_scale() directly where using stage() works?

With scale() and @yutannihilation's example, I was able to get the code working (see below), but if my method is the best way to do it, then it would not easily match the intent of the code. (Where did the 1.5 come from?) While the intent with position_nudge() from the original example is clear, to me. (I want this shifted to be a half-step below "2".)

Is there a better way to use after_scale than what I came up with below?

I agree with @yutannihilation, adding a position argument is a simpler solution, and it would be consistent with many other geom_*()s.

library(ggplot2)

mydata <-
  data.frame(
    x=factor(c("1", "2")),
    y=3:4
  )

ggplot(mydata, aes(x, y)) +
  geom_point() +
  geom_vline(
    aes(xintercept =  after_scale(1.5)),
    colour = "red"
  )
#> Error: geom_vline requires the following missing aesthetics: xintercept

ggplot(mydata, aes(x, y)) +
  geom_point() +
  geom_vline(
    aes(xintercept =  stage(x, after_scale = 1.5)),
    colour = "red"
  )

Created on 2020-12-06 by the reprex package (v0.3.0)

@smouksassi
Copy link

the below works not sure what I am missing ?

library(ggplot2)
mydata <-
  data.frame(
    x=factor(c("1", "2","3")),
    y=3:5
  )
ggplot(mydata, aes(x, y)) +
  geom_point(size=3) +
  geom_vline(
    aes(xintercept =  as.numeric(x) - 0.5),alpha=0.2,size=5,
    colour = "red"
  )

Created on 2020-12-06 by the reprex package (v0.3.0)

@billdenney
Copy link
Contributor Author

@smouksassi, I am surprised that works because it's providing a continuous value to a discrete scale. Thanks for pointing out that it does work.

Your example does rely on x being an explicit factor and the factor levels being the same while the original geom_vline() example was able to use a simpler character value. For my real use case, I have datasets that will have different factor levels, but there will always be one named "Baseline". I want to put the vertical line 0.5 points away from the location of "Baseline", so I wanted to automatically get the location of "Baseline", and nudge from there.

@yutannihilation
Copy link
Member

For my real use case, I have datasets that will have different factor levels, but there will always be one named "Baseline". I want to put the vertical line 0.5 points away from the location of "Baseline", so I wanted to automatically get the location of "Baseline", and nudge from there.

If your x axis is virtually continuous, it might be easier to use numeric values and add the corresponding labels.

@has2k1
Copy link
Contributor

has2k1 commented Dec 6, 2020

What is incorrect about using after_scale() directly where using stage() works?

The after_scale mapping is evaluated after a variable has been mapped to a value by the scale. after_scale allows you to modify the mapped value, but the variable has to come from somewhere. Either mapped from the dataframe or calculated by the stat. Using stage allows you to map the variable in the dataframe (as geom_vline requires it), then modify it after the scale has handled it.

@smouksassi, I am surprised that works because it's providing a continuous value to a discrete scale.

At that point the type of scale does not matter, the categorisation between discrete scale and continuous scale is at a higher level of abstraction. Real (continuous) numbers get plotted.

@billdenney
Copy link
Contributor Author

I don't think of the axis as "virtually continuous". It is a discrete axis where I want to separate the times that are before the discrete value of "Baseline" from the times at and after "Baseline".

To me, it is discrete with two layers of discrete categories: The value shown on the x-axis and a grouping of values shown on the x-axis (before and at or after "Baseline"). The vline is to illustrate the second layer.

@smouksassi
Copy link

this has always worked numeric on top of discrete ( as mentioned above at the end it is 1 ,2 ,3 that are plotted) but the reverse is not true when you supply discrete on numeric scale this will error out

@has2k1
Copy link
Contributor

has2k1 commented Dec 6, 2020

@smouksassi is right. It is okay and helpful to think of the axis. The discrete scale provides "macro organisation" for the groups e.g this boxplot/violin is centered at 1, that one is centered at 2 ..., then the boxes/violins are calculated in continuous form around those central values.

@billdenney
Copy link
Contributor Author

Ah, now I understand better what you were both meaning, thank you. When you were saying that it was "virtually continuous" you were referring to the way that ggplot handles it and not the way that my data is logically considered. Thanks!

Looping back to the original request, I do think that a position argument to geom_vline() and geom_hline() could be helpful, but I do have several other ways to get what I'm wanting if others do not agree.

@smouksassi
Copy link

I agree that a position argument could be helpful see below when faceting and with free_scales the above will not work.
I get that you expect the geom_vline positioning would operate like the geom point/ line positions ?

library(ggplot2)
mydata <-
  data.frame(
    x=factor(c("1", "2","3")),
    y=c(3,4,5)
  )
mydata$splits <- factor(mydata$x, labels=c("baseline","Cycle 1","Cycle 1"))

ggplot(mydata, aes(x, y)) +
  geom_point(size=3,position=position_nudge(x=-0.1)) +
  geom_vline(
    aes(xintercept = as.numeric(x)+0.1) ,
    alpha=0.2,size=5,
    colour = "red"
  )+
  facet_grid(~splits,switch = "x", scales = "free_x", space = "free_x")+
  theme(strip.placement = "outside")

Created on 2020-12-07 by the reprex package (v0.3.0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature a feature request or enhancement layers 📈
Projects
None yet
5 participants