Como exibir apenas valores inteiros em um eixo usando ggplot2

87

Eu tenho o seguinte enredo:

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

Eu quero que o eixo y exiba apenas números inteiros. Se isso é feito por arredondamento ou por um método mais elegante, não é muito importante para mim.

Atticus29
fonte
2
Você já olhou para alguma das funções da escala? scale_y_continuoustalvez?
joran,
Eu li algumas respostas para perguntas semelhantes e tive a impressão de que scale_y_continuous converteu de outros formatos numéricos (por exemplo, notação científica), mas não acomodou o número real para a conversão de inteiro que eu estava procurando. Posso estar enganado ...
Atticus

Respostas:

41

Com o scale_y_continuous()argumento e, breaks=você pode definir os pontos de quebra do eixo y para inteiros que deseja exibir.

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
fonte
41
Esta solução só é boa para situações em que você sabe quais valores estão nos eixos. Não é uma boa solução geral.
swolf de
3
Nota para a posteridade: geom_barnão funciona mais com estética y (substitua por geom_col). E, embora não seja uma solução geral, neste exemplo, chamar bonito com um n específico pode corrigir o problema original (e é mais flexível do que as quebras de codificação): 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

Se você tiver o scalespacote, poderá usá-lo pretty_breaks()sem precisar especificar manualmente as quebras.

q + geom_bar(position='dodge', colour='black') + 
scale_y_continuous(breaks= pretty_breaks())
Sealander
fonte
17
Isso parecia fazer quase o que o método padrão faz e eu ainda tinha casas decimais nas quebras.
kory
De onde pretty_breaks()vem?
Marian
12
pretty_breaks()são bonitos, mas nem sempre inteiros. Obviamente, há beleza em decimais ...
PatrickT
50

Isso é o que eu 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
fonte
17

Você pode usar uma etiquetadora personalizada. Por exemplo, esta função garante produzir apenas quebras de inteiros:

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

Use como

+ scale_y_continuous(breaks = int_breaks)

Ele funciona pegando as pausas padrão e mantendo apenas aquelas que são inteiras. Se estiver mostrando poucas quebras para seus dados, aumente n, por exemplo:

+ scale_y_continuous(breaks = function(x) int_breaks(x, n = 10))
Axeman
fonte
Este faz com que você perca o inteiro 1 se você tiver dados apenas de 0 a 1,25 ou o que quer que seja. Vejo apenas 0 no eixo x.
kory
1
Eu gosto disso por causa da simplicidade. Observe que npode ser necessário alguns ajustes, dependendo da sua faixa de valores. parece determinar quantas quebras haverá (aproximadamente).
Marian
13

Essas soluções não funcionaram para mim e não explicaram as soluções.

O breaksargumento para as scale_*_continuousfunções pode ser usado com uma função personalizada que leva os limites como entrada e retorna quebras como saída. Por padrão, os limites do eixo serão expandidos em 5% em cada lado para dados contínuos (em relação ao intervalo de dados). Os limites do eixo provavelmente não serão valores inteiros devido a essa expansão.

A solução que eu estava procurando era simplesmente arredondar o limite inferior para o inteiro mais próximo, arredondar o limite superior para o inteiro mais próximo e, em seguida, ter quebras nos valores inteiros entre esses pontos finais. Portanto, usei a função de interrupções:

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

O snippet de código necessário é:

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

O exemplo reproduzível da pergunta original é:

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
fonte
2
Melhor resposta aqui
Martin
3

O Google me trouxe a esta questão. Estou tentando usar números reais em escala y. Os números da escala y estão em milhões.

O método do pacote de escalascomma introduz uma vírgula para meus números grandes. Esta postagem no R-Bloggers explica uma abordagem simples usando o 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)

Aproveite R :)

Tony Cronin
fonte
1
As outras soluções aqui não funcionaram para mim ou pareciam ridiculamente complicadas. Este funcionou e foi simples de fazer.
Brian Doherty
obrigado @BrianDoherty, simplicidade é a chave para a maioria das coisas ...
Tony Cronin
3

Todas as respostas existentes parecem exigir funções personalizadas ou falham em alguns casos.

Esta linha faz quebras inteiras:

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

Para obter mais informações, consulte a documentação ?labeling::extended(que é uma função chamada por scales::breaks_extended).

Basicamente, o argumento Qé um conjunto de números legais que o algoritmo tenta usar para quebras de escala. A parcela inicial produz intervalos não inteiros (0, 2,5, 5 e 7,5), porque o valor predefinido para Qinclui 2,5: Q = c(1,5,2,2.5,4,3).

EDITAR: como apontado em um comentário, quebras não inteiras podem ocorrer quando o eixo y tem um pequeno intervalo. Por padrão, breaks_extended()tenta fazer n = 5pausas, o que é impossível quando o alcance é muito pequeno. O teste rápido mostra que intervalos maiores que 0 <y <2,5 dão quebras de inteiros ( ntambém podem ser diminuídos manualmente).

usuario
fonte
1

Esta resposta baseia-se na resposta de @Axeman para abordar o comentário de kory de que se os dados vão apenas de 0 a 1, nenhuma quebra é mostrada em 1. Isso parece ser devido à imprecisão nas prettysaídas que parecem ser 1 não sendo idênticas a 1 (veja o exemplo no final).

Portanto, se você usar

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

com

+ scale_y_continuous(breaks = int_breaks_rounded)

ambos 0 e 1 são mostrados como quebras.

Exemplo para ilustrar a diferença do 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 trabalharão com os dados fornecidos na pergunta inicial.

Ilustração de por que o arredondamento é necessário

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

Encontrei essa solução com Joshua Cook e funcionou muito bem.

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

A fonte é: https://joshuacook.netlify.app/post/integer-values-ggplot-axis/

Bruno Vidigal
fonte