hw_grid widget function not working in flexdashboard - shiny

Because of this issue want to put 6 highcharter graphs in one row like do they over here. It seems to work fine outside of flexdashboard
data(diamonds, package = "ggplot2")
diamonds <- diamonds[-6]
map(names(diamonds), function(x){
diamonds[[x]] %>%
hchart(showInLegend = FALSE) %>%
hc_add_theme(hc_theme_smpl()) %>%
hc_title(text = x) %>%
hc_yAxis(title = list(text = ""))
}) %>%
hw_grid(rowheight = 225, ncol = 3) %>% browsable()
please find a simple example here how it's not working within flexdashboard :
---
title: "test"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
---
```{r}
library(highcharter)
library(data.table)
library(ggplot2)
library(htmltools)
```
### trying to render with hw_grid
```{r}
sliderInput('ncol','ncol',min = 1,max=4,value = 2)
```
```{r}
renderHighchart({
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(
x,
x,
x,
x
)
hw_grid(lst, rowheight = 300,ncol = input$ncol) %>% browsable()
})
```
### hw_grid example without rendering
```{r}
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(
x,
x,
x,
x
)
ncol <- 4
# ncol <- input$ncol # need to have a render as this will triger the error: Operation not allowed without an active reactive context....
hw_grid(lst, rowheight = 300,ncol = ncol) %>% browsable()
```
### rendering example
```{r}
renderHighchart({
x <- hchart(data.table(a=c(input$ncol*1:5),b=c(.5 * input$ncol * 1:5)), type='column', hcaes(x=a,y=b))
})
```

Try using renderUI and htmlOutput together like so:
---
title: "test"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
---
```{r}
library(highcharter)
library(data.table)
library(ggplot2)
library(htmltools)
library(purrr)
library(shiny)
```
### trying to render with hw_grid
```{r}
sliderInput('ncol','ncol',min = 1,max=4,value = 2)
```
```{r}
output$chart1 <- renderUI({
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(x,x,x,x)
hw_grid(lst, rowheight = 300,ncol = input$ncol)
})
htmlOutput('chart1')
```
### hw_grid example without rendering
```{r}
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(
x,
x,
x,
x
)
ncol <- 4
# ncol <- input$ncol # need to have a render as this will triger the error: Operation not allowed without an active reactive context....
hw_grid(lst, rowheight = 300,ncol = ncol) %>% browsable()
```
### rendering example
```{r}
renderHighchart({
x <- hchart(data.table(a=c(input$ncol*1:5),b=c(.5 * input$ncol * 1:5)), type='column', hcaes(x=a,y=b))
})
```

Related

using a for loop to generate a series of plots in new powerpoint slides using quarto

