Thanh thứ tự trong biểu đồ thanh ggplot2


301

Tôi đang cố gắng tạo một biểu đồ thanh trong đó thanh lớn nhất sẽ gần trục y nhất và thanh ngắn nhất sẽ xa nhất. Vì vậy, đây là loại giống như Bảng tôi có

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

Vì vậy, tôi đang cố gắng xây dựng một biểu đồ thanh hiển thị số lượng người chơi theo vị trí

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

nhưng biểu đồ cho thấy thanh thủ môn đầu tiên sau đó là phòng thủ, và cuối cùng là tiền đạo. Tôi muốn đồ thị được sắp xếp sao cho thanh phòng thủ gần nhất với trục y, thủ môn và cuối cùng là tiền đạo. Cảm ơn


12
ggplot không thể sắp xếp lại chúng cho bạn mà không phải loay hoay với bảng (hoặc khung dữ liệu)?
tumultous_rooster

1
@ MattO'Brien Tôi thấy thật khó tin rằng điều này không được thực hiện trong một lệnh đơn giản, đơn giản
Euler_Salter

@Zimano Quá tệ đó là những gì bạn nhận được từ nhận xét của tôi. Quan sát của tôi là về phía những người tạo ra ggplot2, chứ không phải OP
Euler_Salter

2
@Euler_Salter Cảm ơn bạn đã làm rõ, lời xin lỗi chân thành của tôi đã nhảy vào bạn như thế. Tôi đã xóa nhận xét ban đầu của tôi.
Zimano

Câu trả lời:


214

Chìa khóa với thứ tự là đặt các mức của yếu tố theo thứ tự bạn muốn. Một yếu tố được yêu cầu là không cần thiết; thông tin bổ sung trong một yếu tố được sắp xếp là không cần thiết và nếu những dữ liệu này đang được sử dụng trong bất kỳ mô hình thống kê nào, thì việc tham số hóa sai có thể dẫn đến - sự tương phản đa thức không phù hợp với dữ liệu danh nghĩa như thế này.

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

con số barplot

Theo nghĩa chung nhất, chúng ta chỉ cần đặt các mức yếu tố theo thứ tự mong muốn. Nếu không được chỉ định, các mức của một yếu tố sẽ được sắp xếp theo thứ tự abc. Bạn cũng có thể chỉ định thứ tự cấp độ trong lệnh gọi đến hệ số như trên và các cách khác cũng có thể.

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

1
@Gavin: 2 đơn giản hóa: vì bạn đã sử dụng within, nên không cần sử dụng theTable$Positionvà bạn chỉ có thể làm sort(-table(...))để giảm thứ tự.
Prasad Chalasani

2
@Prasad trước đây là một phần còn lại từ thử nghiệm vì vậy cảm ơn bạn đã chỉ ra điều đó. Về sau, tôi thích rõ ràng yêu cầu sắp xếp đảo ngược hơn so với cách -bạn sử dụng vì nó dễ dàng có được ý định decreasing = TRUEhơn là nhận thấy -trong tất cả các phần còn lại của mã.
Gavin Simpson

2
@GavinSimpson; Tôi nghĩ rằng phần levels(theTable$Position) <- c(...)dẫn đến hành vi không mong muốn trong đó các mục thực tế của khung dữ liệu được sắp xếp lại, và không chỉ các cấp của yếu tố. Xem câu hỏi này . Có lẽ bạn nên sửa đổi hoặc loại bỏ những dòng đó?
Anton

2
Rất đồng ý với Anton. Tôi chỉ thấy câu hỏi này và đi chọc vào nơi họ nhận được lời khuyên tồi để sử dụng levels<-. Tôi sẽ chỉnh sửa phần đó ra, ít nhất là dự kiến.
Gregor Thomas

2
@Anton Cảm ơn bạn đã gợi ý (và để Gregor chỉnh sửa); Tôi sẽ không bao giờ làm điều này qua levels<-()ngày hôm nay. Đây là một cái gì đó từ 8 năm trước và tôi không thể nhớ lại nếu mọi thứ trở lại khác đi hay liệu tôi chỉ đơn giản là sai, nhưng bất kể, đó là sai và nên được xóa! Cảm ơn!
Gavin Simpson

220

@GavinSimpson: reorderlà một giải pháp mạnh mẽ và hiệu quả cho việc này:

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

7
Thật vậy, +1 và đặc biệt trong trường hợp này có thứ tự logic mà chúng ta có thể khai thác bằng số. Nếu chúng tôi xem xét việc sắp xếp các danh mục tùy ý và chúng tôi không muốn theo thứ tự bảng chữ cái thì việc chỉ định các cấp trực tiếp như được hiển thị là dễ dàng (dễ dàng hơn?).
Gavin Simpson

2
Đây là gọn gàng nhất. Nullify sự cần thiết phải sửa đổi khung dữ liệu gốc
T.Fung

