简体   繁体   中英

ggplot mirrored geom_bars customized colour

I am plotting max_temperature (mean_tmax) against rainfall (mean_rain) in a mirrored barplot: max temp displayed upwards, rain values downwards on the negative scale. These two are stored in the "name" variable. To highlight the highest values out of the 32 years plotted, I created two vectors colVecTmax, colVecRain. They return a color vector of length 32 each, with the index of max values marked differently.

But when adding these two vectors to fill within geom_bar(), it turns out that ggplot stops counting the top after 16 bars, and moves down to the negative scale to continue. So it does not count by the name (mean_tmax, or mean_rain) variable. This messes up the plot, and I am not sure how to get ggplot count through on the top bars for max_temperature first, coloring by colVecTmax, and then move down to do the same for rain on the negative scale with colVecRain在此处输入图像描述 .

Can anyone give a hint on how to solve this?

colVecTmax <- rep("orange",32)
colVecTmax[which.max(as.numeric(unlist(df.long[df.long$place=="sheffield" & df.long$name == "mean_tmax",4])))] <- "blue"

colVecRain <- rep("grey",32)
colVecRain[which.max(as.numeric(unlist(df.long[df.long$place=="sheffield" & df.long$name == "mean_rain",4])))] <- "blue"
  
ggplot(df.long[df.long$name %in% c('mean_rain', 'mean_tmax'), ] %>% filter(place== "sheffield")%>%
         group_by(name) %>% mutate(value = case_when(
           name == 'mean_rain' ~ value/10 * -1,
           TRUE ~ value)) %>% mutate(place==str_to_sentence(placenames)) %>%
         mutate(name = recode(name,'mean_rain' = "rainfall" ,  "mean_tmax" =  "max temp"))
         , aes(x = yyyy, y = value, fill=name))+
  geom_bar(stat="identity", position="identity", fill=c(colVecTmax,colVecRain))+
  labs(x="Year", y=expression("Rain in cm, temperature in ("*~degree *C*")"))+
  geom_smooth(colour="black", lwd=0.5,se=F)+
  scale_y_continuous(breaks = seq(-30, 30 , 5))+
  scale_x_continuous(breaks = seq(1990, 2025, 5))+
  guides(fill= guide_legend(title=NULL))+
  scale_fill_discrete(labels=c("Max temperature", "Rainfall"))+
  guides(fill=guide_legend(reverse=T), res=96)  

在此处输入图像描述

Using ggplot2 there are much easier and less error prone ways to assign colors. Instead of creating color vectors which you pass to the color or fill argument you could simply map on aesthetics (which you basically already have done) and assign your desired colors using a manual scale, eg scale_fill_manual . The same approach works fine when you want to highlight some values. To this end you could create additional categories, eg in the code below I add "_max" to the name for the observations with the max temperature or rainfall and assign your desired "blue" color to these categories. As doing so will add additional categories I use the breaks argument of scale_fill_manual so that these max categories will not show up in the legend.

Using some fake random example data:

# Create example data
set.seed(123)
df.long <- data.frame(
  name = rep(c("mean_rain", "mean_tmax"), each = 30),
  place = "sheffield",
  yyyy = rep(1991:2020, 2),
  value = c(runif(30, 40, 100), runif(30, 12, 16))
)

library(ggplot2)
library(dplyr)

df_plot <- df.long %>%
  filter(name %in% c("mean_rain", "mean_tmax")) |>
  filter(place == "sheffield") %>%
  mutate(value = case_when(
    name == "mean_rain" ~ -value / 10,
    TRUE ~ value
  )) |>
  # Maximum values
  group_by(name) |>
  mutate(name = ifelse(abs(value) >= max(abs(value)), paste(name, "max", sep = "_"), name))


ggplot(df_plot, aes(x = yyyy, y = value, fill = name)) +
  geom_col(position = "identity") +
  geom_smooth(colour = "black", lwd = 0.5, se = F) +
  scale_y_continuous(breaks = seq(-30, 30, 5), labels = abs) +
  scale_x_continuous(breaks = seq(1990, 2025, 5)) +
  scale_fill_manual(
    values = c(
      mean_rain = "orange", mean_tmax = "grey",
      mean_rain_max = "blue", mean_tmax_max = "blue"
    ),
    labels = c(mean_tmax = "Max temperature", mean_rain = "Rainfall"),
    breaks = c("mean_rain", "mean_tmax")
  ) +
  labs(x = "Year", y = expression("Rain in cm, temperature in (" * ~ degree * C * ")"), fill = NULL) +
  guides(fill = guide_legend(reverse = TRUE))

在此处输入图像描述

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