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

Prevent palette interpolation for some cases #149

Open
EthanJantz opened this issue Feb 16, 2023 · 2 comments · May be fixed by #150
Open

Prevent palette interpolation for some cases #149

EthanJantz opened this issue Feb 16, 2023 · 2 comments · May be fixed by #150
Assignees

Comments

@EthanJantz
Copy link
Contributor

Generating a discrete color palette using cmap_*_discrete will interpolate colors from outside of a defined palette in cases where the number of colors used is less than the number of colors in the full palette. I think this is due to the use of grDevices::colorRampPalette as the palette function in colors_discrete.R. This interpolation is useful in cases where the number of colors needed is larger than the size of the palette or for continuous scales, but for cases where the number of colors needed is less we should expect that the palette function will simply pull from the palette in order, and not interpolate using grDevices::colorRampPalette. Below are the results of calling viz_palette on the "friday" palette for different values of num.

image

I'm unsure if this is intended behavior or not. @nmpeterson do you have any insight?

@EthanJantz EthanJantz self-assigned this Feb 16, 2023
@nmpeterson
Copy link
Contributor

Hmm, curious. I didn't write the code for that, but I think it's safe to say this is not the intended behavior. I don't recall running into this issue when making example plots, so I wonder if something changed in the underlying grDevices::colorRampPalette implementation at some point -- totally possible I just never noticed, though!

@EthanJantz
Copy link
Contributor Author

I've been doing some more digging this morning, and I'm noticing that this behavior doesn't occur in every case where the number of colors is smaller than the palette length. At first I noticed that it's a more common occurrence when the number of colors called is even/odd and the palette length is odd/even; but calling 4 colors on a palette of length 7 works as intended. I'm posting the example below for reference.

image

grDevices has one palette function, colorRampPalette. I'm not aware of or finding any other palette functions in the base R libraries. cmapplot uses this function to generate a palette regardless of whether the palette being called is continuous or discrete, which is based off the ochRe package's implementation. I'm looking at the urbnthemes package, which is a similar project to cmapplot, and noticing that they have a different approach. See palette_urbn.R, colors.R, and scales.R at the urbnthemes package repository. It looks like their approach defines a palette as a list object with each item in the list corresponding to the number of colors to pull from the palette:

palette_urbn <- {

  palette <- list(
    categorical = list(
      c("#1696d2"),
      c("#1696d2", "#fdbf11"),
      c("#1696d2", "#fdbf11", "#000000"),
      c("#1696d2", "#fdbf11", "#000000", "#d2d2d2"),
      c("#1696d2", "#fdbf11", "#000000", "#d2d2d2", "#ec008b"),
      c("#1696d2", "#fdbf11", "#000000", "#d2d2d2", "#ec008b", "#55b748"),
      c("#1696d2", "#fdbf11", "#000000", "#d2d2d2", "#ec008b", "#55b748",
        "#5c5859"),
      c("#1696d2", "#fdbf11", "#000000", "#d2d2d2", "#ec008b", "#55b748",
        "#5c5859", "#db2b27")
    ),

    sequential = list(
      c("#1696d2"),
      c("#a2d4ec", "#1696d2"),
      c("#a2d4ec", "#1696d2", "#0a4c6a"),
      c("#cfe8f3", "#73bfe2", "#1696d2", "#0a4c6a"),
      c("#cfe8f3", "#73bfe2", "#1696d2", "#0a4c6a", "#000000"),
      c("#cfe8f3", "#a2d4ec", "#73bfe2", "#46abdb", "#1696d2", "#12719e"),
      c("#cge8f3", "#a2d4ec", "#73bfe2", "#46abdb", "#1696d2", "#12719e",
        "#0a4c6a"),
      c("#cge8f3", "#a2d4ec", "#73bfe2", "#46abdb", "#1696d2", "#12719e",
        "#0a4c6a", "#062635")
    )
  )

  palette
}

And from there, the palette function is simply calling palette[[n]], which passes to the appropriate scale function.

urbn_color_pal <- function(palette = "categorical") {
  palette_list <- palette_urbn

  types <- palette_list[[palette]]

  function(n) {

    if (n > 8) {

      stop(
        paste(
          "Error: urbnthemes allows for a max of 8 colors. Your code asked for",
          n,
          "colors.",
          "If you need more than 8 colors for exploratory purposes, use",
          "ggplot2::scale_fill_discrete() or ggplot2::scale_color_discrete()."
        )
      )

    }

    types[[n]]
  }
}

scale_color_discrete <- function(...) {
  ggplot2::discrete_scale(
    aesthetics = "colour",
    scale_name = "urbn",
    palette = urbn_color_pal("categorical"),
    ...
  )
}

This would address this issue, but would require a significant reworking of cmapplot based on my understanding of the code.

@dlcomeaux dlcomeaux linked a pull request Feb 20, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants