Cách sử dụng một biến để chỉ định tên cột trong ggplot


105

Tôi có một lệnh ggplot

ggplot( rates.by.groups, aes(x=name, y=rate, colour=majr, group=majr) )

bên trong một hàm. Nhưng tôi muốn có thể sử dụng một tham số của hàm để chọn ra cột để sử dụng làm màu và nhóm. Tức là tôi muốn một cái gì đó như thế này

f <- function( column ) {
    ...
    ggplot( rates.by.groups, aes(x=name, y=rate, colour= ??? , group=??? ) )
}

Vì vậy, cột được sử dụng trong ggplot được xác định bởi tham số. Ví dụ: đối với f ("majr"), chúng tôi nhận được hiệu ứng của

ggplot( rates.by.groups, aes(x=name, y=rate, colour=majr, group=majr) )

nhưng đối với f ("giới tính"), chúng tôi nhận được hiệu ứng của

  ggplot( rates.by.groups, aes(x=name, y=rate, colour=gender, group=gender) )

Một số điều tôi đã thử:

ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ) )

đã không làm việc. Cũng không

e <- environment() 
ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ), environment=e )

Câu trả lời:


161

Bạn có thể sử dụng aes_string:

f <- function( column ) {
    ...
    ggplot( rates.by.groups, aes_string(x="name", y="rate", colour= column,
                                        group=column ) )
}

miễn là bạn chuyển cột cho hàm dưới dạng chuỗi ( f("majr")chứ không phải f(majr)). Cũng lưu ý rằng chúng tôi đã thay đổi các cột khác "name""rate"thành chuỗi.

Nếu vì lý do nào đó mà bạn không muốn sử dụng aes_string, bạn có thể thay đổi nó thành (hơi rườm rà hơn):

    ggplot( rates.by.groups, aes(x=name, y=rate, colour= get(column),
                                        group=get(column) ) )