Thật đáng yêu, chỉ cần lưu ý rằng bạn có thể làm điều này một cách ngắn gọn hơn một chút, nếu tất cả những gì bạn muốn là sắp xếp theo chức năng độ dài và thứ tự tăng dần là ổn, đó là điều tôi thường muốn làm:ggplot(theTable,aes(x=reorder(Position,Position,length))+geom_bar()
postylem

146

Sử dụng scale_x_discrete (limits = ...)để xác định thứ tự của các thanh.

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

12
Giải pháp của bạn là phù hợp nhất với tình huống của tôi, vì tôi muốn lập trình để vẽ đồ thị với x là một cột tùy ý được biểu thị bằng một biến trong data.frame. Các đề xuất khác sẽ khó diễn đạt sự sắp xếp thứ tự của x bằng một biểu thức liên quan đến biến. Cảm ơn! Nếu có hứng thú, tôi có thể chia sẻ giải pháp của mình bằng đề xuất của bạn. Chỉ một vấn đề nữa, thêm scale_x_disc rời (giới hạn = ...), tôi thấy rằng có khoảng trống rộng như biểu đồ thanh, ở bên phải của biểu đồ. Làm thế nào tôi có thể thoát khỏi không gian trống? Vì nó không phục vụ cho bất kỳ mục đích nào.
Yu Shen

Điều này có vẻ cần thiết để đặt hàng thanh biểu đồ
geotheory

9
QIBIN: Wow ... các câu trả lời khác ở đây có tác dụng, nhưng câu trả lời của bạn cho đến nay dường như không chỉ ngắn gọn và thanh lịch nhất, mà còn rõ ràng nhất khi suy nghĩ từ trong khuôn khổ của ggplot. Cảm ơn bạn.
Đan Nguyên

Khi tôi thử giải pháp này, trên dữ liệu của tôi, nó không có biểu đồ NA. Có cách nào để sử dụng giải pháp này và có biểu đồ NA không?
dùng2460499

Đây là một giải pháp thanh lịch và đơn giản - cảm ơn bạn !!
Kalif Vaughn

91

Tôi nghĩ rằng các giải pháp đã được cung cấp là quá dài dòng. Một cách ngắn gọn hơn để thực hiện một barplot được sắp xếp tần số với ggplot là

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

Nó tương tự như những gì Alex Brown đề xuất, nhưng ngắn hơn một chút và hoạt động mà không có định nghĩa hàm bất kỳ.

Cập nhật

Tôi nghĩ rằng giải pháp cũ của tôi là tốt vào thời điểm đó, nhưng ngày nay tôi muốn sử dụng forcats::fct_infreqđó là sắp xếp các mức yếu tố theo tần suất:

require(forcats)

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

Tôi không hiểu đối số thứ hai để sắp xếp lại chức năng và nó làm gì. Bạn có thể vui lòng giải thích những gì đang xảy ra?
dùng3282777

1
@ user3282777 bạn đã thử tài liệu stat.ethz.ch/R-manual/R-devel/l Library / stat / html / Lỗi ?
Holger Brandl

1
Giải pháp tuyệt vời! Thật tốt khi thấy những người khác sử dụng các giải pháp ngăn nắp!
Mike

29

Giống như reorder()trong câu trả lời của Alex Brown, chúng ta cũng có thể sử dụng forcats::fct_reorder(). Về cơ bản, nó sẽ sắp xếp các yếu tố được chỉ định trong đối số 1, theo các giá trị trong đối số thứ 2 sau khi áp dụng một hàm được chỉ định (default = median, đây là những gì chúng ta sử dụng ở đây vì chỉ có một giá trị cho mỗi cấp độ yếu tố).

Thật đáng tiếc khi trong câu hỏi của OP, thứ tự được yêu cầu cũng theo thứ tự chữ cái vì đó là thứ tự sắp xếp mặc định khi bạn tạo các yếu tố, vì vậy sẽ ẩn chức năng này thực sự đang làm gì. Để làm rõ hơn, tôi sẽ thay thế "Thủ môn" bằng "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')

nhập mô tả hình ảnh ở đây


1
IMHO giải pháp tốt nhất là forcats cũng như dplyr một gói gọn gàng.
c0bra

giơ ngón tay cái lên cho Zoalkeeper
otwtm

23

Việc sắp xếp lại các yếu tố dựa trên dplyr đơn giản có thể giải quyết vấn đề này:

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

Bạn chỉ cần xác định Positioncột là một yếu tố được sắp xếp trong đó các mức được sắp xếp theo số lượng của chúng:

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

(Lưu ý rằng việc table(Position)tạo ra số đếm tần số của Positioncột.)

Sau đó, ggplotchức năng của bạn sẽ hiển thị các thanh theo thứ tự giảm dần. Tôi không biết nếu có một tùy chọn geom_barđể làm điều này mà không cần phải tạo một yếu tố theo thứ tự.


Tôi đã không phân tích đầy đủ mã của bạn trên đó, nhưng tôi khá chắc chắn reorder()từ thư viện thống kê hoàn thành nhiệm vụ tương tự.
Đuổi theo

@Chase làm thế nào để bạn đề xuất sử dụng reorder()trong trường hợp này? Yếu tố yêu cầu sắp xếp lại cần phải được sắp xếp lại theo một số chức năng của chính nó và tôi đang đấu tranh để xem một cách tốt để làm điều đó.
Gavin Simpson

ok, with(theTable, reorder(Position, as.character(Position), function(x) sum(duplicated(x))))là một cách, và một cách khác, with(theTable, reorder(Position, as.character(Position), function(x) as.numeric(table(x))))nhưng những điều này cũng như đang bị xáo trộn ...
Gavin Simpson

Tôi đã đơn giản hóa câu trả lời một chút để sử dụng sortthay vìorder
Prasad Chalasani

@Gavin - có lẽ tôi đã hiểu nhầm mã gốc của Prasad (tôi không có R trên máy này để kiểm tra ...) nhưng có vẻ như anh ta đang sắp xếp lại các danh mục dựa trên tần suất, điều reordernày rất phù hợp. Tôi đồng ý cho câu hỏi này rằng một cái gì đó liên quan nhiều hơn là cần thiết. Xin lỗi vì sự nhầm lẫn.
Đuổi theo

17

Ngoài forcats :: fct_infreq, được đề cập bởi @HolgerBrandl, còn có forcats :: fct numv, đảo ngược thứ tự yếu tố.

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)             

