rstudio / shiny

Easy interactive web applications with R
https://shiny.posit.co/
Other
5.37k stars 1.86k forks source link

jsonlite warning with shiny 1.4.0 #2673

Open stla opened 5 years ago

stla commented 5 years ago

Hello,

Consider this app:

library(shiny)
library(ggplot2)

ui <- fluidPage(
  radioButtons("type", "Type of plot", choices = c("density", "boxplot")),
  plotOutput("plot")
)

server <- function(input, output){
  output[["plot"]] <- renderPlot({
    if(input$type == "density"){
      ggplot(iris, aes(Sepal.Length)) + geom_density()
    }else{
      ggplot(iris, aes(x = "", y = Sepal.Length)) + geom_boxplot()
    }
  })
}

shinyApp(ui, server)

When you select the radio button "boxplot", this message appears in the R console:

Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.

It is caused by x = "" in the aes. If I remove this argument, there's no warning anymore.

This message didn't appear with shiny < 1.4.0.

harrismcgehee commented 4 years ago

Similar experience with any single x axis item:

library(shiny)
library(ggplot2)

ui <- fluidPage(
            tabsetPanel(
                tabPanel("no message", plotOutput("quietPlot")),
                tabPanel("generates `Input to asJSON` message", plotOutput("noisyPlot"))
            )
)

# Define server logic required to draw cols
server <- function(input, output, session) {
    output$quietPlot <- renderPlot({
        ggplot(
            data = data.frame(z = c("a", "b"), n = c(1, 2)),
            aes(x = z, y = n)
        ) + geom_col()
    })
    output$noisyPlot <- renderPlot({
        ggplot(
            data = data.frame(z = c("a"), n = c(1)),
            aes(x = z, y = n)
        ) + geom_col() 
    })
}

shinyApp(ui = ui, server = server)
jntrcs commented 4 years ago

Also receiving this warning whenever x-axis is reduced to single factor.

kaijagahm commented 3 years ago

I am getting this warning message when I use onRestore and onBookmark. When I run the same app without those functions, the warning disappears.

wch commented 3 years ago

@kaijagahm Can you file a new issue, with a minimal reproducible example?

For the others that have experienced this issue, when I run the example apps, I don't see the message. It's possible that it has been fixed since the issue was originally filed. If you still see that message, please provide the output of sessionInfo() or sessioninfo::session_info().

SigurdJanson commented 3 years ago

I am not sure this issue is limited to ggplot. I have the same warning whenver I the value argument is a named vector. The problem is there even in shiny 1.6 (session info below). Once I put unname() around it, it works.

I'd prefer if the update-function would just ignore the names in the vector.

library(shiny)

ui <- fluidPage(
    titlePanel("as JSON Warning Sample"),
    mainPanel(
       sliderInput("inpSlider", "Just another value", 1, 10, 5),
       actionButton("btnReset", "Reset to 1")
    )
)

server <- function(input, output, session) {
    observeEvent(
        input$btnReset, 
        {    # NAMED VECTOR CAUSES THE WARNING
             updateSliderInput(session, "inpSlider", value = c(a = 1)) 
        })
}

shinyApp(ui = ui, server = server)
> sessionInfo()
R version 4.0.3 (2020-10-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19041)

Matrix products: default

locale:
[1] LC_COLLATE=German_Germany.1252  LC_CTYPE=German_Germany.1252   
[3] LC_MONETARY=German_Germany.1252 LC_NUMERIC=C                   
[5] LC_TIME=German_Germany.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] shiny_1.6.0

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.6        withr_2.4.1       digest_0.6.27     later_1.1.0.1    
 [5] mime_0.9          R6_2.5.0          jsonlite_1.7.2    lifecycle_0.2.0  
 [9] xtable_1.8-4      magrittr_2.0.1    cachem_1.0.1      rlang_0.4.10     
[13] promises_1.1.1    jquerylib_0.1.3   bslib_0.2.4       ellipsis_0.3.1   
[17] tools_4.0.3       tinytex_0.29      rsconnect_0.8.16  httpuv_1.5.5     
[21] xfun_0.20         fastmap_1.1.0     compiler_4.0.3    htmltools_0.5.1.1
[25] sass_0.3.0   
wch commented 3 years ago

@SigurdJanson Thanks for that example. This is a difficult (or really, almost impossible) problem to fix in general, because of R's nature as a loosely-typed language.

The root issue is that jsonlite doesn't like named atomic vectors when keep_vec_names=TRUE:

> jsonlite::toJSON(c(a=1), keep_vec_names=TRUE)
Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.
{"a":1} 

In contrast, named lists are fine:

