Search code examples
rshinyflexdashboard

how to change up arrow (green color) or down arrow (red color) or a dash (black color) in the flexdashboard


I have a the following sample code for flexdashbard in R:

---
title: "My Dashboard"
runtime: shiny
output: 
  flexdashboard::flex_dashboard:
    orientation: rows
    vertical_layout: fill
always_allow_html: yes
---

```{r init, include=FALSE, echo=FALSE}
gc()

```


```{r setup1, include = FALSE}
library(flexdashboard)
library(thematic)
library(ggplot2)
library(bslib)
library(shiny)
library(plotly)
library(tidyverse)
library(dplyr)
library(htmltools)

```


Home {data-icon="fa-home" .main}
=====================================   

```{r, include=FALSE}

theme_set(theme_bw(base_size = 20))

```


Row
-----------------------------------------------------------------------

### Heading 1

```{r}
valueBox(1, icon = "fa-pencil", color="success")
```

### Heading 2

```{r}

valueBox(2, icon = "fa-file-text-o", color="info")

```

### Heading 3

```{r}
valueBox(3, icon = "fa-database", color = "danger")
```

Row
-------------------------------------------



Screen 2 {data-icon="fa-signal"}
==========================================================================

Sidebar {.sidebar data-width=350}
-------------------------------------

<h3>Selection Area</h3>

```{r}

hr(style = "border-top: 1px solid #000000;")

sliderInput("contact_rate", "Set contact rate", value = 91, min = 0, max = 100)

hr()

numericInput(inputId="my_input", "Enter a number:", 4, min = 0)

actionButton("submit", "Submit")


```


Value Boxes 
-------------------------------------

### Primary

```{r}

observeEvent(input$submit, {
  arrow_icon_temp <- ifelse(input$my_input > 3, icon("fa-arrow-up", class = "text-success"), 
                            icon("fa-arrow-down", class = "text-danger"))
  output$arrow <- renderValueBox({
    valueBox(
      input$my_input, caption = "Days", 
      color = "white",
      icon = arrow_icon_temp
    )
  })
})


renderValueBox({
  valueBoxOutput("arrow")
})

```

### Info

```{r}

valueBox(2, caption = "Weeks", color = "red", icon = "fa-chart-line")

```

### Success

```{r}

valueBox(3, caption = "Weeks", color = "green", icon = "fa-chart-line")

```



Gauges 
-------------------------------------

### Success Rate

```{r}

renderGauge({
  gauge(input$contact_rate, min = 0, max = 100, symbol = '%', 
        sectors = gaugeSectors( danger = c(0, 20), warning = c(20, 80), success = c(80, 100)))
  })

```

### Warning metric

```{r}

renderGauge({
  gauge(input$contact_rate, min = 0, max = 100, symbol = '%', 
        sectors = gaugeSectors( danger = c(0, 20), warning = c(20, 80), success = c(80, 100)))
  })

```

### Danger!

```{r}

renderGauge({
  gauge(input$contact_rate, min = 0, max = 100, symbol = '%', 
        sectors = gaugeSectors( danger = c(0, 20), warning = c(20, 80), success = c(80, 100)))
  })


```

and the dashboard looks like that:

enter image description here

I am trying to change up arrow (green color) or down arrow (red color) or a dash (black color) in the frist valueBox reactively, meaning, when i provide a number in the NumericInput (in side bar), and then click on submit button, then ONLY should be the change in valueBox be reflected along with up or down arrow icon (as shown in the picture) basis the condition applied in the above code.

But then I am encountering two issues here:

  1. first time, when i launch the dashboart (run the app), I need to provide the input number and then click on Submit button, then only valueBox shows the number I just had input.
  2. but, second time the moment i change the number, the number is displayed on the valueBoax immediately even without clicking on Submit button, this should not be the case.
  3. arrow (red, down or green, up) is still not getting displayed

What am I doing wrong here? any suggestions please?


Solution

    1. First, to format the style of your icons you need to save this chunk of css in a styles.css file inside your www folder:
         .value-box .icon i.fa.fa-arrow-up{
          position: absolute;
          top: 15px;
          right: 15px;
          font-size: 80px;
          color: rgba(0, 153, 0);
        }
        
        .value-box .icon i.fa.fa-arrow-down{
          position: absolute;
          top: 15px;
          right: 15px;
          font-size: 80px;
          color: rgba(255, 0, 0);
        }
    
    1. Remember to include this file in the yaml:
    ---
    title: "My Dashboard"
    runtime: shiny
    output: 
      flexdashboard::flex_dashboard:
        orientation: rows
        vertical_layout: fill
    always_allow_html: yes
    css: www/styles.css 
    ---
    
    1. You need to break the dependency that your renderValueBox takes on input$my_input, because you need to renderValueBox only when input$submit is clicked. isolate is the function for that: it suspend the reactive actions of the input or reactive object inside and is only evaluated when another input or reactive object linked to it's enviroment is changed. So with some modifications, your chunk is now like this:
    ### Primary
    
    ```{r}
    
    observeEvent(input$submit, {
      
      output$arrow <- renderValueBox({
        
        valueBox(
          ifelse(input$submit == 0, "Select number of days", isolate(input$my_input)), caption = "Days", 
          color = "white",
          icon = ifelse(isolate(input$my_input) > 3, "fa-arrow-up", "fa-arrow-down"))
        
      })
    }, ignoreNULL = FALSE)
    
    
    renderValueBox({
      valueBoxOutput("arrow")
    })
    
    

    EDIT: answering can I also include a text box like "Error: " in between the number displayed and the arrow?

    That would mean to change the value argument in valueBox to a shiny::tagList that includes the needed elements. Those elements need to be in the same row; in different columns. Now your valueBox looks like this:

    valueBox(
          value = tagList(tags$div(class = "parent",
                           tags$div(class = "column", ifelse(input$submit == 0, "Select number of days", isolate(input$my_input))),
                           tags$div(class = "column", tags$h5("Error:")))), 
          caption = "Days", 
          color = "white",
          icon = ifelse(isolate(input$my_input) > 3, "fa-arrow-up", "fa-arrow-down"))
    

    And your styles.css file needs to include this lines:

    .parent {
      display: flex;
      flex-direction:row;
    }
    
    .column {
      flex: 1 1 0px;
    }