Search code examples
rif-statementshinyggvis

User specified fill


I am using ggvis and have the following code with a selectInput on the UI side allowing the user to select which variable dictates fill and shape (inputId is fill and shape respectively). I want the plot to have the ability to have a constant fill or shape should the user choose. The else section of this code works exactly how I want, but when I select the option in the if statement the app crashes with the following error:

Error in eval: could not find function ":="

I know I have the syntax correct because if I suppress the legends and the if/else statement and specify the fill as constant (fill := "black") it works how I want it to.

Any help would be appreciated.

vis <- reactive({
fillvar <- prop("fill", as.symbol(input$fill))
shapevar <- prop("shape", as.symbol(input$shape))
filteredData() %>%
ggvis(x = xvar, y = yvar) %>%
  layer_points(size.hover := 200,
               fillOpacity:= 0.5, fillOpacity.hover := 1,

               # Allows for points to be consistent if the user desires

               if (input$fill == "All Points Black") {
                 fill := "black"}
               else {
                 fill = fillvar}
               ,

               if (input$shape == "All Points Circles") {
                 shape := "circle"}
               else {
                 shape = shapevar}
              ,

               key := ~ID
  ) %>%

  # Adds legends to the Plot in designated locations
  add_legend("fill", title = as.character(fillvar)) %>%
  add_legend("shape", title = as.character(shapevar), properties = legend_props(legend = list(y=300))) %>%

  # Adds the previously defined tool_tip my_tooltip
  add_tooltip(my_tooltip, "hover") %>%

  # Specifies the size of the plot
  set_options(width = 800, height = 400, duration = 0)
})

#Actually plots the data
vis %>% bind_shiny("plot1")

Solution

  • As I mentioned in a comment, you can create a variable for prop using an if statement. This allows you to bypass the issue of := by using either a constant or a variable directly in prop.

    You get legends automatically. To control the placement when you have two legends (which will lead to an overlap), you can name your ggvis graph. This allows you to refer to add elements to the graphic in order to move the second legend down only when it is added based on logic and your shapevar and fillvar values.

    Here's the code just for the reactive function.

    vis <- reactive({
        fillvar = "black"
        if(input$fill != "All Points Black") {
            fillvar = as.name(input$fill)
        }
    
        shapevar = "circle"
        if(input$shape != "All Points Circles") {
            shapevar = as.name(input$shape)
        }
    
        p1 = filteredData() %>%
            ggvis(x = xvar, y = yvar) %>%
            layer_points(size.hover := 200,
                       fillOpacity:= 0.5, fillOpacity.hover := 1,
                       prop("fill", fillvar),
                       prop("shape", shapevar),
                       key := ~ID
            ) %>%
    
            # Adds the previously defined tool_tip my_tooltip
            add_tooltip(my_tooltip, "hover") %>%
    
            # Specifies the size of the plot
            set_options(width = 800, height = 400, duration = 0)
    
    
        # Control addition of second legend using if() on p1 object
        if(fillvar != "black" & shapevar != "circle") {
            p1 %>% add_legend("shape", properties = legend_props(legend = list(y=300)))
        }
        else {
            p1
        }
    
    })