Come visualizzare solo i valori interi su un asse utilizzando ggplot2


88

Ho la seguente 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())

Voglio che l'asse y visualizzi solo numeri interi. Che ciò avvenga tramite arrotondamento o con un metodo più elegante non è molto importante per me.


2
Hai esaminato almeno una delle funzioni di scala? scale_y_continuouspuò essere?
joran

Ho letto alcune risposte a domande simili e ho avuto l'impressione che scale_y_continuous convertisse da altri formati numerici (ad esempio, notazione scientifica), ma non si adattava alla conversione da numero reale a intero che stavo cercando. Potrei sbagliarmi ...
Atticus29

Risposte:


42

Con l' scale_y_continuous()argomento breaks=e puoi impostare i punti di interruzione per l'asse y su numeri interi che desideri visualizzare.

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

45
Questa soluzione è utile solo per le situazioni in cui si sa quali valori sono sugli assi. Non è una buona soluzione generale.
Swolf

4
Nota per i posteri: geom_barnon funziona più con y estetica (sostituire con geom_col). E, sebbene non sia una soluzione generale, in questo esempio chiamare pretty con un n specifico può risolvere il problema originale (ed è più flessibile delle pause hard-coding): 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

73

Se hai il scalespacchetto, puoi usarlo pretty_breaks()senza dover specificare manualmente le interruzioni.

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

17
Questo sembrava fare quasi quello che fa il metodo predefinito e avevo ancora i punti decimali nelle interruzioni.
kory

Da dove pretty_breaks()viene?
Marian


16
pretty_breaks()sono carini, ma non sempre interi. Ovviamente c'è la bellezza in decimali ...
PatrickT

51

Questo è quello che 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)))))

Questa è la prima risposta che funziona, ma una spiegazione sarebbe più che gradita.
DomQ

18

Puoi utilizzare un'etichettatrice personalizzata. Ad esempio, questa funzione garantisce di produrre solo interruzioni intere:

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

Usare come

+ scale_y_continuous(breaks = int_breaks)

Funziona prendendo le interruzioni predefinite e mantenendo solo quelle che sono numeri interi. Se mostra troppo poche interruzioni per i tuoi dati, aumenta n, ad esempio:

+ scale_y_continuous(breaks = function(x) int_breaks(x, n = 10))

Questo ti fa perdere l'intero 1 se hai solo dati da 0 a 1,25 o quello che hai. Vedo solo 0 sull'asse x.
kory

1
Mi piace per semplicità. Nota che npotrebbe essere necessario apportare alcune modifiche a seconda dell'intervallo di valori. sembra determinare quante pause ci saranno (approssimativamente).
Marian

15

Queste soluzioni non hanno funzionato per me e non hanno spiegato le soluzioni.

L' breaksargomento delle scale_*_continuousfunzioni può essere utilizzato con una funzione personalizzata che accetta i limiti come input e restituisce le interruzioni come output. Per impostazione predefinita, i limiti degli assi verranno espansi del 5% su ciascun lato per i dati continui (relativi all'intervallo di dati). I limiti dell'asse probabilmente non saranno valori interi a causa di questa espansione.

La soluzione che stavo cercando era semplicemente arrotondare il limite inferiore al numero intero più vicino, arrotondare il limite superiore al numero intero più vicino e quindi avere interruzioni ai valori interi tra questi punti finali. Pertanto, ho usato la funzione break:

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

Lo snippet di codice richiesto è:

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

L'esempio riproducibile dalla domanda originale è:

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

2
La migliore risposta qui
Martin

Concordo con Martin - Grazie per aver fatto lo sforzo di fornire un esempio pienamente funzionante. Noto che la risposta di Daniel Gardiner utilizza una migliore funzione di interruzione, che non causerà disordine quando l'intervallo dell'asse è di centinaia o più. Inoltre, per una questione di gusti, ritengo che definire e utilizzare una breaks_integersfunzione separata potrebbe essere più utile per i principianti. Migliore,
DomQ

5

Tutte le risposte esistenti sembrano richiedere funzioni personalizzate o in alcuni casi falliscono.

Questa riga crea interruzioni di numeri interi:

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

Per ulteriori informazioni, vedere la documentazione ?labeling::extended(che è una funzione chiamata da scales::breaks_extended).

Fondamentalmente, l'argomento Qè un insieme di bei numeri che l'algoritmo cerca di utilizzare per le interruzioni di scala. Il grafico originale produce interruzioni non intere (0, 2,5, 5 e 7,5) perché il valore predefinito per Qinclude 2,5:Q = c(1,5,2,2.5,4,3) .

EDIT: come sottolineato in un commento, possono verificarsi interruzioni non intere quando l'asse y ha un intervallo ridotto. Per impostazione predefinita, breaks_extended()cerca di effettuare delle n = 5interruzioni, il che è impossibile quando l'intervallo è troppo piccolo. I test rapidi mostrano che gli intervalli più ampi di 0 <y <2,5 danno interruzioni di numeri interi ( npossono anche essere ridotti manualmente).


3

Google mi ha portato a questa domanda. Sto cercando di usare numeri reali su una scala ay. I numeri della scala y sono in milioni.

Il metodo del pacchetto scalecomma introduce una virgola ai miei grandi numeri. Questo post su R-Bloggers spiega un approccio semplice utilizzando il commametodo:

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)

Goditi R :)


1
Le altre soluzioni qui in realtà non funzionavano per me, o sembravano ridicolmente complicate. Questo ha funzionato ed è stato semplice da fare.
Brian Doherty

grazie @BrianDoherty, la semplicità è la chiave per la maggior parte delle cose ...
Tony Cronin

2

Ho trovato questa soluzione da Joshua Cook e ha funzionato abbastanza bene.

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


Questa funzione dovrebbe essere la risposta corretta. Funziona più facilmente di qualsiasi altro!
zdebruine

1

Questa risposta si basa sulla risposta di @ Axeman per rispondere al commento di kory secondo cui se i dati vanno solo da 0 a 1, nessuna interruzione viene mostrata in 1. Ciò sembra essere dovuto a inesattezze pretty con gli output che sembrano essere 1 non identici a 1 (vedi esempio alla fine).

Quindi se usi

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)

sia 0 che 1 vengono visualizzati come interruzioni.

Esempio per illustrare la differenza da 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)

Entrambi funzioneranno con i dati forniti nella domanda iniziale.

Illustrazione del motivo per cui è necessario l'arrotondamento

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.