I am creating a quarto powerpoint presentation and want to use a dataset to iterate over all the classes in a variable and do a plot for each class on a new slide. However, my plot doesn't seem to show up
---
title: "test_quarto_presentation"
format: pptx
editor: visual
---
## Quarto
Trying to iterate over each species and print the distributions on slides
```{r}
library(tidyverse)
```
```{r, results='asis'}
for (species in unique(iris$Species)){
cat(paste0('## ', species))
print("test")
print(iris %>%
filter(Species == "virginica") %>%
ggplot(aes(x = Petal.Length)) +
geom_histogram())}
```
Here is an option by producing the plots beforehand using purrr based on this discussion:
---
title: "test_quarto_presentation"
format: pptx
---
```{r, include=FALSE}
library(tidyverse)
spec_name <- unique(iris$Species)
make_hist <- function(spec) {
iris |>
filter(Species == spec) |>
ggplot(aes(x = Petal.Length)) +
geom_histogram()
}
list_hist <- map(spec_name, make_hist)
df <- tibble(spec = spec_name, plots = list_hist)
```
```{r}
#| output: asis
res <- pmap_chr(df, \(spec, plots) {
knitr::knit_child(text = c(
"## `r spec`",
"```{r}",
"#| echo: false",
"plots",
"```",
""), envir = environment(), quiet = TRUE)
})
cat(res, sep = '\n')
```
Output:

Dynamic Plots Based on One or More Dropdown Values 2

This question is related to one I asked here: Dynamic Plots Based on One or More Dropdown Values. Although I got an answer from Mr.Rlover, the resulting plots do not look the same. If I choose two or more plots, it seems that the data is being added on and this is reflected exactly in the plots. I wonder how one would separate data based on different species.
one species selected
two or more species selected
Below was my original question:
I am trying to make multiple dynamic plots (one does not know how many plots will output) based on one or more selected dropdown value(s) (species in this case).
I did succeed making plots based on the dropdown. For instance, two plots are displayed if a user selected two values/species from the dropdown list, one plot is displayed if one value/species is selected.
Although the number of plots match the number of dropdown values, the plots show a duplicate if two or more dropdown values/species are selected (it only works if exactly one value is selected). Any advice would be of great help.
The below code uses the iris dataset in R.
library(shiny)
library(shinyWidgets)
library(ggplot2)
library(tidyverse)
library(shinydashboard)
species = c("setosa", "versicolor", "virginica")
ui <- dashboardPage(
dashboardHeader(title = "title"),
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("General Overview", tabName = "tab1", icon = icon("dashboard"))
)
),
body <- dashboardBody(
tabItems(
tabItem(
tabName = "tab1",
uiOutput("species_dropdown"),
# DT::dataTableOutput("table1"),
uiOutput("plots")
)
)
)
)
server <- function(input, output) {
output$species_dropdown <- renderUI({
pickerInput(
"var1",
"Species:",
choices = species,
options = pickerOptions(
actionsBox = T,
header = "Close",
liveSearch = T
),
multiple = T
)
})
filtered_data <- reactive({
iris %>%
filter(Species %in% input$var1) # I think is causing the problem
})
output$table1 <- DT::renderDataTable({
req(input$var1)
filtered_data()
})
# Insert the right number of plot output objects into the web page
output$plots <- renderUI({
req(input$var1)
plot_output_list <- lapply(1:length(input$var1), function(i) {
plotname <- paste("plot", i, sep="")
plotOutput(plotname, height = 280, width = 250)
})
do.call(tagList, plot_output_list)
})
for (i in 1:length(species)) {
local({
my_i <- i #crucial
plotname <- paste("plot", my_i, sep="") # use my_i instead of i
output[[plotname]] <- renderPlot({
ggplot(filtered_data(), aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
labs(title = paste(input$var1[my_i], sep = ""), x = "Sepal Length", y = "Sepal Width") # title needs input$var1 indexed as paste will return a list otherwise, in which case only a first element gets used for the title hence all titles are identical
})
})
}
}
shinyApp(ui, server)
By doing iris %>% filter(Species %in% input$var1) only one dataset was generated. We need one per number of Species.
Instead we create a list with each corresponding plot:
filtered_data <- reactive({
map(input$var1, ~
iris %>%
filter(Species == .x))
})
and subset it with filtered_data()[[index]]
Full app
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(tidyverse)
species <- c("setosa", "versicolor", "virginica")
ui <- dashboardPage(
dashboardHeader(title = "title"),
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("General Overview", tabName = "tab1", icon = icon("dashboard"))
)
),
body <- dashboardBody(
tabItems(
tabItem(
tabName = "tab1",
uiOutput("species_dropdown"),
uiOutput("plots")
)
)
)
)
server <- function(input, output) {
output$species_dropdown <- renderUI({
pickerInput(
"var1",
"Species:",
choices = species,
options = pickerOptions(
actionsBox = T,
header = "Close",
liveSearch = T
),
multiple = T
)
})
filtered_data <- reactive({
map(input$var1, ~
iris %>%
filter(Species == .x)) %>%
set_names(input$var1)
})
#Insert the right number of plot output objects into the web page
output$plots <- renderUI({
req(input$var1)
plot_output_list <- lapply(input$var1, function(i) {
plotname <- paste("plot_", i, sep = "")
plotOutput(plotname, height = 280, width = 250)
})
do.call(tagList, plot_output_list)
})
observeEvent(filtered_data(), {
iwalk(filtered_data(), ~{
output[[paste0("plot_",.y)]] <<- renderPlot({
ggplot(.x, aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
labs(title = .y, x = "Sepal Length", y = "Sepal Width")
})
})
})
}
shinyApp(ui, server)
Using iris %>% filter(Species %in% input$var1[my_i]) directly inside local({}) was the key instead of using:
filtered_data <- reactive({
iris %>%
filter(Species %in% input$var1)
})
for (i in 1:length(species)) {
local({
my_i <- i
plotname <- paste("plot", my_i, sep="")
output[[plotname]] <- renderPlot({
ggplot(iris %>% filter(Species %in% input$var1[my_i]), aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
labs(title = paste(input$var1[my_i], sep = ""), x = "Sepal Length", y = "Sepal Width")
})
})
}

Any chance using input$radio button as argument in group_by

I have tried to use radio button as an argument in group_by. Since I'm new to Shiny with no JS script background so quite being blind in render/output. and how to adapt with normal R-code.
Please show me some useful document/example in applying input to normal R-code
(not as simple as what's shown in shiny- widget gallery)
dat <- read_csv("VN_MAT as of 202001.csv")
datasetInput <- reactive({
switch(input$radio3,
"A" = "PROD_MANUFACTURER, PROD_BRAND, MKT_SDESC",
"B" = "PROD_MANUFACTURER, PROD_LDESC, MKT_SDESC" )
})
dat_brand <- reactive({
dat %>%
data.frame() %>%
group_by(datasetInput()) %>%
summarise(PER_MAT.TY = round(sum(PER_MAT.TY),digit = 2), PER_MAT.YA = round(sum(PER_MAT.YA), digit
=2)) %>%
arrange(MKT_SDESC) %>%
data.frame() %>%
add_count(MKT_SDESC, wt = PER_MAT.TY) %>%
mutate("VALUE_SHARE_TY" = round(PER_MAT.TY/n, digit = 4)) %>%
select(-n) %>%
add_count(MKT_SDESC, wt = PER_MAT.YA) %>%
mutate("VALUE_SHARE_LY" = round(PER_MAT.YA/n, digit = 4)) %>%
select(-n) %>%
mutate("DIFF_SHARE_YA" = round(VALUE_SHARE_TY - VALUE_SHARE_LY, digit = 4)) %>%
mutate("VALUE_GROWTH" = round(PER_MAT.TY/PER_MAT.YA - 1, digit =4))
})
After trial & error, I can figure out the answer as following code
I have overcome it with using if + choice of code
server <- function(input, output, session){
library(shiny)
library(ggplot2)
library(tidyverse)
Principal <- c("a","a","a","a","b","b","b","b","c","c")
Value <- as.numeric(c(4,1,1,3,4,2,2,3,2,1))
g <- c("t1","t1","t1","t1","t1","t2","t2","t2","t2","t2")
b <- as.numeric(c(4,1,1,3,4,2,2,3,2,1))
df <- data.frame(Principal,Value,g,b)
output$plot <- renderPlot({
if(input$radio1 == 1){
df%>%
group_by(g,b) %>%
summarize(total = sum(Value)) %>%
ggplot(aes(x = total, y = b))+
geom_point()
}else{
df%>%
group_by(Principal,b) %>%
summarize(total = sum(Value)) %>%
ggplot(aes(x = total, y = b))+
geom_point()}
})
}
ui <- basicPage(
radioButtons(
inputId = "radio1",
label = "Radio1",
choices = c(1, 2)
),
plotOutput("plot")
)
shinyApp(ui = ui, server = server)

How do you filter a data frame in a shiny document and display a datatable?

I'm trying to filter a data frame and then do some simple ggplots off of the data. I've tried to leverage the R studio example on Shiny documents along with the following SO post on the subject:
Reactively filtering/subsetting a data frame in shiny
Here is my code.
---
title: "Shiny Filter Test"
author: "Novice"
date: "12/13/2019"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r}
library(tidyverse)
library(shiny)
inputPanel(
selectInput("n_break", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 10)
)
cdat <- reactive({
data <- tibble(x = c(10,20,35), y = c("a","b","c"))
data %>%
filter(x %in% input$n_break)
output$table <- DT::renderDT({
cdat()
}, options = list(scrollX = TRUE))
})
```
Can anyone point out where I'm going wrong? When I run the code I get my dropdown box, but that is all. No errors. Just no filtered datatable.
Thanks.
The closing brackets of your reactive are at the wrong place. They should close once you have filtered the data.
---
title: "Shiny Filter Test"
author: "Novice"
date: "12/13/2019"
output: html_document
runtime: shiny
---
```{r setup}
knitr::opts_chunk$set(
echo = FALSE
)
```
```{r}
library(tidyverse)
library(shiny)
inputPanel(
selectInput("n_break", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 10)
)
cdat <- reactive({
data <- tibble(x = c(10,20,35), y = c("a","b","c"))
data %>% filter(x %in% input$n_break)
})
DT::renderDT({
cdat()
}, options = list(scrollX = is ))
```
A remark on the reactive: if you plan to extend this futher, such that the filtered data is used elsewhere, it makes sense to do the filtering in a reactive function. However, if this is not the case I would just do the filtering inside the renderDT:
---
title: "Shiny Filter Test"
author: "Novice"
date: "12/13/2019"
output: html_document
runtime: shiny
---
```{r setup}
knitr::opts_chunk$set(
echo = FALSE
)
```
```{r}
library(tidyverse)
library(shiny)
data <- tibble(x = c(10,20,35), y = c("a","b","c"))
inputPanel(
selectInput("n_break", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 10)
)
DT::renderDT({
data %>% filter(x %in% input$n_break)
}, options = list(scrollX = TRUE))
```

