Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add a new continuous colour/fill scale using colorbrewer colours #439

Closed
wants to merge 7 commits into from

6 participants

@jiho

It fetches 6 colours from a colorbrewer palette and feeds them to gradientn. It gives very nice results even if the palettes were not intended for that use originally.

Ideally, the regular brewer scale should be able to deal with this: use scale_colour/fill_brewer() and provide a continuous or a discrete scale depending on the data... but this may run again into the problem that the data is only known at render time or something like this. Anyhow, I couldn't figure out how to do that with the current state of the code so a created new functions. The names (scale_colour/fill_brewerc) are clearly not very inspired so I am completely open to suggestions.

@jiho jiho Add a new continuous colour/fill scale using colorbrewer colours
It fetches 6 colours from a colorbrewer palette and feeds them to gradientn. It gives very nice results even if the palettes were not intended for that use originally.
0418d57
@jiho

This is an example map produced with the "Spectral" palette (and stereographic projection in coord_map, Yay!):

image

For those who want to know, this is the average
temperature at the sea surface in summer.

@wch
Collaborator

I think you'll want to add an alias for the American spelling also: scale_color_brewerc

@hadley hadley commented on the diff
R/scale-brewer.r
@@ -38,6 +38,30 @@ scale_fill_brewer <- function(..., type = "seq", palette = 1) {
discrete_scale("fill", "brewer", brewer_pal(type, palette), ...)
}
+#' @export
@hadley Owner
hadley added a note

Can you also add a few words to the main doc mentioning that it does both continuous and discrete variables?

@jiho
jiho added a note

Is commit b5fe2d4 enough?

@hadley Owner
hadley added a note

Maybe mention that continuous colours are smoothly interpolated discrete colours, and have not be tested like the discrete colours have.

@jiho
jiho added a note

OK, I expanded the description in commit afda6e9. Let me know if the text is OK.

(I also committed the .Rd file this time, while I forgot on the previous commit)

@hadley Owner
hadley added a note

Much better, but can you please break the documentation lines at ~80 characters?

@jiho
jiho added a note

I think this should be the text editor's job (and TextMate actually does this quite well now) rather than mine (or yours) and I also feel that "justifying" text manually like this complicates diffs when one wants to add a word or two and has to shift every subsequent line... but I did ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@hadley
Owner

I like the idea, but I'm not a big fan of the name (I don't like the compounding). Any other ideas?

jiho added some commits
@jiho jiho Expand documentation of scale_brewer
As per Hadley's request: "add a few words to the main doc mentioning
that it does both continuous and discrete variables""
b5fe2d4
@jiho jiho Further expand the description of scale_brewer
Give more precisions regarding the intent of the original colours and how
ggplot2 modifies them (in the continuous case).
afda6e9
@jiho jiho Break lines at 80 characters f03b072
@jiho

What about scale_***_distiller to signify that it goes a bit further than "brewer". That's not very discoverable (to say the least) but is kinda fun.

@jiho

Just realized there might be some unintended association with Acrobat Distiller and the production of PDFs etc. Did anyone else think of this?

@jiho

So, what about scale_***_distiller? Opinions anyone? I know I won't be able to find a better name, but native english speakers might.

@BrianDiggs

The only thing I can think of would require overhauling all the color/fill names: making the method of generation of the levels a suffix. So this would be scale_***_continuous_brewer, and the current scale_***_brewer would be scale_***_discrete_brewer; scale_***_gradient would be scale_***_continuous_gradient; etc. However, I am not sure that it would be worth it (even with the original names being maintained as aliases for backwards compatibility).

@hadley
Owner

I like scale_*_distiller - if you make the change, I'm happy to merge the pull request.

@baptiste

It's always seemed kind of odd to me that Brewer palettes (and, if they were to be implemented, those of dichromat) would have their own special syntax in ggplot2. Should we consider the possibility of hard-coding these particular colour values in ggplot2 (or package scales, presumably), independently of the original package, and make a more consistent interface to all these special cases? It could even be part of a new colour package, defining a general structure to define and access colour palettes.
The weird contraints of RColorBrewer (n >=3 for "Set1" ??), the absence of continuous versions, and the inconsistent naming scheme are somewhat confusing in the otherwise consistent ggplot2 framework.

@jiho

I agree with baptiste though. I think there should be two colour scales: scale_colour_discrete and scale_colour_continuous and the palette argument should determine which colours to use. For the discrete scale, the default could be "hue" and that would be the current behaviour, or the appropriate palettes from ColorBrewer or dichromat.

But that would probably break too much pre-existing code to be viable...

@baptiste

But that would probably break too much pre-existing code to be viable...

not necessarily: if scale_colour_brewer() became merely an alias for scale_colour_discrete(palette = ...) the more general functions would not have to break anything.

@hadley
Owner

I don't particularly see the appeal of collapsing scales with rather different arguments in to one function - I think two many r functions do that already, and it's rather confusing. A function should do one thing well.

@hadley
Owner

I don't particularly see the appeal of collapsing scales with rather different arguments in to one function - I think two many r functions do that already, and it's rather confusing. A function should do one thing well.

@jiho
@baptiste

I don't particularly see the appeal of collapsing scales with rather different arguments in to one function - I think two many r functions do that already, and it's rather confusing. A function should do one thing well.

I'm not sure; if a grammar of graphic does such a good job at combining heaps of different plot types into a single, consistent framework with one top-level function (ggplot), why couldn't we aim for the same approach with scales?

It seems to me that choosing a colour scale is conceptually similar to choosing a type of plot and playing with variations, from a user's perspective.
Having a wild variety of different colour functions that inherit their name from the particular colour package they come from, or the type of scale that they represent, or something else, ... seems more confusing to me than one or two generic functions, with good defaults, that accept one consistent argument for fine-tuning the appearance (namely, the palette of colours).

@jiho

It's quite different from the problem at hand but while we are on the topic of scales and since many interested parties are watching the topic, here is another suggestion: issue #578.

Edit: wow, it actually got automatically referenced here. Nice. Thanks github.

@hadley
Owner

