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

Allow separate expansion values for lower and upper range limits (v2) #1805

Merged
merged 11 commits into from
Jul 10, 2017

Conversation

huftis
Copy link
Contributor

@huftis huftis commented Oct 1, 2016

Fixes issue #1669.

The expand argument for scale_*_continuous() and scale_*_discrete() now accepts separate expansion constants for the lower and upper range limits.

This is useful for creating bar charts where the bottom of the bars are flush with the x axis but the bars still have some (automatically calculated amount of) space above them:

ggplot(mtcars) +
  geom_bar(aes(x = factor(cyl))) +
  scale_y_continuous(expand = c(0, 0, 0.1, 0))

It can also be useful for line charts, e.g. for counts over time, where one wants to have a ’hard’ lower limit of y = 0, but leave the upper limit unspecified (and perhaps differing between panels), but with some extra space above the highest point on the line. (With symmetrical limits, the extra space above the highest point could cause the lower limit to be negative.)

The syntax for the multiplicative and additive expansion constants has been changed from c(m, a) to c(m_lower, a_lower, m_uppper, a_upper). The old syntax will still work, as length 2 vectors c(m, a) are expanded to c(m, a, m, a) and length 3 vectors are expanded from c(m1, a1, m2) to c(m1, a2, m2, a1).

Note that by default, all graphs should exactly look like they do with the current version of ggplot2.

Some examples (only meant to illustrate the functionality – several don’t make much sense from a graphical point of view):

# Continuous scales
p = ggplot(mtcars) +
      geom_bar(aes(x = factor(cyl)))

# No space below but 10% space above bars
p + scale_y_continuous(expand = c(0, 0, 0.10, 0))

# It also works with facets
p + facet_wrap(~cyl) +
    scale_y_continuous(expand = c(0, 0, 0.05))
p + facet_wrap(~cyl, scales="free_y") +
    scale_y_continuous(expand = c(0, 0, 0.05))
# Note that all the bars should
# look identical in this last example

# Coordinate flipping also works
p + scale_y_continuous(expand = c(.5, 0, 0.05, 0)) +
    coord_flip()
p + scale_y_continuous(expand = c(0, 2, 0, 5)) +
    coord_flip()


# Similar examples for discrete scales
d <- ggplot(subset(diamonds, carat > 1), aes(cut, clarity)) +
  geom_jitter()

d + scale_x_discrete(expand = c(.25, 0))
d + scale_x_discrete(expand = c(0, 1))
d + scale_x_discrete(expand = c(0, 1, 0, 5))
d + scale_x_discrete(expand = c(.25, 0, .5, 0))
d + scale_x_discrete(expand = c(.25, 1, .25, 5))
d + scale_x_discrete(expand = c(.25, 1, .25, 5)) + coord_flip()

The `expand` argument for `scale_*_continuous()` and `scale_*_discrete()`
now accepts separate expansion constants for the lower and upper range limits.

This is useful for creating bar charts where the bottom of the bars
are flush with the x axis but the bars still have some (automatically
calculated amount of) space above them:

```R
ggplot(mtcars) +
  geom_bar(aes(x = factor(cyl))) +
  scale_y_continuous(expand = c(0, 0, 0.1, 0))
```

It can also be useful for line charts, e.g. for counts over time,
where one wants to have a ’hard’ lower limit of y = 0, but leave the
upper limit unspecified (and perhaps differing between panels),
but with some extra space above the highest point on the line.
(With symmetrical limits, the extra space above the highest point
could cause the lower limit to be negative.)