Knitr and/or Kableextra: Global Table Options?

Is it possible to instruct Rmarkdown to default all tables to my styled output? Here is my attempt:
---
title: 'Test Kable Global Styling'
output:
html_document:
df_print: kable
---
```{r}
library(knitr)
library(kableExtra)
kable <- function(data) {
message("YES, IT BITES! (not sortable, but styled.)\n")
knitr::kable(data, digits=3) %>% kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
}
```
## Testing
```{r}
d <- data.frame( x=1:3, y=rnorm(3) )
```
### Explicit Invokation
```{r}
kable(d)
```
### Implicit Invokation Fails
```{r}
d
```
The output looks like this:
[possibly related to How to set knitr::kable() global options in markdown for reuse, but defining my own kable function is not enough for Rmarkdown to select it.
thanks, mystery user for the complete solved update to the above problem. alas, could it generalize to :
```{r}
library(knitr)
library(DT); p <- function(...) DT::datatable(...)
knit_print.data.frame <- function(x, ...) asis_output( paste( c("",p(x)) , collapse="\n" ) )
registerS3method("knit_print", "data.frame", knit_print.data.frame)
```
# Test Code
```{r}
d <- data.frame( x=1:3, y=rnorm(3) )
```
## Print
```{r}
p(d)
d
```
done
As you saw, How to set knitr::kable() global options in markdown for reuse describes how to do this with an explicit call to kable, but doesn't handle implicit displays. The way to do that is described in the ?knitr::knit_print help page. You need code like this early in your document:
kable <- function(data, ...) {
message("YES, IT BITES! (not sortable, but styled.)\n")
knitr::kable(data, digits=3, ...) %>% kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
}
knit_print.data.frame <- function(x, ...) {
res <- paste(c("", "", kable(x)), collapse = "\n")
asis_output(res)
}
registerS3method("knit_print", "data.frame", knit_print.data.frame)