Could you please rebase/merge against master, re-document with the development version of roxygen2 (install_github("klutometis/roxygen) and resubmit?

@hadley hadley closed this
@krlmlr

@jiho: I have combined this pull request with your other change that implements reverse Brewer scales, fully maintaining your authorship (#830). @hadley prefers two separate pull requests. Would you mind if I prepared the two pull requests based on your changes?

@jiho

Thanks for the work but since the two need to stay separate I've done two P-R already. Rebasing this one was kind of a mess but it is now done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 14, 2012
  1. @jiho

    Add a new continuous colour/fill scale using colorbrewer colours

    jiho authored
    It fetches 6 colours from a colorbrewer palette and feeds them to gradientn. It gives very nice results even if the palettes were not intended for that use originally.
Commits on Mar 27, 2012
  1. @jiho
Commits on Apr 11, 2012
  1. @jiho

    Expand documentation of scale_brewer

    jiho authored
    As per Hadley's request: "add a few words to the main doc mentioning
    that it does both continuous and discrete variables""
  2. @jiho

    Further expand the description of scale_brewer

    jiho authored
    Give more precisions regarding the intent of the original colours and how
    ggplot2 modifies them (in the continuous case).
  3. @jiho

    Break lines at 80 characters

    jiho authored
Commits on Jun 10, 2012
  1. @jiho
  2. @jiho
This page is out of date. Refresh to see the latest.
View
3  NAMESPACE
@@ -112,6 +112,7 @@ export(scale_area)
export(scale_color_brewer)
export(scale_color_continuous)
export(scale_color_discrete)
+export(scale_color_distiller)
export(scale_color_gradient)
export(scale_color_gradient2)
export(scale_color_gradientn)
@@ -122,6 +123,7 @@ export(scale_color_manual)
export(scale_colour_brewer)
export(scale_colour_continuous)
export(scale_colour_discrete)
+export(scale_colour_distiller)
export(scale_colour_gradient)
export(scale_colour_gradient2)
export(scale_colour_gradientn)
@@ -132,6 +134,7 @@ export(scale_colour_manual)
export(scale_fill_brewer)
export(scale_fill_continuous)
export(scale_fill_discrete)
+export(scale_fill_distiller)
export(scale_fill_gradient)
export(scale_fill_gradient2)
export(scale_fill_gradientn)
View
51 R/scale-brewer.r
@@ -1,9 +1,20 @@
#' Sequential, diverging and qualitative colour scales from colorbrewer.org
#'
+#' Create colour scales based on ColorBrewer colours.
+#'
+#' ColorBrewer provides sequential, diverging and qualitative colour schemes
+#' which are particularly suited and tested to display discrete values (levels
+#' of a factor) on a map. ggplot2 can use those colours in discrete scales. It
+#' also allows to smoothly interpolate the colours to a continuous scale,
+#' although the original colour schemes (particularly the qualitative ones)
+#' were not intended for this. The perceptual result is left to the
+#' appreciation of the user.
+#'
#' See \url{http://colorbrewer2.org} for more information.
#'
#' @inheritParams scales::brewer_pal
#' @inheritParams scale_colour_hue
+#' @inheritParams scale_colour_gradient
#' @family colour scales
#' @rdname scale_brewer
#' @export
@@ -28,6 +39,22 @@
#' ggplot(diamonds, aes(x=price, fill=cut)) +
#' geom_histogram(position="dodge", binwidth=1000) +
#' scale_fill_brewer()
+#'
+#' # Generate map data
+#' library(reshape2) # for melt
+#' volcano3d <- melt(volcano)
+#' names(volcano3d) <- c("x", "y", "z")
+#'
+#' # Basic plot
+#' v <- ggplot() + geom_tile(aes(x=x, y=y, fill=z), data=volcano3d)
+#' v
+#' v + scale_fill_distiller()
+#' v + scale_fill_distiller(palette=2)
+#' v + scale_fill_distiller(type="div")
+#' v + scale_fill_distiller(palette="Spectral")
+#' v + scale_fill_distiller(palette="Spectral", trans="reverse")
+#' v + scale_fill_distiller(type="qual")
+#' # Not appropriate for continuous data, issues a warning
scale_colour_brewer <- function(..., type = "seq", palette = 1) {
discrete_scale("colour", "brewer", brewer_pal(type, palette), ...)
}
@@ -38,6 +65,30 @@ scale_fill_brewer <- function(..., type = "seq", palette = 1) {
discrete_scale("fill", "brewer", brewer_pal(type, palette), ...)
}
+#' @export
@hadley Owner
hadley added a note

Can you also add a few words to the main doc mentioning that it does both continuous and discrete variables?

@jiho
jiho added a note

Is commit b5fe2d4 enough?

@hadley Owner
hadley added a note

Maybe mention that continuous colours are smoothly interpolated discrete colours, and have not be tested like the discrete colours have.

@jiho
jiho added a note

OK, I expanded the description in commit afda6e9. Let me know if the text is OK.

(I also committed the .Rd file this time, while I forgot on the previous commit)

@hadley Owner
hadley added a note

Much better, but can you please break the documentation lines at ~80 characters?

@jiho
jiho added a note

I think this should be the text editor's job (and TextMate actually does this quite well now) rather than mine (or yours) and I also feel that "justifying" text manually like this complicates diffs when one wants to add a word or two and has to shift every subsequent line... but I did ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+#' @rdname scale_brewer
+scale_colour_distiller <- function(..., type = "seq", palette = 1, values = NULL, space = "Lab", na.value = "grey50") {
+ # warn about using a qualitative brewer palette to generate the gradient
+ type <- match.arg(type, c("seq", "div", "qual"))
+ if (type == "qual") {
+ warning("Using a discrete colour palette in a continuous scale.\n Consider using type=\"seq\" or type=\"div\" instead")
+ }
+ continuous_scale("colour", "distiller",
+ gradient_n_pal(brewer_pal(type, palette)(6), values, space), na.value = na.value, ...)
+ # NB: 6 colours per palette gives nice gradients; more results in more saturated colours which do not look as good
+}
+
+#' @export
+#' @rdname scale_brewer
+scale_fill_distiller <- function(..., type = "seq", palette = 1, values = NULL, space = "Lab", na.value = "grey50") {
+ type <- match.arg(type, c("seq", "div", "qual"))
+ if (type == "qual") {
+ warning("Using a discrete colour palette in a continuous scale.\n Consider using type=\"seq\" or type=\"div\" instead")
+ }
+ continuous_scale("fill", "distiller",
+ gradient_n_pal(brewer_pal(type, palette)(6), values, space), na.value = na.value, ...)
+}
+
# icon.brewer <- function() {
# rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9), width=0.21,
# gp=gpar(fill=RColorBrewer::brewer.pal(5, "PuOr"), col=NA)
View
4 R/zxx.r
@@ -23,6 +23,10 @@ scale_fill_continuous <- scale_fill_gradient
scale_color_brewer <- scale_colour_brewer
#' @export
+#' @rdname scale_brewer
+scale_color_distiller <- scale_colour_distiller
+
+#' @export
#' @rdname scale_gradient
scale_color_continuous <- scale_colour_gradient
View
6 man/coord_fixed.Rd
@@ -33,9 +33,9 @@
# ensures that the ranges of axes are equal to the specified ratio by
# adjusting the plot aspect ratio
-qplot(mpg, wt, data = mtcars) + coord_equal(ratio = 1)
-qplot(mpg, wt, data = mtcars) + coord_equal(ratio = 5)
-qplot(mpg, wt, data = mtcars) + coord_equal(ratio = 1/5)
+qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 1)
+qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 5)
+qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 1/5)
# Resize the plot to see that the specified aspect ratio is maintained
}
View
43 man/scale_brewer.Rd
@@ -1,14 +1,26 @@
\name{scale_colour_brewer}
\alias{scale_color_brewer}
+\alias{scale_color_distiller}
\alias{scale_colour_brewer}
+\alias{scale_colour_distiller}
\alias{scale_fill_brewer}
+\alias{scale_fill_distiller}
\title{Sequential, diverging and qualitative colour scales from colorbrewer.org}
\usage{
scale_colour_brewer(..., type = "seq", palette = 1)
scale_fill_brewer(..., type = "seq", palette = 1)
+ scale_colour_distiller(..., type = "seq", palette = 1,
+ values = NULL, space = "Lab", na.value = "grey50")
+
+ scale_fill_distiller(..., type = "seq", palette = 1,
+ values = NULL, space = "Lab", na.value = "grey50")
+
scale_color_brewer(..., type = "seq", palette = 1)
+
+ scale_color_distiller(..., type = "seq", palette = 1,
+ values = NULL, space = "Lab", na.value = "grey50")
}
\arguments{
\item{type}{One of seq (sequential), div (diverging) or
@@ -21,8 +33,23 @@
\item{...}{Other arguments passed on to
\code{\link{continuous_scale}} to control name, limits,
breaks, labels and so forth.}
+
+ \item{na.value}{Colour to use for missing values}
}
\description{
+ Create colour scales based on ColorBrewer colours.
+}
+\details{
+ ColorBrewer provides sequential, diverging and
+ qualitative colour schemes which are particularly suited
+ and tested to display discrete values (levels of a
+ factor) on a map. ggplot2 can use those colours in
+ discrete scales. It also allows to smoothly interpolate
+ the colours to a continuous scale, although the original
+ colour schemes (particularly the qualitative ones) were
+ not intended for this. The perceptual result is left to
+ the appreciation of the user.
+
See \url{http://colorbrewer2.org} for more information.
}
\examples{
@@ -46,6 +73,22 @@ d + scale_colour_brewer(palette="Set1")
ggplot(diamonds, aes(x=price, fill=cut)) +
geom_histogram(position="dodge", binwidth=1000) +
scale_fill_brewer()
+
+# Generate map data
+library(reshape2) # for melt
+volcano3d <- melt(volcano)
+names(volcano3d) <- c("x", "y", "z")
+
+# Basic plot
+v <- ggplot() + geom_tile(aes(x=x, y=y, fill=z), data=volcano3d)
+v
+v + scale_fill_distiller()
+v + scale_fill_distiller(palette=2)
+v + scale_fill_distiller(type="div")
+v + scale_fill_distiller(palette="Spectral")
+v + scale_fill_distiller(palette="Spectral", trans="reverse")
+v + scale_fill_distiller(type="qual")
+# Not appropriate for continuous data, issues a warning
}
\seealso{
Other colour scales:
View
3  man/scale_gradient.Rd
@@ -95,18 +95,21 @@ qplot(mpg, wt, data = mtcars, colour = miss) +
Other colour scales: \code{\link{scale_color_brewer}},
\code{\link{scale_color_discrete}},
+ \code{\link{scale_color_distiller}},
\code{\link{scale_color_gradient2}},
\code{\link{scale_color_gradientn}},
\code{\link{scale_color_grey}},
\code{\link{scale_color_hue}},
\code{\link{scale_colour_brewer}},
\code{\link{scale_colour_discrete}},
+ \code{\link{scale_colour_distiller}},
\code{\link{scale_colour_gradient2}},
\code{\link{scale_colour_gradientn}},
\code{\link{scale_colour_grey}},
\code{\link{scale_colour_hue}},
\code{\link{scale_fill_brewer}},
\code{\link{scale_fill_discrete}},
+ \code{\link{scale_fill_distiller}},
\code{\link{scale_fill_gradient2}},
\code{\link{scale_fill_gradientn}},
\code{\link{scale_fill_grey}},
View
3  man/scale_gradient2.Rd
@@ -84,6 +84,7 @@ p + scale_fill_gradient2("fill")
Other colour scales: \code{\link{scale_color_brewer}},
\code{\link{scale_color_continuous}},
\code{\link{scale_color_discrete}},
+ \code{\link{scale_color_distiller}},
\code{\link{scale_color_gradient}},
\code{\link{scale_color_gradientn}},
\code{\link{scale_color_grey}},
@@ -91,6 +92,7 @@ p + scale_fill_gradient2("fill")
\code{\link{scale_colour_brewer}},
\code{\link{scale_colour_continuous}},
\code{\link{scale_colour_discrete}},
+ \code{\link{scale_colour_distiller}},
\code{\link{scale_colour_gradient}},
\code{\link{scale_colour_gradientn}},
\code{\link{scale_colour_grey}},
@@ -98,6 +100,7 @@ p + scale_fill_gradient2("fill")
\code{\link{scale_fill_brewer}},
\code{\link{scale_fill_continuous}},
\code{\link{scale_fill_discrete}},
+ \code{\link{scale_fill_distiller}},
\code{\link{scale_fill_gradient}},
\code{\link{scale_fill_gradientn}},
\code{\link{scale_fill_grey}},
View
3  man/scale_gradientn.Rd
@@ -62,6 +62,7 @@ d + scale_colour_gradientn(colours = terrain.colors(10),
Other colour scales: \code{\link{scale_color_brewer}},
\code{\link{scale_color_continuous}},
\code{\link{scale_color_discrete}},
+ \code{\link{scale_color_distiller}},
\code{\link{scale_color_gradient}},
\code{\link{scale_color_gradient2}},
\code{\link{scale_color_grey}},
@@ -69,6 +70,7 @@ d + scale_colour_gradientn(colours = terrain.colors(10),
\code{\link{scale_colour_brewer}},
\code{\link{scale_colour_continuous}},
\code{\link{scale_colour_discrete}},
+ \code{\link{scale_colour_distiller}},
\code{\link{scale_colour_gradient}},
\code{\link{scale_colour_gradient2}},
\code{\link{scale_colour_grey}},
@@ -76,6 +78,7 @@ d + scale_colour_gradientn(colours = terrain.colors(10),
\code{\link{scale_fill_brewer}},
\code{\link{scale_fill_continuous}},
\code{\link{scale_fill_discrete}},
+ \code{\link{scale_fill_distiller}},
\code{\link{scale_fill_gradient}},
\code{\link{scale_fill_gradient2}},
\code{\link{scale_fill_grey}},
View
3  man/scale_grey.Rd
@@ -45,6 +45,7 @@ qplot(mpg, wt, data = mtcars, colour = miss) +
Other colour scales: \code{\link{scale_color_brewer}},
\code{\link{scale_color_continuous}},
\code{\link{scale_color_discrete}},
+ \code{\link{scale_color_distiller}},
\code{\link{scale_color_gradient}},
\code{\link{scale_color_gradient2}},
\code{\link{scale_color_gradientn}},
@@ -52,6 +53,7 @@ qplot(mpg, wt, data = mtcars, colour = miss) +
\code{\link{scale_colour_brewer}},
\code{\link{scale_colour_continuous}},
\code{\link{scale_colour_discrete}},
+ \code{\link{scale_colour_distiller}},
\code{\link{scale_colour_gradient}},
\code{\link{scale_colour_gradient2}},
\code{\link{scale_colour_gradientn}},
@@ -59,6 +61,7 @@ qplot(mpg, wt, data = mtcars, colour = miss) +
\code{\link{scale_fill_brewer}},
\code{\link{scale_fill_continuous}},
\code{\link{scale_fill_discrete}},
+ \code{\link{scale_fill_distiller}},
\code{\link{scale_fill_gradient}},
\code{\link{scale_fill_gradient2}},
\code{\link{scale_fill_gradientn}},
View
3  man/scale_hue.Rd
@@ -90,18 +90,21 @@ qplot(mpg, wt, data = mtcars, colour = miss) +
\seealso{
Other colour scales: \code{\link{scale_color_brewer}},
\code{\link{scale_color_continuous}},
+ \code{\link{scale_color_distiller}},
\code{\link{scale_color_gradient}},
\code{\link{scale_color_gradient2}},
\code{\link{scale_color_gradientn}},
\code{\link{scale_color_grey}},
\code{\link{scale_colour_brewer}},
\code{\link{scale_colour_continuous}},
+ \code{\link{scale_colour_distiller}},
\code{\link{scale_colour_gradient}},
\code{\link{scale_colour_gradient2}},
\code{\link{scale_colour_gradientn}},
\code{\link{scale_colour_grey}},
\code{\link{scale_fill_brewer}},
\code{\link{scale_fill_continuous}},
+ \code{\link{scale_fill_distiller}},
\code{\link{scale_fill_gradient}},
\code{\link{scale_fill_gradient2}},
\code{\link{scale_fill_gradientn}},
Something went wrong with that request. Please try again.