วิธีแสดงเฉพาะค่าจำนวนเต็มบนแกนโดยใช้ ggplot2


88

ฉันมีพล็อตต่อไปนี้:

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

ฉันต้องการให้แกน y แสดงเฉพาะจำนวนเต็ม ไม่ว่าสิ่งนี้จะทำได้โดยการปัดเศษหรือวิธีการที่หรูหรากว่านั้นก็ไม่สำคัญสำหรับฉัน


2
คุณได้ดูฟังก์ชั่นสเกลใด ๆ หรือไม่? scale_y_continuousอาจจะ?
joran

ฉันอ่านคำตอบของคำถามที่คล้ายกันและพบว่า scale_y_continuous แปลงจากรูปแบบตัวเลขอื่น ๆ (เช่นสัญกรณ์วิทยาศาสตร์) แต่ไม่รองรับการแปลงจำนวนจริงเป็นจำนวนเต็มที่ฉันกำลังมองหา ฉันอาจจะเข้าใจผิด ...
Atticus29

คำตอบ:


42

ด้วยscale_y_continuous()และอาร์กิวเมนต์breaks=คุณสามารถกำหนดจุดแตกหักสำหรับแกน y เป็นจำนวนเต็มที่คุณต้องการแสดง

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
โซลูชันนี้ใช้ได้ดีสำหรับสถานการณ์ที่คุณรู้ว่าค่าใดอยู่บนแกนเท่านั้น ไม่ใช่วิธีแก้ปัญหาทั่วไปที่ดี
swolf

4
หมายเหตุสำหรับคนรุ่นหลัง: ใช้geom_barไม่ได้กับความงามอีกต่อไป (แทนที่ด้วยgeom_col) และแม้ว่าจะไม่ใช่วิธีแก้ปัญหาทั่วไปในตัวอย่างนี้การโทรสวยด้วย 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

73

หากคุณมีscalesแพ็กเกจคุณสามารถใช้ได้pretty_breaks()โดยไม่ต้องระบุช่วงพักด้วยตนเอง

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

17
สิ่งนี้ดูเหมือนจะเกือบจะทำตามวิธีการเริ่มต้นและฉันยังมีจุดทศนิยมในช่วงพัก
kory

ในกรณีที่ไม่pretty_breaks()มาจากไหน?
Marian


16
pretty_breaks()ค่อนข้างสวย แต่ไม่ใช่จำนวนเต็มเสมอไป เห็นได้ชัดว่ามีความสวยงามเป็นทศนิยม ...
PatrickT

51

นี่คือสิ่งที่ฉันใช้:

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

นี่เป็นคำตอบแรกที่ได้ผล แต่ผู้อธิบายยินดีเป็นอย่างยิ่ง
DomQ

18

คุณสามารถใช้เครื่องติดฉลากที่กำหนดเองได้ ตัวอย่างเช่นฟังก์ชันนี้รับประกันว่าจะสร้างตัวแบ่งจำนวนเต็มเท่านั้น:

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

ใช้เป็น

+ scale_y_continuous(breaks = int_breaks)

มันทำงานโดยการแบ่งค่าเริ่มต้นและเก็บเฉพาะที่เป็นจำนวนเต็ม หากมีการแสดงช่วงพักข้อมูลของคุณน้อยเกินไปให้เพิ่มnเช่น:

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

สิ่งนี้ทำให้คุณสูญเสียจำนวนเต็ม 1 หากคุณมีข้อมูลตั้งแต่ 0 - 1.25 หรือคุณมีอะไร ฉันเห็น 0 บนแกน x เท่านั้น
kory

1
ฉันชอบสิ่งนี้เพราะเห็นแก่ความเรียบง่าย โปรดทราบว่าnอาจใช้การปรับแต่งบางอย่างขึ้นอยู่กับช่วงค่าของคุณ ดูเหมือนว่าจะกำหนดว่าจะมีการหยุดพักกี่ครั้ง (คร่าวๆ)
Marian

15

วิธีแก้ปัญหาเหล่านี้ไม่ได้ผลสำหรับฉันและไม่ได้อธิบายวิธีแก้ปัญหา

breaksโต้แย้งกับscale_*_continuousฟังก์ชั่นที่สามารถใช้กับฟังก์ชั่นที่กำหนดเองที่ใช้วงเงินเป็น input และส่งกลับแบ่งเป็นผลผลิต ตามค่าเริ่มต้นขีด จำกัด ของแกนจะขยาย 5% ในแต่ละด้านสำหรับข้อมูลต่อเนื่อง (เทียบกับช่วงของข้อมูล) ขีด จำกัด ของแกนจะไม่เป็นค่าจำนวนเต็มเนื่องจากการขยายนี้

วิธีแก้ปัญหาที่ฉันกำลังมองหาคือเพียงแค่ปัดเศษขีด จำกัด ล่างขึ้นเป็นจำนวนเต็มที่ใกล้ที่สุดปัดขีด จำกัด บนลงไปเป็นจำนวนเต็มที่ใกล้ที่สุดจากนั้นแบ่งค่าจำนวนเต็มระหว่างจุดสิ้นสุดเหล่านี้ ดังนั้นฉันจึงใช้ฟังก์ชันแบ่ง:

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

ข้อมูลโค้ดที่จำเป็นคือ:

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

ตัวอย่างที่ทำซ้ำได้จากคำถามเดิมคือ:

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
คำตอบที่ดีที่สุดที่นี่
Martin

ฉันเห็นด้วยกับมาร์ติน - ขอขอบคุณที่พยายามจัดทำตัวอย่างที่ใช้งานได้อย่างเต็มที่ ฉันสังเกตเห็นว่าคำตอบของ Daniel Gardinerใช้ฟังก์ชันการแบ่งที่ดีกว่าซึ่งจะไม่ทำให้เกิดความยุ่งเหยิงเมื่อช่วงแกนอยู่ในช่วงหลักร้อยขึ้นไป นอกจากนี้ตามรสนิยมแล้วฉันรู้สึกว่าการกำหนดและใช้breaks_integersฟังก์ชันแยกต่างหากอาจเป็นประโยชน์สำหรับผู้เริ่มต้นมากกว่า ดีที่สุด
DomQ

5

คำตอบที่มีอยู่ทั้งหมดดูเหมือนจะต้องใช้ฟังก์ชันที่กำหนดเองหรือล้มเหลวในบางกรณี

บรรทัดนี้แบ่งจำนวนเต็ม:

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

สำหรับข้อมูลเพิ่มเติมโปรดดูเอกสารประกอบ?labeling::extended(ซึ่งเป็นฟังก์ชันที่เรียกโดยscales::breaks_extended)

โดยพื้นฐานแล้วอาร์กิวเมนต์Qคือชุดของตัวเลขที่ดีที่อัลกอริทึมพยายามใช้สำหรับการแบ่งมาตราส่วน พล็อตเดิมที่ผลิตแบ่งที่ไม่ใช่จำนวนเต็ม (0, 2.5, 5 และ 7.5) เนื่องจากค่าเริ่มต้นสำหรับการQรวม Q = c(1,5,2,2.5,4,3)2.5:

แก้ไข:ตามที่ระบุไว้ในความคิดเห็นการแบ่งที่ไม่ใช่จำนวนเต็มอาจเกิดขึ้นได้เมื่อแกน y มีช่วงเล็ก ๆ โดยค่าเริ่มต้นbreaks_extended()จะพยายามสร้างn = 5ช่วงพักซึ่งเป็นไปไม่ได้เมื่อช่วงมีขนาดเล็กเกินไป การทดสอบด่วนแสดงให้เห็นว่าช่วงที่กว้างกว่า 0 <y <2.5 ให้ตัวแบ่งจำนวนเต็ม ( nสามารถลดได้ด้วยตนเอง)


3

Google นำฉันมาสู่คำถามนี้ ฉันกำลังพยายามใช้จำนวนจริงในระดับที่เหมาะสม ตัวเลขมาตราส่วน y อยู่ในหน่วยล้าน

เครื่องชั่งน้ำหนักแพคเกจcommaวิธีการแนะนำจุลภาคจำนวนมากของฉัน โพสต์นี้ในR-Bloggersอธิบายวิธีการง่ายๆโดยใช้commaวิธีการ:

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)

สนุกกับR :)


1
วิธีแก้ปัญหาอื่น ๆ ที่นี่ไม่ได้ผลสำหรับฉันจริง ๆ หรือดูเหมือนซับซ้อนอย่างน่าขัน อันนี้ใช้ได้ผลและทำได้ง่าย
Brian Doherty

ขอบคุณ @BrianDoherty ความเรียบง่ายเป็นกุญแจสำคัญสำหรับทุกสิ่ง ...
Tony Cronin

2

ฉันพบวิธีแก้ปัญหานี้จาก Joshua Cook และทำงานได้ดี

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

แหล่งที่มาคือ: https://joshuacook.netlify.app/post/integer-values-ggplot-axis/


ฟังก์ชันนี้ควรเป็นคำตอบที่ถูกต้อง ทำงานได้ง่ายกว่าใด ๆ !
zdebruine

1

คำตอบนี้สร้างขึ้นจากคำตอบของ @ Axeman เพื่อระบุความคิดเห็นโดย kory ว่าหากข้อมูลเปลี่ยนจาก 0 ถึง 1 เท่านั้นจะไม่มีการแบ่งที่ 1 ซึ่งดูเหมือนว่าจะเป็นเพราะความไม่ถูกต้องในprettyเอาต์พุตซึ่งดูเหมือนว่า 1 จะไม่เหมือนกับ 1 (ดูตัวอย่างตอนท้าย)

เพราะฉะนั้นถ้าคุณใช้

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

ด้วย

+ scale_y_continuous(breaks = int_breaks_rounded)

ทั้ง 0 และ 1 จะแสดงเป็นตัวแบ่ง

ตัวอย่างเพื่อแสดงความแตกต่างจาก Axeman's

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)

ทั้งสองอย่างจะทำงานกับข้อมูลที่ให้ไว้ในคำถามเริ่มต้น

ภาพประกอบว่าเหตุใดจึงต้องมีการปัดเศษ

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.