Cómo mostrar solo valores enteros en un eje usando ggplot2

87

Tengo la siguiente trama:

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())

Quiero que el eje y muestre solo números enteros. Si esto se logra mediante redondeo o mediante un método más elegante, no es realmente importante para mí.

Atticus29
fuente
2
¿Ha mirado alguna de las funciones de escala? scale_y_continuous¿tal vez?
joran
Leí algunas respuestas a preguntas similares y tenía la impresión de que scale_y_continuous se convertía de otros formatos numéricos (por ejemplo, notación científica), pero no acomodaba la conversión de número real a entero que estaba buscando. Podría estar equivocado ...
Atticus29

Respuestas:

41

Con un scale_y_continuous()argumento y breaks=puede establecer los puntos de ruptura para el eje y en los números enteros que desea mostrar.

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
fuente
41
Esta solución solo es buena para situaciones en las que sabe qué valores están en los ejes. No es una buena solución general.
swolf
3
Nota para la posteridad: geom_barya no funciona con y estética (reemplazar con geom_col). Y, aunque no es una solución general, en este ejemplo, llamar a pretty con una n específica puede solucionar el problema original (y es más flexible que las interrupciones de codificación): 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 tiene el scalespaquete, puede usarlo pretty_breaks()sin tener que especificar manualmente los descansos.

q + geom_bar(position='dodge', colour='black') + 
scale_y_continuous(breaks= pretty_breaks())
Sealander
fuente
17
Esto parecía hacer casi lo que hace el método predeterminado y todavía tenía puntos decimales en los descansos.
kory
De donde pretty_breaks()viene
Marian
12
pretty_breaks()son bonitos, pero no siempre enteros. Obviamente, hay belleza en los decimales ...
PatrickT
50

Esto es lo que uso:

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
fuente
17

Puede utilizar una etiquetadora personalizada. Por ejemplo, esta función garantiza que solo se produzcan rupturas de enteros:

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

Usar como

+ scale_y_continuous(breaks = int_breaks)

Funciona tomando los descansos predeterminados y solo conservando aquellos que son números enteros. Si muestra muy pocas interrupciones para sus datos, aumente n, por ejemplo:

+ scale_y_continuous(breaks = function(x) int_breaks(x, n = 10))
Hacha
fuente
Este hace que pierda el entero 1 si solo tiene datos de 0 a 1,25 o lo que sea. Solo veo 0 en el eje x.
kory
1
Me gusta esto por simplicidad. Tenga en cuenta que npodría necesitar algunos ajustes dependiendo de su rango de valores. parece determinar cuántos descansos habrá (aproximadamente).
Marian
13

Estas soluciones no funcionaron para mí y no explicaron las soluciones.

El breaksargumento de las scale_*_continuousfunciones se puede usar con una función personalizada que toma los límites como entrada y devuelve cortes como salida. De forma predeterminada, los límites del eje se ampliarán un 5% en cada lado para datos continuos (en relación con el rango de datos). Es probable que los límites del eje no sean valores enteros debido a esta expansión.

La solución que estaba buscando era simplemente redondear el límite inferior al número entero más cercano, redondear el límite superior al número entero más cercano y luego tener rupturas en los valores enteros entre estos puntos finales. Por lo tanto, utilicé la función de pausas:

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

El fragmento de código requerido es:

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

El ejemplo reproducible de la pregunta original es:

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
fuente
2
La mejor respuesta aquí
Martin
3

Google me trajo a esta pregunta. Estoy tratando de usar números reales en escala ay. Los números de la escala y están en millones.

El método del paquete de escalascomma introduce una coma en mis números grandes. Esta publicación sobre R-Bloggers explica un enfoque simple usando el commamétodo:

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)

Disfruta R :)

Tony Cronin
fuente
1
Las otras soluciones aquí en realidad no funcionaron para mí, o parecían ridículamente complicadas. Este funcionó y fue fácil de hacer.
Brian Doherty
gracias @BrianDoherty, la simplicidad es la clave para la mayoría de las cosas ...
Tony Cronin
3

Todas las respuestas existentes parecen requerir funciones personalizadas o fallan en algunos casos.

Esta línea hace rupturas enteras:

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

Para obtener más información, consulte la documentación ?labeling::extended(que es una función llamada por scales::breaks_extended).

Básicamente, el argumento Qes un conjunto de números agradables que el algoritmo intenta utilizar para los saltos de escala. La trama original produce roturas no enteros (0, 2,5, 5, y 7,5) debido a que el valor predeterminado para Qincluye 2,5: Q = c(1,5,2,2.5,4,3).

EDITAR: como se señaló en un comentario, las rupturas no enteras pueden ocurrir cuando el eje y tiene un rango pequeño. De forma predeterminada, breaks_extended()intenta realizar n = 5rupturas, lo que es imposible cuando el rango es demasiado pequeño. Las pruebas rápidas muestran que los rangos más anchos que 0 <y <2.5 dan saltos enteros ( ntambién se pueden reducir manualmente).

Mella
fuente
1

Esta respuesta se basa en la respuesta de @ Axeman para abordar el comentario de kory de que si los datos solo van de 0 a 1, no se muestra ninguna ruptura en 1. Esto parece deberse a una inexactitud en las prettysalidas que parecen ser 1 y no son idénticas a 1 (ver ejemplo al final).

Por lo tanto, si usa

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

con

+ scale_y_continuous(breaks = int_breaks_rounded)

tanto 0 como 1 se muestran como pausas.

Ejemplo para ilustrar la diferencia con 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)

Ambos trabajarán con los datos proporcionados en la pregunta inicial.

Ilustración de por qué se requiere redondeo

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
fuente
1

Encontré esta solución de Joshua Cook y funcionó bastante bien.

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 fuente es: https://joshuacook.netlify.app/post/integer-values-ggplot-axis/

Bruno Vidigal
fuente