jrowen / rhandsontable

A htmlwidgets implementation of Handsontable.js
http://jrowen.github.io/rhandsontable/
Other
380 stars 147 forks source link

hot_to_r coerce logical to integers #400

Open bartekch opened 2 years ago

bartekch commented 2 years ago

In some cases hot_to_r does not convert logical type correctly and returns integer instead. The following example shows different cases. Returned type is incorrect when logical column is paired only with numeric, without character columns (second case). Adding character column seems to help (third case), but no when all values are missing (fourth case). I would say it's pretty surprising behaviour.

shinyApp(
  ui = basicPage(
    tagList(
      h4("Logical"),
      rhandsontable::rHandsontableOutput("t1"),
      verbatimTextOutput("o1"),

      h4("Numeric + logical"),
      rhandsontable::rHandsontableOutput("t2"),
      verbatimTextOutput("o2"),

      h4("Numeric + logical + character"),
      rhandsontable::rHandsontableOutput("t3"),
      verbatimTextOutput("o3"),

      h4("Numeric + logical + NA_character"),
      rhandsontable::rHandsontableOutput("t4"),
      verbatimTextOutput("o4")
    )
  ),

  server = function(input, output, session) {
    output$t1 <- rhandsontable::renderRHandsontable({
      rhandsontable::rhandsontable(
        data.frame(
          logical = FALSE
        )
      )
    })
    output$o1 <- renderPrint({
      str(rhandsontable::hot_to_r(input$t1))
    })

    output$t2 <- rhandsontable::renderRHandsontable({
      rhandsontable::rhandsontable(
        data.frame(
          logical = FALSE,
          numeric = 0
        )
      )
    })
    output$o2 <- renderPrint({
      str(rhandsontable::hot_to_r(input$t2))
    })

    output$t3 <- rhandsontable::renderRHandsontable({
      rhandsontable::rhandsontable(
        data.frame(
          logical = FALSE,
          numeric = 0,
          character = ""
        )
      )
    })
    output$o3 <- renderPrint({
      str(rhandsontable::hot_to_r(input$t3))
    })

    output$t4 <- rhandsontable::renderRHandsontable({
      rhandsontable::rhandsontable(
        data.frame(
          logical = FALSE,
          numeric = 1,
          character = NA_character_
        )
      )
    })
    output$o4 <- renderPrint({
      str(rhandsontable::hot_to_r(input$t4))
    })

  }
)

I think that the problem is with type.convert function used inside colClasess, as it is not working as it is expected here. type.convert(0, as.is = TRUE) returns 0 and not FALSE. The reason that it works when there is some character column is that we pass "FALSE" to type.convert which indeed returns logical value. And of cource type.convert(FALSE, as.is = TRUE) == FALSE.

Why there are different values at all is caused by the fact, that inside toR the whole table is turned into vector and therefore coerced to the same type. In the examples:

> unlist(list(FALSE))
# FALSE                     # logical
> unlist(list(FALSE, 0))
# 0 0                          # numeric
> unlist(list(FALSE, 0, ""))
# "FALSE" "0" ""         # character
> unlist(list(FALSE, 0, NULL))
# 0 0                          # numeric

I think that the problem should be solved by calling as.logical inside colClasses instead of type.convert, I haven't found any issues with such a solution so far. I'd be happy to make pull request.