4
votes

Comment créer une barre de couleur dégradée discrète avec geom_contour_filled?

Je trace une carte basée sur un morceau de code comme celui-ci:

ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
geom_contour_filled(breaks = c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf))+
theme(plot.title = element_text(size = 10,hjust = 0.5))

Voici mon intrigue qui ressemble actuellement à: entrez la description de l'image ici Mais mon patron me demande de faire la légende comme ceci: entrez la description de l'image ici ou comme ça: entrez la description de l'image ici Les arguments de ce lien ( https://ggplot2.tidyverse.org/reference/theme.html ) ne fournissent que des modifications mineures pour la légende. Et je ne trouve aucun argument qui puisse y parvenir, est-ce faisable avec ggplot? ou je dois utiliser un autre package de traçage?

Créer une barre de couleur discrète avec des largeurs d'intervalle variables et aucun espacement entre les niveaux de légende Cette question (réponse n ° 4) fournit une méthode qui peut créer une barre de couleur comme mon patron l'exige, cependant, j'utilise geom_contour_filled(breaks = c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf)) cet argument donc la légende apparaît toujours avec beaucoup du texte: entrez la description de l'image ici Y a-t-il des solutions?


2 commentaires

Est-ce que cela répond à votre question? Créez une barre de couleur discrète avec des largeurs d'intervalle variables et sans espacement entre les niveaux de légende


Désolé d'avoir peu de temps. Je pense que ce lien pourrait aider: stackoverflow.com/questions/10032513/… ; Aussi, voici un tutoriel générique sur les étiquettes: sthda.com/english/wiki / ...


4 Réponses :


3
votes

Éditer

Je recommande de ne pas utiliser cette réponse - ma deuxième réponse dans ce fil est beaucoup plus appropriée, mais j'y ai répondu ici en ignorant les nouvelles fonctions. Je pense toujours que cela peut être utile dans des situations très spécifiques, je le laisse donc aux futurs lecteurs. Les fonctions sont prises et modifiées à partir du commentaire de Claus Wilke dans ce numéro de github .

Je voudrais également recommander à nouveau de considérer la fonction de l'utilisateur AF7 pour créer une fausse légende, car vous avez beaucoup plus de liberté pour styliser votre légende.

geom_contour_filled discrétise votre dimension d'intérêt, puis le scale_fill_discrete_gradient intrinsèquement continu échoue. Il semble que metR::geom_contour_fill ne produit pas de données discrètes, mais les garde continues ...

Pour que cette solution fonctionne, vous devez couper votre variable en casiers, puis utiliser les niveaux de facteur pour définir des pauses et des limites. C'est un peu hacky ...

## very mildly modified from Claus Wilke
discrete_gradient_pal <- function(colours, bins = 5) {
  ramp <- scales::colour_ramp(colours)
  
  function(x) {
    if (length(x) == 0) return(character())
    
    i <- floor(x * bins)
    i <- ifelse(i > bins-1, bins-1, i)
    ramp(i/(bins-1))
  }
}

scale_fill_discrete_gradient <- 
  function(..., colours, bins = 5, 
           na.value = "grey50", 
           guide = "colourbar", 
           aesthetics = "fill", colors)  {
    colours <- if (missing(colours)) 
      colors
    else colours
    continuous_scale(
      aesthetics,
      "discrete_gradient",
      discrete_gradient_pal(colours, bins),
      na.value = na.value,
      guide = guide,
      ...
    )
  } 

les fonctions

library(RColorBrewer)
library(metR)
library(ggplot2)

mybreaks <- c(seq(-2,2,0.5), 3:5, seq(7,11,2))
mycols <- rev(colorRampPalette(brewer.pal(11, "Spectral"))(length(mybreaks)-1))
faithfuld$cut_dens <- cut(100*faithfuld$density, mybreaks)

ggplot(faithfuld, aes(eruptions, waiting)) +
  geom_contour_fill(aes(z = as.integer(cut_dens))) +
  scale_fill_discrete_gradient(
    colours = mycols,
    breaks = seq(1, 15, 1), # breaks and limits based on factor levels! 
    limits = c(1,15),
    bins = length(mybreaks)-1,
    labels = mybreaks,
    guide = guide_colourbar(frame.colour = "black", 
                            ticks.colour = "black", # you can also remove the ticks with NA
                            barwidth=20)
  ) +
  theme(legend.position = "bottom")


3 commentaires

Salut Tjebo, merci beaucoup. Je ne sais pas si vous vous souvenez que vous m'avez aidé sur cette question Comment personnaliser une palette de couleurs dans r pour ggplot? . J'ai essayé plusieurs fois, mais je ne trouve toujours pas comment introduire votre argument dans mon code, il semble qu'il y ait un conflit avec "geom_contour_filled". En fait, j'ai aussi essayé d'autres codes qui peuvent modifier la légende, mais la plupart d'entre eux ne fonctionnent pas lorsque j'utilise "geom_contour_filled"


@LambertYe Bien sûr que je me souviens et c'était amusant de répondre. Cela m'aiderait énormément (et tout le monde ici!) Si vous pouviez essayer de créer un exemple reproductible. Cela inclut également le partage de certaines données avec lesquelles vous souhaitez créer les contours remplis. Habituellement, vous n'avez pas besoin de publier les données complètes, mais juste les colonnes minimales et certains points de données pour créer, dans ce cas, un contour.


@LambertYe Consultez également le paquet metR github.com/eliocamp/metR qui peut sembler fournir quelque chose de très proche de ce que vous voulez faire. et vérifiez le fil github auquel j'ai lié dans mon message ci-dessus, et aussi vraiment cette fonction d'Adriano!



2
votes

Une autre option consiste à utiliser guide_bins .

Pour obtenir de belles étiquettes, vous pouvez probablement utiliser l'argument des labels pour cut comme je le fais dans mon approche.

Malheureusement, je ne pouvais pas trouver un moyen de supprimer l'espacement entre les touches de légende ou d'avoir un cadre noir autour des touches.

De plus, sans un coup d'œil à vos données et à votre palette de couleurs, je ne suis pas sûr que cette approche puisse être facilement adaptée à votre cas.

set.seed(42)

d <- data.frame(
  x = runif(1000, -20, 20)
)

d$y <- cut(d$x, breaks = c(-Inf, seq(-2, 11, 1), Inf), labels = c(seq(-2, 11, 1), ""))

library(ggplot2)

ggplot(d, aes(y, fill = as.numeric(y))) +
  geom_bar() +
  scale_fill_viridis_b(name = "\u00B0C", limits = c(-2, 11), breaks = seq(-2, 11, 1),
                       guide = guide_bins(axis = FALSE, title.position = "right",
                                          axis.colour = "black",
                                          keywidth = unit(1, "cm"), 
                                          keyheight = unit(1, "cm"))) + 
  theme(legend.position = "bottom")


0 commentaires

1
votes

Je pense que c'est assez différent de ma réponse précédente pour en justifier une seconde. J'ai répondu à ce dernier en refusant complètement les nouvelles fonctions d'échelle fournies avec ggplot2 3.3.0, et maintenant, c'est parti, elles facilitent beaucoup la tâche. Je garderais toujours l'autre solution car elle pourrait aider pour ... enfin des exigences très spécifiques.

Nous devons toujours utiliser metR car le problème avec le contour continu / discret persiste, et metR :: geom_contour_fill gère bien cela.

Je modifie la fonction scale_fill_fermenter qui est la bonne fonction à utiliser ici car elle fonctionne avec une échelle groupée. J'ai légèrement amélioré la fonction brewer_pal sous-jacente, de sorte qu'elle donne plus que les couleurs originales du brasseur, si n > max(palette_colors) .

update Vous devez utiliser guide_colorsteps pour changer la barre de couleurs.

craftbrewer_pal <- function (type = "seq", palette = 1, direction = 1) 
{
  pal <- scales:::pal_name(palette, type)
  force(direction)
  function(n) {
    n_max_palette <- RColorBrewer:::maxcolors[names(RColorBrewer:::maxcolors) == palette]
    
    if (n < 3) {
      pal <- suppressWarnings(RColorBrewer::brewer.pal(n, pal))
    } else if (n > n_max_palette){
      rlang::warn(paste(n, "colours used, but", palette, "has only",
                    n_max_palette, "- New palette created based on all colors of", 
                    palette))
      n_palette <- RColorBrewer::brewer.pal(n_max_palette, palette)
      colfunc <- grDevices::colorRampPalette(n_palette)
      pal <- colfunc(n)
    }
    else {
      pal <- RColorBrewer::brewer.pal(n, pal)
    }
    pal <- pal[seq_len(n)]
    if (direction == -1) {
      pal <- rev(pal)
    }
    pal
  }
}

scale_fill_craftfermenter <- function(..., type = "seq", palette = 1, direction = -1, na.value = "grey50", guide = "coloursteps", aesthetics = "fill") {
  type <- match.arg(type, c("seq", "div", "qual"))
  if (type == "qual") {
    warn("Using a discrete colour palette in a binned scale.\n  Consider using type = \"seq\" or type = \"div\" instead")
  }
  binned_scale(aesthetics, "fermenter", ggplot2:::binned_pal(craftbrewer_pal(type, palette, direction)), na.value = na.value, guide = guide, ...)
}

## with uneven steps, better representing the scale 
ggplot(faithfuld, aes(eruptions, waiting)) +
  metR::geom_contour_fill(aes(z = 100*density)) +
  scale_fill_craftfermenter(
    breaks = mybreaks, 
    palette = "Spectral", 
    limits = c(-2,11),
    guide = guide_colorsteps(
      even.steps = FALSE,
      frame.colour = "black", 
      ticks.colour = "black", # you can also remove the ticks with NA
      barwidth=20, )
  ) +
  theme(legend.position = "bottom")
#> Warning: 14 colours used, but Spectral has only 11 - New palette created based
#> on all colors of Spectral

Modifications de fonction

library(ggplot2)
library(metR)

mybreaks <- c(seq(-2,2,0.5), 3:5, seq(7,11,2))

ggplot(faithfuld, aes(eruptions, waiting)) +
  metR::geom_contour_fill(aes(z = 100*density)) +
  scale_fill_craftfermenter(
    breaks = mybreaks, 
    palette = "Spectral", 
    limits = c(-2,11),
    guide = guide_colorsteps(
      frame.colour = "black", 
      ticks.colour = "black", # you can also remove the ticks with NA
      barwidth=20)
  ) +
  theme(legend.position = "bottom")
#> Warning: 14 colours used, but Spectral has only 11 - New palette created based
#> on all colors of Spectral


3 commentaires

Merci beaucoup @Tjebo. Je ne suis qu'un débutant dans le codage R et je crois que je reviendrai sur votre message car c'est super utile. Je voudrais envoyer les deux versions à mon patron (la méthode du pas pair est son exigence initiale). Mais pour les deux réponses que vous avez données sur les solutions à étapes égales, je pense que la légende ne correspond pas à l'intrigue. Pour Fidèle, il n'y a pas de données inférieures à 0 dans l'ensemble de données, mais votre graphique montre que le minimum est compris entre -1 et 0,5. C'est aussi la même chose pour mon intrigue. Je suis confus à ce sujet.


En outre, vous avez mentionné la création d'un exemple reproductible dans vos commentaires précédents. Je suis tout nouveau sur ce site Web, et en tant que débutant en codage, je sais aussi l'importance d'avoir un exemple reproductible. alors merci de me dire ça!


@LambertYe voyez la mise à jour, le problème était qu'il fallait utiliser guide_colorsteps . (Je n'ai pas pensé à redimensionner la variable si je voulais utiliser des sauts personnalisés ... Mais cette solution de contournement n'est plus nécessaire)



0
votes

C'est une vieille réponse, mais le package metR pourrait résoudre ce problème avec la nouvelle échelle discrétisée (avertissement, je suis l'auteur :)). Utilisez ggplot2::geom_contour_filled() (ou metR::geom_contour_fill(aes(fill = stat(level))) ) puis utilisez metR::scale_fill_discretised()

ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = breaks) +
  scale_fill_distiller(super = metR::ScaleDiscretised, palette = "Spectral")

Cela traitera les valeurs discrétisées (telles que la variable de level calculée de geom_contour_filled() ) comme si elles étaient continues. Notez que maintenant, l'échelle de couleurs reflète correctement l'espacement inégal des sauts. Autrement dit, non seulement les pauses sont espacées de manière inégale dans le guide, mais également les couleurs sont espacées de manière inégale dans l'échelle de couleurs.

Si vous souhaitez utiliser une palette de couleurs similaire à celles de votre capture d'écran, vous pouvez utiliser ggplot2::scale_fill_gradientn() mais la convertir en une échelle discrétisée avec le super argument.

ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = breaks) +
  scale_fill_gradientn(colours = c("#0A2864", "#CCD9FF", "#FFF9CF", "#FEBF00", "#E6281E", "#6C0000"),
    super = metR::ScaleDiscretised)

Ou toute autre échelle continue.

library(ggplot2)

breaks <-  c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf)
ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = breaks) +
  metR::scale_fill_discretised()

Et à partir de là, continuez simplement avec les ajustements que vous voulez.

(Cette fonctionnalité est un peu nouvelle et peut contenir des erreurs sur des cas que je n'ai pas pris en compte. Si vous l'utilisez et trouvez un problème, veuillez ouvrir un problème dans le référentiel github . Je serais heureux de le résoudre.)

Créé le 2020-11-26 par le package reprex (v0.3.0)


0 commentaires