简体   繁体   中英

Specify different alpha for fill and color in geom_rect inside aes( )?

I have a graph in which I would like to set individual alpha levels for each component of an element. I have a geom_rect element that is meant to change color and fill based on the variable "violation". I want specify the alpha for color and fill separately. However, I have not been able to accomplish this while maintaining the grouping color based on "violation".

I have a named vector of colors such as this, where the names match the value for the "violation" variable:

viol.colors <- c("darkorange", "darkblue")
names(viol.colors) = c("violation.mean", "violation.sd")

Example data (real data has more columns, which is why "select" is included in the plot code):

    groups <- data.frame(
      violation = rep(c("violation.mean", "violation.sd"), each = 5),
      xmin = rep(c(1,1.5), each = 5),
      xmax = rep(c(2,3), each = 5),
      ymin = rep(c(1,2), each = 5),
      ymax = rep(c(1.5, 3), each = 5),
      rect.color = rep(c("darkorange", "darkblue"), each = 5)
    )

If I set color and fill to be grouped by "violation", and then use scale_fill_manual to set the colors, the colors are correctly applied to both of those components of geom_rect. However, I cannot specify the alpha level if I set color and fill inside aes().

Example 1 - This applies the correct colors based on the "violation" variable, but I cannot specify alpha from within aes().

geom_rect(data = groups %>%
                        group_by(violation) %>%
                select(violation, xmin, xmax, ymin, ymax, rect.color) %>%
                unique(),
              aes(xmin = xmin - 0.75,
                  xmax = xmax + 0.75,
                  ymin = ymin - (sd *0.15),
                  ymax = ymax + (sd *0.15),
                  colour = violation,
                  fill = violation
                  ),
              size= 0.25
    scale_fill_manual(values = viol.colors, aesthetics = c("color", "fill"))

Example 2 - If I set a color and fill for geom_rect outside of aes(), I can specify the alpha, but the correct colors are not applied based on "violation".

    geom_rect(data = groups %>%
                    group_by(violation) %>%
            select(violation, xmin, xmax, ymin, ymax, rect.color) %>%
            unique(),
          aes(xmin = xmin - 0.75,
              xmax = xmax + 0.75,
              ymin = ymin - (sd *0.15),
              ymax = ymax + (sd *0.15),
              group = violation
              ),
          size= 0.25,
          fill = alpha("darkorange", .05),
          colour = alpha("darkorange", .5) +
scale_fill_manual(values = viol.colors, aesthetics = c("color", "fill"))

It seems to me like the most simple way to do this should be to combine those two approaches and place the following code inside aes(). However, this throw an error.

fill = alpha(violation, .05),
colour = alpha(violation, .5)

Any insight to how this could be accomplished would be much appreciated, I've tried many different versions of this without success.

One way around this would be to encode the alpha in the color you want, by specifying the color in hexadecimal with the last two digits representing alpha values. You can look these values up in many online calculators.

For instance, if you want dark blue ("#00008b" where I looked it up) at 5% opacity, you'd append "0D", representing 13 (~5% of 255), to the end. scale_color_identity then uses the color name you'd added into your data to output that specific color. If you specify the color in hex, you get the additional option of specifying an alpha for it too.

https://ggplot2.tidyverse.org/reference/aes_colour_fill_alpha.html#alpha

ggplot(data = data.frame(violation = 1:2,
                         colors = c("#00008b0D",   #0D = 13 in hex = 5% of 255
                                    "#ff8c0080")),  #80 = 128 in hex = 50% of 255  
       aes(violation, 1, fill = colors)) +
  geom_tile() +
  scale_fill_identity() +
  theme_minimal()

在此处输入图像描述

You can use those functions to control aesthetic evaluation .

library(tidyverse)
viol.colors <- c("darkorange", "darkblue")
names(viol.colors) = c("violation.mean", "violation.sd")

groups <- data.frame(
  violation = rep(c("violation.mean", "violation.sd"), each = 5),
  xmin = rep(c(1,1.5), each = 5),
  xmax = rep(c(2,3), each = 5),
  ymin = rep(c(1,2), each = 5),
  ymax = rep(c(1.5, 3), each = 5)
) 

ggplot(groups) +
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax ,
                  colour = stage(violation, after_scale = alpha(color, .5)),
                  fill = stage(violation, after_scale = alpha(fill, .05))
                  ), size= 0.25) +
  scale_fill_manual(values = viol.colors, aesthetics = c("color", "fill"))

在此处输入图像描述

I did come up with a solution to this. It seems a bit hacky and I won't accept this as the answer for the time being, but I wanted to share it. In my previous code, I filtered the "groups" data within the ggplot code. I changed that to happen when the data is initially produced elsewhere in the code. This allowed me to set the values for "fill" and "color" based on a column value for the "group" dataset.

Data:

groups <- data.frame(
  violation = rep(c("violation.mean", "violation.sd"), each = 5),
  xmin = rep(c(1,1.5), each = 5),
  xmax = rep(c(2,3), each = 5),
  ymin = rep(c(1,2), each = 5),
  ymax = rep(c(1.5, 3), each = 5),
  rect.color = rep(c("darkorange", "darkblue"), each = 5)
)

Then, filter only to unique values here instead of in the ggplot code

groups <- groups %>%
            group_by(violation) %>%
            unique()

Now, I can use the column value for "rect.color" in "color" and "fill" outside of aes() since groups$rect.color now has the same length as the number of geom_rect elements produced.

  geom_rect_pattern(data = groups,
              aes(xmin = xmin - 0.75,
                  xmax = xmax + 0.75,
                  ymin = ymin - (sd *0.15),
                  ymax = ymax + (sd *0.15),
                  group = violation,
                  ),
              size= 0.25,
              color = alpha(groups$rect.color, .5),
              fill = alpha(groups$rect.color, .05)

I know this may not be the best way to accomplish this but it does work. If someone has a better approach or can improve on this I'll accept that as the answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM