Comment afficher uniquement des valeurs entières sur un axe à l'aide de ggplot2

87

J'ai l'intrigue suivante:

library(reshape)
library(ggplot2)
library(gridExtra)
require(ggplot2)



data2<-structure(list(IR = structure(c(4L, 3L, 2L, 1L, 4L, 3L, 2L, 1L
), .Label = c("0.13-0.16", "0.17-0.23", "0.24-0.27", "0.28-1"
), class = "factor"), variable = structure(c(1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L), .Label = c("Real queens", "Simulated individuals"
), class = "factor"), value = c(15L, 11L, 29L, 42L, 0L, 5L, 21L, 
22L), Legend = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L), .Label = c("Real queens", 
"Simulated individuals"), class = "factor")), .Names = c("IR", 
"variable", "value", "Legend"), row.names = c(NA, -8L), class = "data.frame")
p <- ggplot(data2, aes(x =factor(IR), y = value, fill = Legend, width=.15))


data3<-structure(list(IR = structure(c(4L, 3L, 2L, 1L, 4L, 3L, 2L, 1L
), .Label = c("0.13-0.16", "0.17-0.23", "0.24-0.27", "0.28-1"
), class = "factor"), variable = structure(c(1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L), .Label = c("Real queens", "Simulated individuals"
), class = "factor"), value = c(2L, 2L, 6L, 10L, 0L, 1L, 4L, 
4L), Legend = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L), .Label = c("Real queens", 
"Simulated individuals"), class = "factor")), .Names = c("IR", 
"variable", "value", "Legend"), row.names = c(NA, -8L), class = "data.frame")
q<- ggplot(data3, aes(x =factor(IR), y = value, fill = Legend, width=.15))


##the plot##
q + geom_bar(position='dodge', colour='black') + ylab('Frequency') + xlab('IR')+scale_fill_grey() +theme(axis.text.x=element_text(colour="black"), axis.text.y=element_text(colour="Black"))+ opts(title='', panel.grid.major = theme_blank(),panel.grid.minor = theme_blank(),panel.border = theme_blank(),panel.background = theme_blank(), axis.ticks.x = theme_blank())

Je veux que l'axe des y affiche uniquement des entiers. Que cela soit accompli par arrondi ou par une méthode plus élégante n'est pas vraiment important pour moi.

Atticus29
la source
2
Avez-vous examiné l'une des fonctions de l'échelle? scale_y_continuouspeut être?
joran
J'ai lu quelques réponses à des questions similaires et j'avais l'impression que scale_y_continuous était converti à partir d'autres formats numériques (par exemple, la notation scientifique), mais ne permettait pas la conversion de nombre réel en nombre entier que je recherchais. Je pourrais me tromper ...
Atticus29

Réponses:

41

Avec l' scale_y_continuous()argument et, breaks=vous pouvez définir les points de rupture de l'axe y sur les entiers que vous souhaitez afficher.

ggplot(data2, aes(x =factor(IR), y = value, fill = Legend, width=.15)) +
    geom_bar(position='dodge', colour='black')+
    scale_y_continuous(breaks=c(1,3,7,10))
Didzis Elferts
la source
41
Cette solution n'est bonne que pour les situations où vous savez quelles valeurs se trouvent sur les axes. Pas une bonne solution générale.
swolf
3
Note pour la postérité: geom_barne fonctionne plus avec y esthétique (remplacer par geom_col). Et, bien que ce ne soit pas une solution générale, dans cet exemple, appeler pretty avec un n spécifique peut résoudre le problème d'origine (et est plus flexible que les pauses de codage en dur): q + geom_col(position='dodge', colour='black') + xlab('IR')+scale_fill_grey() + theme_bw() + scale_y_continuous('Frequency', breaks=function(x) pretty(x, n=6))
helmingstay
72

Si vous disposez du scalespackage, vous pouvez l'utiliser pretty_breaks()sans avoir à spécifier manuellement les pauses.

q + geom_bar(position='dodge', colour='black') + 
scale_y_continuous(breaks= pretty_breaks())
Sealander
la source
17
Cela semblait faire presque ce que fait la méthode par défaut et j'avais toujours des points décimaux dans les pauses.
kory
D'où pretty_breaks()vient-il?
Marian
12
pretty_breaks()sont jolis, mais pas toujours des entiers. Évidemment, il y a de la beauté en décimales ...
PatrickT
50

Voici ce que j'utilise:

ggplot(data3, aes(x = factor(IR), y = value, fill = Legend, width = .15)) +
  geom_col(position = 'dodge', colour = 'black') + 
  scale_y_continuous(breaks = function(x) unique(floor(pretty(seq(0, (max(x) + 1) * 1.1)))))
Daniel Gardiner
la source
17

Vous pouvez utiliser une étiqueteuse personnalisée. Par exemple, cette fonction garantit de ne produire que des sauts d'entiers:

int_breaks <- function(x, n = 5) {
  l <- pretty(x, n)
  l[abs(l %% 1) < .Machine$double.eps ^ 0.5] 
}

Utilisé comme

+ scale_y_continuous(breaks = int_breaks)

Cela fonctionne en prenant les pauses par défaut et en ne conservant que celles qui sont des entiers. S'il affiche trop peu de ruptures pour vos données, augmentez n, par exemple:

+ scale_y_continuous(breaks = function(x) int_breaks(x, n = 10))
Axeman
la source
Celui-ci vous fait perdre l'entier 1 si vous n'avez que des données de 0 à 1,25 ou que vous avez. Je ne vois que 0 sur l'axe des x.
kory
1
J'aime ça par souci de simplicité. Notez que cela npourrait nécessiter quelques ajustements en fonction de votre plage de valeurs. il semble déterminer combien de pauses il y aura (approximativement).
Marian
13

Ces solutions n'ont pas fonctionné pour moi et n'ont pas expliqué les solutions.

L' breaksargument des scale_*_continuousfonctions peut être utilisé avec une fonction personnalisée qui prend les limites en entrée et retourne les ruptures en sortie. Par défaut, les limites de l'axe seront étendues de 5% de chaque côté pour les données continues (par rapport à la plage de données). Les limites de l'axe ne seront probablement pas des valeurs entières en raison de cette expansion.

La solution que je recherchais consistait simplement à arrondir la limite inférieure à l'entier le plus proche, à arrondir la limite supérieure à l'entier le plus proche, puis à avoir des ruptures aux valeurs entières entre ces points de terminaison. Par conséquent, j'ai utilisé la fonction breaks:

brk <- function(x) seq(ceiling(x[1]), floor(x[2]), by = 1)

L'extrait de code requis est:

scale_y_continuous(breaks = function(x) seq(ceiling(x[1]), floor(x[2]), by = 1))

L'exemple reproductible de la question originale est:

data3 <-
  structure(
    list(
      IR = structure(
        c(4L, 3L, 2L, 1L, 4L, 3L, 2L, 1L),
        .Label = c("0.13-0.16", "0.17-0.23", "0.24-0.27", "0.28-1"),
        class = "factor"
      ),
      variable = structure(
        c(1L, 1L, 1L, 1L,
          2L, 2L, 2L, 2L),
        .Label = c("Real queens", "Simulated individuals"),
        class = "factor"
      ),
      value = c(2L, 2L, 6L, 10L, 0L, 1L, 4L,
                4L),
      Legend = structure(
        c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L),
        .Label = c("Real queens",
                   "Simulated individuals"),
        class = "factor"
      )
    ),
    row.names = c(NA,-8L),
    class = "data.frame"
  )

ggplot(data3, aes(
  x = factor(IR),
  y = value,
  fill = Legend,
  width = .15
)) +
  geom_col(position = 'dodge', colour = 'black') + ylab('Frequency') + xlab('IR') +
  scale_fill_grey() +
  scale_y_continuous(
    breaks = function(x) seq(ceiling(x[1]), floor(x[2]), by = 1),
    expand = expand_scale(mult = c(0, 0.05))
    ) +
  theme(axis.text.x=element_text(colour="black", angle = 45, hjust = 1), 
        axis.text.y=element_text(colour="Black"),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        panel.background = element_blank(), 
        axis.ticks.x = element_blank())
Nat
la source
2
Meilleure réponse ici
Martin
3

Google m'a amené à cette question. J'essaie d'utiliser des nombres réels à l'échelle ay. Les nombres d'échelle y sont en millions.

La balance package commaméthode introduit une virgule à mes grand nombre. Cet article sur R-Bloggers explique une approche simple utilisant la commaméthode:

library(scales)

big_numbers <- data.frame(x = 1:5, y = c(1000000:1000004))

big_numbers_plot <- ggplot(big_numbers, aes(x = x, y = y))+
geom_point()

big_numbers_plot + scale_y_continuous(labels = comma)

Profitez de R :)

Tony Cronin
la source
1
Les autres solutions ici ne fonctionnaient pas vraiment pour moi, ou semblaient ridiculement compliquées. Celui-ci a fonctionné et était simple à faire.
Brian Doherty
merci @BrianDoherty, la simplicité est la clé de la plupart des choses ...
Tony Cronin
3

Toutes les réponses existantes semblent nécessiter des fonctions personnalisées ou échouer dans certains cas.

Cette ligne fait des sauts d'entiers:

bad_scale_plot +
  scale_y_continuous(breaks = scales::breaks_extended(Q = c(1, 5, 2, 4, 3)))

Pour plus d'informations, consultez la documentation ?labeling::extended(qui est une fonction appelée par scales::breaks_extended).

Fondamentalement, l'argument Qest un ensemble de bons nombres que l'algorithme essaie d'utiliser pour les sauts d'échelle. La parcelle d' origine produit pauses non entiers (0, 2,5, 5, 7,5) et parce que la valeur par défaut Qcomprend 2,5: Q = c(1,5,2,2.5,4,3).

EDIT: comme indiqué dans un commentaire, des sauts non entiers peuvent se produire lorsque l'axe des y a une petite plage. Par défaut, breaks_extended()essaie de faire des n = 5pauses, ce qui est impossible lorsque la plage est trop petite. Des tests rapides montrent que les plages plus larges que 0 <y <2,5 donnent des coupures entières ( npeuvent également être diminuées manuellement).

pseudo
la source
1

Cette réponse s'appuie sur la réponse de @ Axeman pour répondre au commentaire de kory selon lequel si les données ne vont que de 0 à 1, aucune interruption n'est affichée à 1. Cela semble être dû à une imprécision dans les prettysorties qui semblent être 1 n'étant pas identiques à 1 (voir l'exemple à la fin).

Par conséquent, si vous utilisez

int_breaks_rounded <- function(x, n = 5)  pretty(x, n)[round(pretty(x, n),1) %% 1 == 0]

avec

+ scale_y_continuous(breaks = int_breaks_rounded)

les deux 0 et 1 sont affichés comme des pauses.

Exemple pour illustrer la différence avec Axeman

testdata <- data.frame(x = 1:5, y = c(0,1,0,1,1))

p1 <- ggplot(testdata, aes(x = x, y = y))+
  geom_point()


p1 + scale_y_continuous(breaks = int_breaks)
p1 + scale_y_continuous(breaks =  int_breaks_rounded)

Les deux fonctionneront avec les données fournies dans la question initiale.

Illustration des raisons pour lesquelles l'arrondi est nécessaire

pretty(c(0,1.05),5)
#> [1] 0.0 0.2 0.4 0.6 0.8 1.0 1.2
identical(pretty(c(0,1.05),5)[6],1)
#> [1] FALSE
Sarah
la source
1

J'ai trouvé cette solution de Joshua Cook et j'ai plutôt bien fonctionné.

integer_breaks <- function(n = 5, ...) {
fxn <- function(x) {
breaks <- floor(pretty(x, n, ...))
names(breaks) <- attr(breaks, "labels")
breaks
}
return(fxn)
}

q + geom_bar(position='dodge', colour='black') + 
scale_y_continuous(breaks = integer_breaks())

La source est: https://joshuacook.netlify.app/post/integer-values-ggplot-axis/

Bruno Vidigal
la source