Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

selectInput: improve factor handling #2524

Merged
merged 12 commits into from Jul 15, 2019
Merged

Conversation

alandipert
Copy link
Contributor

@alandipert alandipert commented Jul 11, 2019

This work was motivated by #2515, which demonstrated that unnamed factors work as expected, but named factors did not.

  1. listify() was restructured in order to make clearer how various types are handled. Support for named factors was added.
  2. selectInput() documentation now mentions factor handling.
  3. Additional unit tests were added to check factor handling, and existing unit tests were improved to exercise handling of complex and logical vectors.

Open Questions

  1. Should selectInput() produce a warning if a factor is used as an option list or otherwise included in the list of options? We decided not to produce a warning.

QA Notes

Given this test application:

library(shiny)

choices <- factor(setNames(letters, LETTERS))
ui <- fluidPage(selectInput("example", "Choose", choices))
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
  • On Shiny 1.3.2 (the latest released version on CRAN), running the test app should produce an error like the following: Error in (function (choice, name) : All sub-lists in "choices" must be named.
  • Install Shiny from Github: devtools::install_github("rstudio/shiny") (this PR has been merged)
  • Run the test app again, you should see no error
  • The test app should display a selectInput that looks and works like the one below

select

@alandipert alandipert changed the title selectInput: handle factor choices, fixes #2515 selectInput: improve factor handling Jul 11, 2019
@alandipert alandipert self-assigned this Jul 11, 2019
@alandipert alandipert marked this pull request as ready for review July 11, 2019 23:02
R/input-utils.R Outdated

#' @export
listify.character <- function(x) {
if (length(x) == 1 && is.null(names(x))) x else as.list(ensureNamed(x))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... else ensureNames(as.list(x)) ?

Is the goal to return a list with every element's name as '' or to return a list with no names?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, return a list with every element's name as '' (unless it's already named)

Copy link
Collaborator

@schloerke schloerke Jul 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's my interpretation of https://github.com/rstudio/shiny/pull/2524/files#diff-c851d180beb8024d6b46a73dab4756d9L113 . makeNamed(as.list(val)) vs as.list(ensureNamed(x))

R/input-utils.R Outdated
# Take a vector or list, and convert to list. Also, if any children are
# vectors with length > 1, convert those to list. If the list is unnamed,
# convert it to a named list with blank names.
listify <- function(x) UseMethod("listify", x)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My gut reaction is this should be rewritten to be a if / else.

  • It wouldn't need to be exported to work.
  • It could handle odd s3 cases better (things that don't have atomic classes).

Setup:

if `is.list`, `is.null`
  "code for `is.list`"
else if `is.numeric`, `is.complex`, `is.logical`, `is.factor`
  "code for `is.numeric`"
else 
  "code for `is.character`"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know, now that it has all the @export noise, I have to agree. I swear, it was looking pretty tight before all that 😄

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the listify generic isn't exported from the package, you don't need to @export every method, and therefore nothing will be added to the NAMESPACE file. That said, I also lean toward having a single function with if-else here.

Copy link
Collaborator

@schloerke schloerke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add {``} due to the nested if/else statement.

(I like them any time there is anything beyond an if. Makes it so things can be executed in the console.)

@schloerke schloerke self-requested a review July 12, 2019 19:20
Copy link
Collaborator

@schloerke schloerke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix travis. otherwise LGTM!

@wch
Copy link
Collaborator

wch commented Jul 12, 2019

One thought -- we should make sure there are tests for lists (and atomic vectors) where the list is named, but some or all of the names are "". For example:

x <- list(A="a", "b", "c")
x
#> $A
#> [1] "a"
#> 
#> [[2]]
#> [1] "b"
#> 
#> [[3]]
#> [1] "c"
attributes(x)
#> $names
#> [1] "A" ""  ""

y <- x[2:3]
y
#> [[1]]
#> [1] "b"
#> 
#> [[2]]
#> [1] "c"
attributes(y)
#> $names
#> [1] "" ""

# Contrast y with:
z <- list("b", "c")
z
#> [[1]]
#> [1] "b"
#> 
#> [[2]]
#> [1] "c"
attributes(z)
#> NULL

@alandipert
Copy link
Contributor Author

@wch there's a test for that case:

choicesWithNames(c(A=Inf+0i, 1+0i, C=0+0i)),

@alandipert alandipert dismissed schloerke’s stale review July 12, 2019 21:15

Confirmed is good on Slack

@schloerke schloerke requested a review from wch July 13, 2019 12:49
Copy link
Collaborator

@wch wch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Just a couple of small nits.

R/input-utils.R Outdated Show resolved Hide resolved
R/input-utils.R Show resolved Hide resolved
@wch wch force-pushed the alan/select-input-handle-factors branch from 15deadc to 65f4974 Compare July 15, 2019 19:15
@wch wch merged commit 1a8b36f into master Jul 15, 2019
@wch wch deleted the alan/select-input-handle-factors branch July 15, 2019 19:51
alandipert added a commit to rstudio/shiny-examples that referenced this pull request Jul 25, 2019
alandipert added a commit to rstudio/shiny-examples that referenced this pull request Jul 25, 2019
alandipert added a commit to rstudio/shiny-examples that referenced this pull request Jul 25, 2019
wch pushed a commit to rstudio/shiny-examples that referenced this pull request Jul 25, 2019
* Use a factor in the selectInput for 002-text, tests rstudio/shiny#2524

* Revert "Use a factor in the selectInput for 002-text, tests rstudio/shiny#2524"

This reverts commit b79f51d.

* Add test app for selecting from a factor, tests rstudio/shiny#2524
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants