สั่งซื้อแท่งกราฟแท่ง ggplot2


301

ฉันกำลังพยายามสร้างกราฟแท่งที่แถบที่ใหญ่ที่สุดใกล้กับแกน y และแถบที่สั้นที่สุดจะไกลที่สุด นี่คือตารางที่ฉันมี

    Name   Position
1   James  Goalkeeper
2   Frank  Goalkeeper
3   Jean   Defense
4   Steve  Defense
5   John   Defense
6   Tim    Striker

ดังนั้นฉันจึงพยายามสร้างกราฟแท่งที่จะแสดงจำนวนผู้เล่นตามตำแหน่ง

p <- ggplot(theTable, aes(x = Position)) + geom_bar(binwidth = 1)

แต่กราฟจะแสดงแถบผู้รักษาประตูก่อนจากนั้นจะเป็นการป้องกันและในที่สุดก็เป็นกองหน้า ฉันต้องการให้กราฟสั่งให้แถบป้องกันอยู่ใกล้กับแกน y, ผู้รักษาประตูคนหนึ่งและในที่สุดก็เป็นกองหน้า ขอบคุณ


12
ggplot ไม่สามารถจัดลำดับใหม่ให้คุณโดยไม่ต้องยุ่งกับตาราง (หรือ dataframe)?
tumultous_rooster

1
@ MattO'Brien ฉันพบว่าไม่น่าเชื่อว่าสิ่งนี้ไม่ได้ทำในคำสั่งเดียวที่เรียบง่าย
Euler_Salter

@Zimano แย่เกินไปนั่นคือสิ่งที่คุณได้รับจากความคิดเห็นของฉัน การสังเกตของฉันมีต่อผู้สร้างggplot2ไม่ใช่ OP
Euler_Salter

2
@Euler_Salter ขอขอบคุณที่ให้ความกระจ่างขอโทษอย่างจริงใจของฉันสำหรับการกระโดดที่คุณเช่นนั้น ฉันได้ลบคำพูดเดิมของฉัน
Zimano

คำตอบ:


214

กุญแจสำคัญในการสั่งซื้อคือการกำหนดระดับของปัจจัยตามลำดับที่คุณต้องการ ไม่จำเป็นต้องใช้ปัจจัยสั่ง ข้อมูลเพิ่มเติมในปัจจัยที่จัดเรียงนั้นไม่จำเป็นและหากมีการใช้ข้อมูลเหล่านี้ในแบบจำลองทางสถิติใด ๆ การ parametrisation ที่ไม่ถูกต้องอาจส่งผลให้ - ความแตกต่างของพหุนามไม่เหมาะสมสำหรับข้อมูลที่ระบุเช่นนี้

## set the levels in order we want
theTable <- within(theTable, 
                   Position <- factor(Position, 
                                      levels=names(sort(table(Position), 
                                                        decreasing=TRUE))))
## plot
ggplot(theTable,aes(x=Position))+geom_bar(binwidth=1)

รูปที่ barplot

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

theTable$Position <- factor(theTable$Position, levels = c(...))

1
@Gavin: 2 การทำให้เข้าใจง่าย: เนื่องจากคุณใช้อยู่แล้วคุณwithinไม่จำเป็นต้องใช้theTable$Positionและคุณสามารถทำได้sort(-table(...))เพื่อลดลำดับ
Prasad Chalasani

2
@ ประสาทอดีตเป็นส่วนที่เหลือจากการทดสอบดังนั้นขอบคุณสำหรับการชี้ให้เห็นว่า เท่าที่ผ่านมาฉันชอบถามอย่างชัดเจนถึงการเรียงลำดับย้อนกลับมากกว่าที่-คุณใช้เพราะมันง่ายกว่าที่จะได้รับความตั้งใจdecreasing = TRUEมากกว่าสังเกตเห็น-รหัสที่เหลือทั้งหมด
Gavin Simpson

2
@GavinSimpson; ฉันคิดว่าส่วนหนึ่งเกี่ยวกับlevels(theTable$Position) <- c(...)การนำไปสู่พฤติกรรมที่ไม่พึงประสงค์ซึ่งรายการจริงของ data frame ได้รับการจัดลำดับใหม่ไม่ใช่เฉพาะระดับของปัจจัย ดูคำถามนี้ บางทีคุณควรแก้ไขหรือลบบรรทัดเหล่านั้นใช่ไหม
Anton

2
เห็นด้วยอย่างยิ่งกับแอนตัน ฉันเพิ่งเห็นคำถามนี้และเดิน poking levels<-รอบที่พวกเขามีคำแนะนำที่ดีที่จะใช้ ฉันจะแก้ไขส่วนนั้นอย่างน้อยอย่างไม่แน่นอน
Gregor Thomas

2
@ Anton ขอบคุณสำหรับคำแนะนำ (และ Gregor สำหรับการแก้ไข); ฉันจะไม่ทำสิ่งนี้ผ่านlevels<-()วันนี้ นี่คือสิ่งที่มาจาก 8 ปีย้อนหลังและฉันจำไม่ได้ว่าสิ่งต่าง ๆ ในตอนนั้นหรือว่าฉันแค่ผิดธรรมดา แต่ไม่ว่าจะผิดและควรลบ! ขอบคุณ!
Gavin Simpson

220

@GavinSimpson: reorderเป็นโซลูชั่นที่ทรงพลังและมีประสิทธิภาพสำหรับสิ่งนี้:

ggplot(theTable,
       aes(x=reorder(Position,Position,
                     function(x)-length(x)))) +
       geom_bar()

7
+1 จริงและโดยเฉพาะอย่างยิ่งในกรณีนี้ที่มีลำดับตรรกะที่เราสามารถใช้ประโยชน์จากตัวเลข หากเราพิจารณาการจัดหมวดหมู่ตามอำเภอใจและเราไม่ต้องการเรียงตามตัวอักษรมันเป็นเรื่องง่าย (ง่ายกว่า) ในการระบุระดับตามที่แสดง
Gavin Simpson

2
นี่คือความประณีต ลบล้างความจำเป็นในการแก้ไขดาต้าเฟรมเดิม
T.Fung

น่ารักเพิ่งสังเกตเห็นว่าคุณสามารถทำเช่นนี้เล็ก ๆ น้อย ๆ ขึ้น succincly ถ้าสิ่งที่คุณต้องการคือการสั่งซื้อโดยฟังก์ชั่นความยาวและการสั่งซื้อน้อยไปหามากไม่เป็นไรซึ่งเป็นสิ่งที่ผมมักจะต้องการที่จะทำ:ggplot(theTable,aes(x=reorder(Position,Position,length))+geom_bar()
postylem

146

ใช้scale_x_discrete (limits = ...)เพื่อระบุลำดับของแถบ

positions <- c("Goalkeeper", "Defense", "Striker")
p <- ggplot(theTable, aes(x = Position)) + scale_x_discrete(limits = positions)

12
วิธีแก้ปัญหาของคุณเหมาะสมกับสถานการณ์ของฉันมากที่สุดเนื่องจากฉันต้องการตั้งโปรแกรมให้พล็อตโดย x เป็นคอลัมน์ที่กำหนดโดยตัวแปรใน data.frame ข้อเสนอแนะอื่น ๆ จะยากขึ้นในการแสดงการจัดลำดับของ x โดยนิพจน์ที่เกี่ยวข้องกับตัวแปร ขอบคุณ! หากมีความสนใจฉันสามารถแบ่งปันโซลูชันของฉันโดยใช้ข้อเสนอแนะของคุณ อีกหนึ่งปัญหาที่เพิ่ม scale_x_discrete (จำกัด = ... ) ฉันพบว่ามีพื้นที่ว่างกว้างเท่ากับแผนภูมิแท่งทางด้านขวาของแผนภูมิ ฉันจะกำจัดพื้นที่ว่างได้อย่างไร ในขณะที่มันไม่ได้ตอบสนองวัตถุประสงค์ใด ๆ
Yu Shen

ดูเหมือนว่าจำเป็นสำหรับการสั่งซื้อแท่งฮิสโตแกรม
geotheory

9
QIBIN: ว้าว ... คำตอบอื่น ๆ ที่นี่ใช้ได้ แต่คำตอบของคุณดูเหมือนจะไม่เพียง แต่รัดกุมและสง่างามที่สุด แต่ชัดเจนที่สุดเมื่อคิดถึงจากภายในกรอบของ ggplot ขอบคุณ.
Dan Nguyen

เมื่อฉันลองวิธีนี้บนข้อมูลของฉันมันไม่ได้กราฟ NAs มีวิธีใช้โซลูชันนี้และมีกราฟ NAs หรือไม่
user2460499

นี่เป็นทางออกที่หรูหราและเรียบง่าย - ขอบคุณ !!
Kalif Vaughn

91

ฉันคิดว่าวิธีแก้ปัญหาที่ให้ไว้นั้นมีความละเอียดมากเกินไป วิธีรัดกุมมากขึ้นในการทำ barplot ที่เรียงลำดับความถี่ด้วย ggplot คือ

ggplot(theTable, aes(x=reorder(Position, -table(Position)[Position]))) + geom_bar()

มันคล้ายกับสิ่งที่ Alex Brown แนะนำ แต่สั้นกว่าเล็กน้อยและทำงานได้โดยไม่ต้องมีคำจำกัดความฟังก์ชันใด ๆ

ปรับปรุง

ฉันคิดว่าวิธีแก้ปัญหาแบบเก่าของฉันทำได้ดีในเวลานั้น แต่ทุกวันนี้ฉันควรใช้forcats::fct_infreqซึ่งเป็นการเรียงลำดับปัจจัยตามความถี่:

require(forcats)

ggplot(theTable, aes(fct_infreq(Position))) + geom_bar()

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

1
@ user3282777 คุณได้ลองใช้ docs stat.ethz.ch/R-manual/R-devel/library/stats/html/ แล้วหรือยัง?
Holger Brandl

1
สุดยอดทางออก! ดีใจที่ได้เห็นคนอื่นใช้โซลูชั่นที่เป็นระเบียบเรียบร้อย!
Mike

29

เช่นเดียวกับในคำตอบของอเล็กซ์บราวน์เรายังสามารถใช้reorder() forcats::fct_reorder()โดยพื้นฐานแล้วมันจะเรียงลำดับปัจจัยที่ระบุใน ARG 1 ตามค่าใน ARG 2 หลังจากใช้ฟังก์ชั่นที่ระบุ (ค่าเริ่มต้น = ค่ามัธยฐานซึ่งเป็นสิ่งที่เราใช้ที่นี่เพียงแค่มีหนึ่งค่าต่อระดับปัจจัย)

เป็นที่น่าเสียดายที่ในคำถามของ OP ลำดับที่ต้องการนั้นยังเรียงตามตัวอักษรเนื่องจากเป็นลำดับการจัดเรียงเริ่มต้นเมื่อคุณสร้างปัจจัยดังนั้นจะซ่อนสิ่งที่ฟังก์ชันนี้กำลังทำอยู่ เพื่อให้ชัดเจนยิ่งขึ้นฉันจะแทนที่ "ผู้รักษาประตู" ด้วย "Zoalkeeper"

library(tidyverse)
library(forcats)

theTable <- data.frame(
                Name = c('James', 'Frank', 'Jean', 'Steve', 'John', 'Tim'),
                Position = c('Zoalkeeper', 'Zoalkeeper', 'Defense',
                             'Defense', 'Defense', 'Striker'))

theTable %>%
    count(Position) %>%
    mutate(Position = fct_reorder(Position, n, .desc = TRUE)) %>%
    ggplot(aes(x = Position, y = n)) + geom_bar(stat = 'identity')

ป้อนคำอธิบายรูปภาพที่นี่


1
IMHO ทางออกที่ดีที่สุดเช่นเดียวกับ forcats เป็น dplyr แพ็คเกจ tidyverse
c0bra

ยกนิ้วให้ Zoalkeeper
otwtm

23

การเรียงลำดับตามปัจจัยแบบง่าย ๆ สามารถแก้ไขปัญหานี้ได้:

library(dplyr)

#reorder the table and reset the factor to that ordering
theTable %>%
  group_by(Position) %>%                              # calculate the counts
  summarize(counts = n()) %>%
  arrange(-counts) %>%                                # sort by counts
  mutate(Position = factor(Position, Position)) %>%   # reset factor
  ggplot(aes(x=Position, y=counts)) +                 # plot 
    geom_bar(stat="identity")                         # plot histogram

19

คุณเพียงแค่ต้องระบุPositionคอลัมน์ให้เป็นปัจจัยจัดเรียงที่ระดับจะถูกเรียงลำดับตามการนับ:

theTable <- transform( theTable,
       Position = ordered(Position, levels = names( sort(-table(Position)))))

(โปรดทราบว่าการtable(Position)สร้างความถี่นับของPositionคอลัมน์)

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


ฉันไม่ได้แยกวิเคราะห์โค้ดของคุณทั้งหมด แต่ฉันค่อนข้างแน่ใจว่าreorder()จากไลบราลีสถิติทำภารกิจเดียวกัน
Chase

@Chase คุณเสนอให้ใช้อย่างไรreorder()ในกรณีนี้ ปัจจัยที่ต้องมีการจัดเรียงใหม่จำเป็นต้องจัดลำดับใหม่โดยฟังก์ชันบางอย่างของตัวเองและฉันกำลังดิ้นรนเพื่อดูวิธีที่ดีในการทำเช่นนั้น
Gavin Simpson

ตกลงwith(theTable, reorder(Position, as.character(Position), function(x) sum(duplicated(x))))เป็นวิธีหนึ่งและอื่น ๆwith(theTable, reorder(Position, as.character(Position), function(x) as.numeric(table(x))))แต่สิ่งเหล่านี้เป็นเพียง convoluted ...
Gavin Simpson

ฉันทำให้คำตอบง่ายขึ้นเล็กน้อยเพื่อใช้sortแทนorder
Prasad Chalasani

@Gavin - บางทีฉันเข้าใจผิดรหัสต้นฉบับของ Prasad (ฉันไม่มี R บนเครื่องนี้เพื่อทดสอบ ... ) แต่ดูเหมือนว่าเขากำลังจัดเรียงหมวดหมู่ใหม่ตามความถี่ซึ่งreorderเชี่ยวชาญในการทำ ฉันเห็นด้วยกับคำถามนี้ว่าจำเป็นต้องมีสิ่งที่เกี่ยวข้องมากกว่านี้ ขอโทษสำหรับความสับสน.
Chase

17

นอกจาก forcats :: fct_infreq ที่กล่าวถึงโดย @HolgerBrandl ยังมี forcats :: fct_rev ซึ่งกลับคำสั่งตัวคูณ

theTable <- data.frame(
    Position= 
        c("Zoalkeeper", "Zoalkeeper", "Defense",
          "Defense", "Defense", "Striker"),
    Name=c("James", "Frank","Jean",
           "Steve","John", "Tim"))

p1 <- ggplot(theTable, aes(x = Position)) + geom_bar()
p2 <- ggplot(theTable, aes(x = fct_infreq(Position))) + geom_bar()
p3 <- ggplot(theTable, aes(x = fct_rev(fct_infreq(Position)))) + geom_bar()

gridExtra::grid.arrange(p1, p2, p3, nrow=3)             

เอาต์พุต gplot


"fct_infreq (ตำแหน่ง)" เป็นสิ่งเล็กน้อยที่ทำได้มากขอบคุณ !!
พอล

12

ฉันเห็นด้วยกับแซคว่าการนับภายใน dplyr เป็นทางออกที่ดีที่สุด ฉันพบสิ่งนี้ว่าเป็นรุ่นที่สั้นที่สุด:

dplyr::count(theTable, Position) %>%
          arrange(-n) %>%
          mutate(Position = factor(Position, Position)) %>%
          ggplot(aes(x=Position, y=n)) + geom_bar(stat="identity")

นอกจากนี้ยังจะมีความหมายได้เร็วกว่าการจัดเรียงใหม่ระดับปัจจัยก่อนตั้งแต่การนับจะทำใน dplyr ไม่ได้อยู่ใน ggplot tableหรือใช้


12

หากคอลัมน์แผนภูมิมาจากตัวแปรที่เป็นตัวเลขเช่นเดียวกับใน dataframe ด้านล่างคุณสามารถใช้วิธีที่ง่ายกว่า:

ggplot(df, aes(x = reorder(Colors, -Qty, sum), y = Qty)) 
+ geom_bar(stat = "identity")  

เครื่องหมายลบก่อนตัวแปร sort (-Qty) ควบคุมทิศทางการเรียง (ขึ้น / ลง)

นี่คือข้อมูลสำหรับการทดสอบ:

df <- data.frame(Colors = c("Green","Yellow","Blue","Red","Yellow","Blue"),  
                 Qty = c(7,4,5,1,3,6)
                )

**Sample data:**
  Colors Qty
1  Green   7
2 Yellow   4
3   Blue   5
4    Red   1
5 Yellow   3
6   Blue   6

เมื่อฉันพบกระทู้นี้นั่นคือคำตอบที่ฉันต้องการ หวังว่ามันจะมีประโยชน์สำหรับคนอื่น ๆ


8

ทางเลือกอื่นโดยใช้การจัดลำดับใหม่เพื่อสั่งซื้อระดับของปัจจัย เป็นการเรียงจากน้อยไปมาก (n) หรือจากมากไปหาน้อย (-n) ตามจำนวน คล้ายกับที่ใช้fct_reorderจากforcatsแพ็คเกจ:

เรียงลำดับจากมากไปน้อย

df %>%
  count(Position) %>%
  ggplot(aes(x = reorder(Position, -n), y = n)) +
  geom_bar(stat = 'identity') +
  xlab("Position")

ป้อนคำอธิบายรูปภาพที่นี่

เรียงลำดับขึ้น

df %>%
  count(Position) %>%
  ggplot(aes(x = reorder(Position, n), y = n)) +
  geom_bar(stat = 'identity') +
  xlab("Position")

ป้อนคำอธิบายรูปภาพที่นี่

กรอบข้อมูล:

df <- structure(list(Position = structure(c(3L, 3L, 1L, 1L, 1L, 2L), .Label = c("Defense", 
"Striker", "Zoalkeeper"), class = "factor"), Name = structure(c(2L, 
1L, 3L, 5L, 4L, 6L), .Label = c("Frank", "James", "Jean", "John", 
"Steve", "Tim"), class = "factor")), class = "data.frame", row.names = c(NA, 
-6L))

5

เนื่องจากเราดูที่การกระจายตัวของตัวแปรเดี่ยว ("ตำแหน่ง") เท่านั้นเมื่อเทียบกับการมองหาความสัมพันธ์ระหว่างสองตัวแปรดังนั้นบางทีฮิสโตแกรมจะเป็นกราฟที่เหมาะสมกว่า ggplot มีgeom_histogram ()ที่ทำให้ง่าย:

ggplot(theTable, aes(x = Position)) + geom_histogram(stat="count")

ป้อนคำอธิบายรูปภาพที่นี่

ใช้ geom_histogram ():

ฉันคิดว่าgeom_histogram ( ) นั้นแปลกไปหน่อยเพราะมันปฏิบัติต่อเนื่องและแยกข้อมูลต่างกัน

สำหรับข้อมูลต่อเนื่องคุณสามารถใช้geom_histogram ()โดยไม่มีพารามิเตอร์ ตัวอย่างเช่นถ้าเราเพิ่มใน "คะแนน" เวกเตอร์ตัวเลข ...

    Name   Position   Score  
1   James  Goalkeeper 10
2   Frank  Goalkeeper 20
3   Jean   Defense    10
4   Steve  Defense    10
5   John   Defense    20
6   Tim    Striker    50

และใช้ geom_histogram () กับตัวแปร "คะแนน" ...

ggplot(theTable, aes(x = Score)) + geom_histogram()

ป้อนคำอธิบายรูปภาพที่นี่

สำหรับข้อมูลที่ไม่ต่อเนื่องเช่น "ตำแหน่ง" เราต้องระบุสถิติที่คำนวณโดยสุนทรียศาสตร์เพื่อให้ค่า y สำหรับความสูงของแท่งโดยใช้stat = "count":

 ggplot(theTable, aes(x = Position)) + geom_histogram(stat = "count")

หมายเหตุ:อยากรู้อยากเห็นและสับสนคุณยังสามารถใช้stat = "count"สำหรับข้อมูลต่อเนื่องได้เช่นกันและฉันคิดว่ามันให้กราฟที่น่าพอใจยิ่งขึ้น

ggplot(theTable, aes(x = Score)) + geom_histogram(stat = "count")

ป้อนคำอธิบายรูปภาพที่นี่

การแก้ไข : ขยายคำตอบเพื่อตอบสนองคำแนะนำที่เป็นประโยชน์ของDebanjanB


0

ฉันพบว่ามันน่ารำคาญมากที่ggplot2ไม่มีวิธีการ 'อัตโนมัติ' สำหรับสิ่งนี้ นั่นเป็นเหตุผลที่ฉันสร้างฟังก์ชั่นในbar_chart()ggcharts

ggcharts::bar_chart(theTable, Position)

ป้อนคำอธิบายรูปภาพที่นี่

ตามค่าเริ่มต้นจะbar_chart()เรียงแท่งและแสดงพล็อตแนวนอน หากต้องการเปลี่ยนชุด horizontal = FALSEนั้น นอกจากนี้bar_chart()จะลบ 'ช่องว่าง' ที่ไม่น่าดูระหว่างแท่งกับแกน

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