đầu ra gplot


"fct_infreq (Position)" là điều nhỏ bé làm được rất nhiều, cảm ơn !!
Paul

12

Tôi đồng ý với zach rằng đếm trong dplyr là giải pháp tốt nhất. Tôi thấy đây là phiên bản ngắn nhất:

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

Điều này cũng sẽ nhanh hơn đáng kể so với việc sắp xếp lại các cấp độ yếu tố trước vì số lượng được thực hiện trong dplyr không phải trong ggplot hoặc sử dụng table.


12

Nếu các cột biểu đồ đến từ một biến số như trong khung dữ liệu bên dưới, bạn có thể sử dụng một giải pháp đơn giản hơn:

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

Dấu trừ trước biến sắp xếp (-Qty) điều khiển hướng sắp xếp (tăng dần / giảm dần)

Đây là một số dữ liệu để thử nghiệm:

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

Khi tôi tìm thấy chủ đề này, đó là câu trả lời tôi đang tìm kiếm. Hy vọng nó hữu ích cho những người khác.


8

Một cách khác là sử dụng sắp xếp lại để sắp xếp các mức của một yếu tố. Theo thứ tự tăng dần (n) hoặc giảm dần (-n) dựa trên số đếm. Rất giống với cái được sử dụng fct_reordertừforcats gói:

Thứ tự giảm dần

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

nhập mô tả hình ảnh ở đây

Thứ tự tăng dần

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

nhập mô tả hình ảnh ở đây

Khung dữ liệu:

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

Vì chúng ta chỉ nhìn vào phân phối của một biến duy nhất ("Vị trí") trái ngược với việc xem xét mối quan hệ giữa hai biến , nên có lẽ biểu đồ sẽ là biểu đồ phù hợp hơn. ggplot có geom_histogram () giúp dễ dàng:

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

nhập mô tả hình ảnh ở đây

Sử dụng geom_histogram ():

Tôi nghĩ geom_histogram ( ) hơi kỳ quặc vì nó xử lý dữ liệu liên tục và rời rạc khác nhau.

Đối với dữ liệu liên tục , bạn chỉ có thể sử dụng geom_histogram () không có tham số. Ví dụ: nếu chúng ta thêm vào một vectơ số "Điểm" ...

    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

và sử dụng geom_histogram () trên biến "Điểm" ...

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

nhập mô tả hình ảnh ở đây

Đối với dữ liệu riêng biệt như "Vị trí", chúng tôi phải chỉ định một thống kê được tính toán theo thẩm mỹ để đưa ra giá trị y cho chiều cao của các thanh bằng cách sử dụng stat = "count":

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

Lưu ý: Thật kỳ lạ và khó hiểu bạn cũng có thể sử dụng stat = "count"cho dữ liệu liên tục và tôi nghĩ rằng nó cung cấp một biểu đồ thẩm mỹ hơn.

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

nhập mô tả hình ảnh ở đây

Chỉnh sửa : Câu trả lời mở rộng để đáp ứng với các đề xuất hữu ích của DebanjanB .


0

Tôi thấy rất khó chịu khi ggplot2không cung cấp giải pháp 'tự động' cho việc này. Đó là lý do tại sao tôi tạo ra bar_chart()chức năng này ggcharts.

ggcharts::bar_chart(theTable, Position)

nhập mô tả hình ảnh ở đây

Theo mặc định bar_chart()sắp xếp các thanh và hiển thị một âm mưu ngang. Để thay đổi bộ đó horizontal = FALSE. Ngoài ra, bar_chart()loại bỏ "khoảng cách" khó coi giữa các thanh và trục.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.