Điều đáng nói là bạn không nên / không thể làm aes_string(x = rates.by.groups$name..., và dù sao thì bạn cũng không cần vì bạn đã vượt qua ggplot(data = rates.by.groups...lập luận. (Vấn đề trong câu hỏi này )
smci

3
Chỉ cần thêm ghi chú để hướng mọi người đến câu trả lời của Moody_Mudskipper với các bản cập nhật cho ggplot2 phiên bản 3.0.0
Gregor Thomas

@buncis Đó là không đúng sự thật, trích dẫn "column_name"hoặc "column"sẽ không làm việc
David Robinson

@DavidRobinson xin lỗi do nhầm lẫn của tôi, tôi không thấy mã được bao bọc trên một hàm có tham số, tôi sẽ xóa nhận xét của tôi
buncis

"rườm rà"? Đánh giá không chuẩn trong R trớ trêu thay lại là "tính năng" cồng kềnh nhất mà tôi từng gặp trong một ngôn ngữ lập trình. Thật sự rất đáng buồn.
jessexknight

43

Từ ghi chú phát hành của ggplot2 V3.0.0:

aes () hiện hỗ trợ quasiquotation để bạn có thể sử dụng !!, !!!, và: =. Điều này thay thế aes_ () và aes_string () hiện không được dùng nữa (nhưng sẽ tồn tại trong một thời gian dài).

Cách thành ngữ bây giờ sẽ là chuyển đổi thành một ký hiệu chuỗi mà biến chứa, bằng cách sử dụng sym()(gần giống như bí danh cơ sở as.name()/ as.symbol()) và hủy trích dẫn nó bằng cách sử dụng!!

Mô phỏng dữ liệu của OP, chúng ta có thể làm:

library(tidyverse)
rates.by.groups <- data.frame(
  name = LETTERS[1:3],
  rate = 1:3,
  mjr = LETTERS[c(4,4,5)],
  gender = c("M","F","F")
)

f <- function(column) {
  column <- sym(column)
  ggplot(rates.by.groups, 
         aes(x = name, 
             y = rate, 
             fill  = !!column, 
             group = !!column)) +
    geom_col()
}

f("gender")
f("mjr")
x <- "gender"
f(x)

Nếu chúng ta muốn cung cấp các tên thô cho hàm, chúng ta có thể làm:

f2 <- function(column) {
  column <- ensym(column)
  ggplot(rates.by.groups, 
         aes(x = name, 
             y = rate, 
             fill  = !!column, 
             group = !!column)) +
    geom_col()
}

Nó sẽ hoạt động với các tên hay ký hiệu VÀ với các ký tự chuỗi

f2(gender)
f2(mjr)
f2("gender")
f2("mjr")

Như Lionel nói về ensym():

nó có nghĩa là bắt chước cú pháp của các đối số mà bạn có thể cung cấp cả hai trong LHS, ví dụ: list (bare = 1, "quote" = 2)


Một lưu ý về enquo()

enquo()trích dẫn biểu thức (không nhất thiết phải là ký hiệu) được cung cấp cho đối số, nó không chuyển đổi một chuỗi ký tự thành một ký hiệu như ensym()vậy, vì vậy nó có thể ít được điều chỉnh ở đây, nhưng chúng ta có thể làm:

f3 <- function(column) {
  column <- enquo(column)
  ggplot(rates.by.groups, 
         aes(x = name, 
             y = rate, 
             fill  = !!column, 
             group = !!column)) +
    geom_col()
}

f3(gender)
f2(mjr)

12
Công cụ ngăn nắp này thật khó chịu. Tài liệu cho aes()chính nó nói về enquo()nhưng nó không hoạt động. Và ai đã nghe nói về ensym()trước đây? BIG
SIGH

@Moody_Mudskipper Đối với f2, tất cả bốn ví dụ đều hoạt động và việc nắm bắt tên cột trong một biến (tức là aname <- "mjr"; f2(aname)) cũng vậy. Nếu tôi thêm mã để thao tác với khung dữ liệu bằng cách sử dụng dplyrnó sẽ cố gắng tìm một cột bằng tên biến chứ không phải chuỗi trong tên biến. Nói cách khác, làm thế nào để tôi đi rates.by.groups %>% group_by(!!column)...làm mà vẫn hỗ trợ ba cách gọi trên f2?
steveb

1
"việc nắm bắt tên cột trong một biến cũng vậy": nó không bị lỗi nhưng không trả về cùng một kết quả, ensymđược thiết kế để xử lý các đối số được cung cấp dưới dạng tên và dung nạp các dấu ngoặc kép xung quanh chúng. Tôi tin rằng bạn muốn coi đối số như một cái tên và quay trở lại giá trị nếu không tìm thấy tên. Đây thực sự là những gì xảy ra với select, nhưng không phải với group_by... Có thể hack xung quanh nó nhưng không rõ ràng. Nếu nó quan trọng với bạn, tôi nghĩ nó sẽ xứng đáng với câu hỏi của chính nó.
Moody_Mudskipper

@Moody_Mudskipper Cảm ơn. Tôi đã sử dụng cả hai selectgroup_byvì vậy đó có thể là vấn đề. Tôi có thể tạo một câu hỏi mới, nhưng tôi cần đưa ra một ví dụ đơn giản và kiểm tra xem nó đã được trả lời chưa. Tôi có thể đăng nó nếu không.
steveb

Cách sử dụng !! trong trường hợp của facet_grid? Nó hoạt động với facet_grid(cols = vars(!!column))nhưng ném một lỗi vớifacet_grid(~ !!column)
mRiddle

14

Hãy thử sử dụng aes_stringthay vì aes.


5
Đây là lời khuyên tuyệt vời nhưng bạn có thể cho họ biết tại sao không? aes_string khiến bạn sử dụng "" cho các biến không phải là biến và bạn sử dụng dấu ngoặc kép của biến. aes_string (x = "foo", y = "phí", nhóm = biến)
mtelesha

@mtelesha có lẽ vì biến có chuỗi như giá trị của nó
buncis

9

Một tùy chọn khác ( ggplot2 > 3.0.0) là sử dụng đại từ đánh giá gọn gàng .datađể cắt biến / cột đã chọn khỏi rates.by.groupskhung dữ liệu.

library(ggplot2)
theme_set(theme_classic(base_size = 14))

# created by @Moody_Mudskipper
rates.by.groups <- data.frame(
  name = LETTERS[1:3],
  rate = 1:3,
  mjr = LETTERS[c(4, 4, 5)],
  gender = c("M", "F", "F")
)

f1 <- function(df, column) {
  gg <- ggplot(df, 
         aes(x = name, 
             y = rate, 
             fill  = .data[[column]], 
             group = .data[[column]])) +
    geom_col() +
    labs(fill = column)
  return(gg)
}

plot_list <- lapply(list("gender", "mjr"), function(x){ f1(rates.by.groups, x) })
plot_list
#> [[1]]

#> 
#> [[2]]

# combine all plots
library(egg)
ggarrange(plots = plot_list,
          nrow = 2,
          labels = c('A)', 'B)'))

Được tạo vào 2019-04-04 bởi gói reprex (v0.2.1.9000)


0

Sử dụng aes_stringkhông khắc phục được sự cố này, nhưng gặp sự cố khi thêm các thanh lỗi geom_errorbar. Dưới đây là một giải pháp đơn giản.

#Identify your variables using the names of your columns indie your dataset
 xaxis   <- "Independent"   
 yaxis   <- "Dependent"
 sd      <- "error"

#Specify error bar range (in 'a-b' not 'a'-'b')
 range   <- c(yaxis, sd)                                #using c(X, y) allows use of quotation marks inside formula
 yerrbar <- aes_string(ymin=paste(range, collapse='-'), 
                       ymax=paste(range, collapse='+'))


#Build the plot
  ggplot(data=Dataset, aes_string(x=xaxis, y=yaxis)) +
    geom_errorbar(mapping=yerrbar, width=15, colour="#73777a", size = 0.5) +
    geom_point   (shape=21)

Phần thưởng, bạn cũng có thể thêm các khía cạnh vào cốt truyện của mình bằng cách sử dụng các dòng sau bên trong ggplot:

facet_grid(formula(paste(Variable1, "~", Variable2)))

Tập lệnh này đã được sửa đổi từ bài đăng gốc này: ggplot2 - Thanh lỗi sử dụng hàm tùy chỉnh


0

Đây là một ví dụ cực kỳ đơn giản.

Chỉ cần làm hai điều

  1. Biến chuỗi thành một biểu tượng
  2. Thêm !!khi bạn sử dụng nó
select_col <- sym("Petal.Length")

iris %>% 
  ggplot(aes(x = Sepal.Length, y = !!select_col)) +
  geom_point()
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.