> jsonlite::toJSON(list(a=1), keep_vec_names = TRUE)
{"a":[1]} 

In the examples posted previously, it seems that something in ggplot2 generated data with named atomic vectors. In @SigurdJanson's example, it's the call to updateSliderInput() that tries to send a named vector.

In Shiny, we do some input validation, we don't check every possible input for every possible kind of invalid value. (It's similar to the vast majority of R code in this way.) With a strongly-typed language, many checks just happen automatically; with a loosely-typed language like R, deciding which things to check (and whether to "fix" them for the user) is much more subjective.

lbramley commented 1 year ago

Is there any option for a workaround here? This issue is making it impossible to label graphs other than using a legend. The functions ggrepel::geom_label_repel and ggplot2::geom_label also seem to throw the same error once reactive inputs are used.

library(ggplot2)
library(ggrepel)
library(shiny)

# Define UI 
ui <- fluidPage(

    # Application title
    titlePanel("mtcars plot"),

    # Sidebar with a slider input for minimum displacement
    sidebarLayout(
        sidebarPanel(
            sliderInput("disp",
                        "Minimum Displacement (cu.in.):",
                        min = 70,
                        max = 470,
                        value = 70)
        ),

        # Show the resulting plot
        mainPanel(
           plotOutput("mtcars_plot")
        )
    )
)

# Define server logic required to draw the mtcars plot
server <- function(input, output) {

    output$mtcars_plot <- renderPlot({
        mtcars_disp <- mtcars %>%
            filter(disp >= input$disp)

        p <- ggplot(mtcars_disp,
                    aes(wt, mpg, label = rownames(mtcars), colour = factor(cyl))) +
            geom_point()

        # Labels with background
        p + geom_label() # or geom_label_repel()

    })
}

# Run the application 
shinyApp(ui = ui, server = server)
gadenbuie commented 1 year ago

Hi @lbramley, I just tried your app and can reproduce the error. There's a rather long message that's printed, for me it's the following:

Warning: ggrepel: 2 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: Error in geom_point: Problem while computing aesthetics.
ℹ Error occurred in the 1st layer.
Caused by error in `check_aesthetics()`:
! Aesthetics must be either length 1 or the same as the data (16)
✖ Fix the following mappings: `label`
  198: <Anonymous>
  197: signalCondition
  196: signal_abort
  195: rlang::abort
  194: cli::cli_abort
  193: handlers[[1L]]
  192: <Anonymous>
  191: signalCondition
  190: signal_abort
  189: rlang::abort
  188: cli::cli_abort
  187: check_aesthetics
  186: compute_aesthetics
  185: l$compute_aesthetics
  184: f
  177: by_layer
  176: ggplot_build.ggplot
  174: print.ggplot
  169: func
  167: f
  166: Reduce
  157: do
  156: hybrid_chain
  128: drawPlot
  114: <reactive:plotObj>
   98: drawReactive
   85: renderFunc
   84: output$mtcars_plot
    3: runApp
    2: print.shiny.appobj
    1: <Anonymous>
Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.
Run `rlang::last_trace()` to see where the error occurred.

That second-to-last line about asJSON() is really a misdirection; that's a jsonlite error that happens after other errors occur. In this case the key lines are

Warning: Error in geom_point: Problem while computing aesthetics.
ℹ Error occurred in the 1st layer.
Caused by error in `check_aesthetics()`:
! Aesthetics must be either length 1 or the same as the data (16)
✖ Fix the following mappings: `label`

which occur because you need to use the same data frame for label as is provided to ggplot():

p <- ggplot(mtcars_disp,
-   aes(wt, mpg, label = rownames(mtcars), colour = factor(cyl))) +
+   aes(wt, mpg, label = rownames(mtcars_disp), colour = factor(cyl))) +
    geom_point()
lbramley commented 1 year ago

Thanks @gadenbuie! Really helpful to know that the asJSON() error is a misdirection; my real app is using the same object unlike the test one above, but it must be something in my code then, sorry about that!

jcheng5 commented 1 year ago

@gadenbuie Is the asJSON error happening when attempting to JSON-serialize a fancy rlang error? I have a vague feeling like those fancy errors need to be accounted for in Shiny's catch-error-during-output-render logic.

gadenbuie commented 1 year ago

Is the asJSON error happening when attempting to JSON-serialize a fancy rlang error?

@jcheng5 Maybe? That also feels likely to me too, although it doesn't seem to be going through shiny's internal toJSON() and I'm getting lost in the many error handlers. Do you have any suggestions about where to look for the error-to-JSON serialization?

toxintoxin commented 1 year ago

I also get a warning when renderPlot, but if I activate the shiny from R not radian, everything goes well