3

I am writing a function that uses plot_ly for a pieplot. The tilde (~) within argument labels = ~ is in conflict with the unquote operator !!. Is there a solution for this problem?

pieplotr <- function (df, Property){

Property_Name <- enquo(Property)

Pie <- plot_ly(df,
              labels = ~!!Property_Name,
              type = "pie")

return(Pie)

}
Toy_dataframe <- data.frame(
                 Sex = c("Male", "Female", "Female", "Male", "Male","NA"),
                 Height = c(12,11,7,3,9,NA),
                 Name = c("John", "Dora", "Dora","Dora", "Anna", "John"),
                 Last = c("Henry", "Paul", "House", "Houze", "Henry", "Bill"),
                 Location = c("Chicago", "Chicago", "Portland", "NYC", "NYC", "NYC"),
                 stringsAsFactors = TRUE)

e.g.

pieplotr(df = Toy_dataframe,
          Property = Name)

I expect to return a pieplot, but I am getting the following error message:

Error in as.list.environment(x, all.names = TRUE) :
object 'Name' not found

ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
Soph Carr
  • 31
  • 5

3 Answers3

2

We can evaluate after creating creating an expression

pieplotr <- function (df, Property){

Property_Name <- rlang::enquo(Property)
rlang::eval_tidy(
    rlang::quo_squash(quo(
    plot_ly(df, labels = ~!!Property_Name,  type = "pie")
    )))


} 




pieplotr(df = Toy_dataframe, Property = Name)

-output

enter image description here


Or remove the ~!!

pieplotr <- function (df, Property){

Property_Name <- rlang::enquo(Property)

    plot_ly(df, labels = Property_Name,  type = "pie")



}

pieplotr(df = Toy_dataframe, Property = Name)
akrun
  • 874,273
  • 37
  • 540
  • 662
  • That worked! Thank you so much. Do you mind walking me through your thought process? I would greatly appreciate it so I can have a much better understanding if the solution. – Soph Carr Nov 07 '19 at 18:30
  • 1
    @SophCarr It is not a straightforward solution as we are `eval`uating an expression created with `quo`, `quo_squash` flattens the expression and on top of which we are evaluating. As I mentioned in the comments, `plotly` is not a tidyverse compatible package. – akrun Nov 07 '19 at 18:33
  • 1
    @SophCarr Noticed that the issue is also with the `~!!` part. Removing it works – akrun Nov 07 '19 at 18:38
  • Don't really need `quo` / `quo_quash`. You can just use `rlang::expr( plot_ly(df, labels = ~!!Property_name, type="pie") )`, which will create the appropriate expression. (@SophCarr: try returning the output of `rlang::expr` from the function to see what it does). The expression is then evaluated using `eval_tidy`. – Artem Sokolov Nov 07 '19 at 18:38
  • @ArtemSokolov Not even that is needed – akrun Nov 07 '19 at 18:38
  • Also, the correct verb here is `ensym()` not `enquo()`, because you are providing the context of the symbol directly to the function as the dataframe. – Artem Sokolov Nov 07 '19 at 18:38
2

An alternative solution is to avoid non-standard-evaluation / quasiquoation entirely and simply modify how you are calling the function

pieplotr <- function (df, Property) {
    plot_ly(df, labels = Property, type = "pie")
}

pieplotr( Toy_dataframe, ~Name )    # Notice the ~

The reason this works here is because the plotly universe uses formulas (defined via ~) to pass around information about variables. Tidyverse uses unevaluated expressions instead of formulas, which is the reason for needing enquo(), etc.

Artem Sokolov
  • 13,196
  • 4
  • 43
  • 74
0

I was trying to find a way to use plot_ly inside a function, but also trying to avoid passing unquoted variable names. Turns out passing quoted column names, parsing, and then evaluating within the plot_ly call works nicely, and, at least for me, its easier to read and understand than some of the other solutions:

ply <- function(data, x, y) {

  name_x <- parse(text = x)
  name_y <- parse(text = y)

  plotly::plot_ly(data = data, x = ~eval(name_x), y = ~eval(name_y)) %>%
    plotly::add_trace(type = "scatter")
}

ply(faithful, "eruptions", "waiting")
teofil
  • 2,344
  • 1
  • 8
  • 17