The syntax for the multiplicative and additive expansion
constants has been changed from `c(m, a)` to
`c(m_lower, a_lower, m_uppper, a_upper)`. The old syntax will still
work, as length 2 vectors `c(m, a)` are expanded to `c(m, a, m, a)`
and length 3 vectors are expanded from `c(m1, a1, m2)` to
`c(m1, a2, m2, a1)`. (@huftis, tidyverse#1669)
@hadley
Copy link
Member

hadley commented Oct 2, 2016

I think expand = c(0, 0, 0.1, 0) is hard to understand. Can you please add a helper function with named arguments and documentation? I think it might be best to have mult and add arguments that can take a vector of length 1 or 2.

@huftis
Copy link
Contributor Author

huftis commented Oct 2, 2016

@hadley The reason I used expand = c(0, 0, 0.1, 0) is for backwards compatibility, so that all old code would continue to work. But I guess converting the expand argument to a list could also work, expand = list(mult=c(0, .1), add=c(0,0)). Or are you thinking that I should add a helper function that takes a mult and add argument and converts it into the new c(m1, a1, m2, a2) syntax? (BTW, any suggestion for the name of this function, given that expand_range() and expand_limits() are both taken?)

@hadley
Copy link
Member

hadley commented Oct 3, 2016

Yes, a helper function (possibly returning an S3 object or just a vector). I don't know what to call it either 😞

@hadley
Copy link
Member

hadley commented Oct 4, 2016

Maybe expand_scale()? Or expansion()?

@hadley
Copy link
Member

hadley commented Jan 25, 2017

Are you still interested in this PR? I'm going to be working on ggplot2 off and on for a bit.

@huftis
Copy link
Contributor Author

huftis commented Jan 26, 2017

@hadley Yes, I’m still interested; I’ve just been too busy to take a look at it (or, really, it’s been too low on my priority list for too long). I hope to have a new go at it sometime in the next few weeks. When are you planning a test/beta release of the next ggplot2 version? I’ll try to finish it before that, so that it can be properly tested.

vectors.

Instead of having to manually specify an `expand` argument using
a somewhat confusing syntax (a vector of 2, 3 or 4 numeric values),
it’s now possible to use the user-friendly (and documented)
`expand_scale()` function.

This commit also cleans up the documentation related to the
`expand` argument, which was duplicated in several functions.
The documentation for one of the functions had a no-breaking space,
(between a number and the word ‘units’), which caused R CMD check to
complain about ‘non-ASCII input and no declared encoding’.
This adds a character encoding declaration of UTF-8 to the DESCRIPTION
file to fix this problem.
@huftis
Copy link
Contributor Author

huftis commented Feb 5, 2017

@hadley, I have now added an expand_scale() function for specifying the expansion values, along with documentation and and couple of examples.

One thing I’m not entirely happy with regarding this patch, is that the defaults for expand_scale() don’t duplicate the defaults of mult = .05, add = 0’ for continuous scales and mult = 0, add = 0.6` for discrete scales. It’s not a problem functionality-wise; the defaults do continue to work as before. But it’s not possible change the ‘Usage’ section of the documentation for the scales from

scale_x_discrete(..., expand = waiver(), position = "bottom")

to the more user-friendly

scale_x_discrete(..., expand = expand_scale(), position = "bottom")

since expand_scale() can’t know if it’s a continuous or discrete scale that is being used (and adjust its defaults based on this). I’m not sure if it is possible to fix this.

@hannes101
Copy link

Could this also be implemented for area plots, since especially when using a color scheme with a light color at the bottom it gives the impression of a much bigger area and additionally it kind of wastes space in a publications.
Thanks a lot in advance.
Just a quick'n'dirty example showing the "problem".

 ggplot(melt(dt id.vars = c("Year.and.Quarter"), measure.vars = colnames(dt)[-1])[like(variable,"Gas"),], aes( x = Year.and.Quarter, y = value)) +
        geom_area(aes(fill= variable), position = 'stack') +
        scale_x_yearqtr(format = "%Y-Q%q",n = 8, expand = c(0,0)) +
        theme_bw() +
        scale_fill_brewer(name = "", labels =c(  "Directional"
                                                 , "Horizontal "
                                                 , "Unknown"
                                                 , "Vertical"),direction = -1, palette = my.color.scheme) +
        labs(title = "", x = "Time", y = "Quarterly Gas Production in mmcf ") +
        theme(text=element_text(family="CMU Serif", size=24)
              , strip.text.y = element_text(family="CMU Serif", size=14, colour = "black")
              , legend.position="bottom"
              , plot.margin = unit(c(1,1.5,1,1), "cm")) 

grafik

Copy link
Member

@hadley hadley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple of tiny style issues and it'll be ready to merge 😄

R/utilities.r Outdated
stopifnot(is.numeric(mult) && is.numeric(add))
stopifnot((length(mult) %in% 1:2) && (length(add) %in% 1:2))

mult = rep(mult, length.out = 2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please use <- here

R/utilities.r Outdated

mult = rep(mult, length.out = 2)
add = rep(add, length.out = 2)
expand = c(mult[1], add[1], mult[2], add[2])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for expand variable

@huftis
Copy link
Contributor Author

huftis commented Jul 9, 2017

@hannes101 This feature works with scales in general, so yes, it should work with area plots too.

@huftis
Copy link
Contributor Author

huftis commented Jul 9, 2017

@hadley I’ve now fixed the issues you mentioned and updated the PR to cleanly apply to master.

Copy link
Member

@hadley hadley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One tiny last change and we can merge 😄

@@ -172,6 +172,76 @@ rescale01 <- function(x) {
(x - rng[1]) / (rng[2] - rng[1])
}

#' Similar to expand_range(), but taking a vector ‘expand’
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's @noRd this

@hadley
Copy link
Member

hadley commented Jul 10, 2017

Thanks for all your hard work on this!

@hadley hadley merged commit 4255cd8 into tidyverse:master Jul 10, 2017
karawoo pushed a commit to karawoo/ggplot2 that referenced this pull request Jul 14, 2017
…tidyverse#1805)

* Allow separate expansion values for lower and upper range limits.

The `expand` argument for `scale_*_continuous()` and `scale_*_discrete()`
now accepts separate expansion constants for the lower and upper range limits.

This is useful for creating bar charts where the bottom of the bars
are flush with the x axis but the bars still have some (automatically
calculated amount of) space above them:

```R
ggplot(mtcars) +
  geom_bar(aes(x = factor(cyl))) +
  scale_y_continuous(expand = c(0, 0, 0.1, 0))
```

It can also be useful for line charts, e.g. for counts over time,
where one wants to have a ’hard’ lower limit of y = 0, but leave the
upper limit unspecified (and perhaps differing between panels),
but with some extra space above the highest point on the line.
(With symmetrical limits, the extra space above the highest point
could cause the lower limit to be negative.)

The syntax for the multiplicative and additive expansion
constants has been changed from `c(m, a)` to
`c(m_lower, a_lower, m_uppper, a_upper)`. The old syntax will still
work, as length 2 vectors `c(m, a)` are expanded to `c(m, a, m, a)`
and length 3 vectors are expanded from `c(m1, a1, m2)` to
`c(m1, a2, m2, a1)`. (@huftis, tidyverse#1669)

* Added `expand_scale()` function for easier generation of scale expansion
vectors.

Instead of having to manually specify an `expand` argument using
a somewhat confusing syntax (a vector of 2, 3 or 4 numeric values),
it’s now possible to use the user-friendly (and documented)
`expand_scale()` function.

This commit also cleans up the documentation related to the
`expand` argument, which was duplicated in several functions.

* Added UTF-8 character encoding declaration to DESCRIPTION.

The documentation for one of the functions had a no-breaking space,
(between a number and the word ‘units’), which caused R CMD check to
complain about ‘non-ASCII input and no declared encoding’.
This adds a character encoding declaration of UTF-8 to the DESCRIPTION
file to fix this problem.

* Fixed some style issues.

* Updated and regenerated documentation.

* Specify character encoding used for documentation.

* Minor grammar improvement in documentation.

* Don’t generate documentation for internal function expand_range4().
@lock
Copy link

lock bot commented Jan 18, 2019

This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/

@lock lock bot locked and limited conversation to collaborators Jan 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants