Error in eval(substitute(expr), envir, enclos) in Shiny R - r

I'm receiving the following error when trying to run a Shiny App I'm building. The error is:
Listening on http://........
Error in eval(substitute(expr), envir, enclos) :
incorrect length (0), expecting: 202
I've been modeling the base of my app after the movie-explorer example App. The data is fed in via CSV and is a 202 lines long dataframe.
UPDATE
After running through debugger I've found that the actual expression that causes the error is found within the %>% function. The error occurs after the following two lines of code are executed:
env[["_lhs"]] <- eval(lhs, parent, parent)
result <- withVisible(eval(quote(`_fseq`(`_lhs`)), env, env))
At this point in the code the variable values are:
lhs = companies
parent = Environment
env = Environment
Obviously, the code is expecting my dataframe but is receiving an empty set. Reason is unknown.
END UPDATE
SPECIFIC QUESTION: What am I doing wrong and how do I fix it?
my server.R file looks like:
library(shiny)
library(dplyr)
library(ggvis)
all_dat = read.csv("data/company_data.csv")
shinyServer(function(input, output, session) {
companies <- reactive({
# Filter the clicks, views, opens
clicks <- input$Clicks
pageviews <- input$Pageviews
opens <- input$Opens
engage_value <- input$Engage_Value
viewspermsg <- input$views_per_msg
clickspermsg <- input$clicks_per_msg
openspermsg <- input$opens_per_msg
# Apply Filters
d <- all_dat %>%
filter(
Clicks >= clicks,
Pageviews >= pageviews,
Opens >= opens,
Engage_Value >= engage_value,
views_per_msg >= viewspermsg,
clicks_per_msg >= clickspermsg,
opens_per_msg >= openspermsg
) %>%
arrange(Clicks)
# Optional: filter by Dive
if (input$Dive != "All") {
size <- paste0("%", input$Dive, "%")
d <- d %>% filter(Dive %like% dive)
}
# Optional: filter by Dive Family
if (input$Family != "All") {
family <- paste0("%", input$Family, "%")
d <- d %>% filter(Family %like% family)
}
# Optional: filter by Industry
if (input$Industry != "All") {
industry <- paste0("%", input$Industry, "%")
d <- d %>% filter(Industry %like% industry)
}
# Optional: filter by Dive Family
if (input$Size != "All") {
size <- paste0("%", input$Size, "%")
d <- d %>% filter(Size %like% size)
}
d <- as.data.frame(d)
d$Has_International <- character(nrow(d))
d$Has_International[d$Oscars == 0] <- "No"
d$Has_International[d$Oscars >= 1] <- "Yes"
#I don't know if I need this.
d
})
company_tooltip <- function(x) {
if (is.null(x)) return(NULL)
if (is.null(x$Unnamed..0)) return(NULL)
all_dat <- isolate(companies())
company <- all_dat[all_dat$Unnamed..0 == x$Unnamed..0, ]
paste0("<b>", company$Company, "</b><br>",
company$Industry, "<br>",
company$Size, " employees", "<br>",
company$Company_Type, "<br>",
round(company$Percent_New, digits=2), " % New Readers"
)
}
#reactive labels and graph aspects
vis <- reactive({
# Labels for axes
xvar_name <- names(axis_vars)[axis_vars == input$xvar]
yvar_name <- names(axis_vars)[axis_vars == input$yvar]
# Normally we could do something like props(x = ~BoxOffice, y = ~Reviews),
# but since the inputs are strings, we need to do a little more work.
xvar <- prop("x", as.symbol(input$xvar))
yvar <- prop("y", as.symbol(input$yvar))
companies %>%
ggvis(x = xvar, y = yvar) %>%
layer_points(size := 50, size.hover := 200,
fillOpacity := 0.2, fillOpacity.hover := 0.5,
stroke = ~Has_International, key := ~Unnamed..0) %>%
add_tooltip(company_tooltip, "hover") %>%
add_axis("x", title = xvar_name) %>%
add_axis("y", title = yvar_name) %>%
add_legend("stroke", title = "International Presence", values = c("Yes", "No")) %>%
scale_nominal("stroke", domain = c("Yes", "No"),
range = c("orange", "#aaa")) %>%
set_options(width = 500, height = 500)
})
vis %>% bind_shiny("plot1")
})

Solution: In the code where filters are setup, reference all lowercase variable names (input$dive), not the uppercase variable name as it originally appears in the initial data frame (input$Dive). So change input$Dive to input$dive.
The wrong way
# Optional: filter by Dive
if (input$Dive != "All") {
size <- paste0("%", input$Dive, "%")
d <- d %>% filter(Dive %like% dive)
}
The right way.
# Optional: filter by Dive
if (input$dive != "All") {
size <- paste0("%", input$dive, "%")
d <- d %>% filter(Dive %like% dive)
}

Related

ddply stops with warning Error in str2lang(x) : <text>:2:0: unexpected end of input

Question
I have the following code of ddply where the inside function works well with a single element i in modelNames. However, when I run the entire code in ddply, it gives me error:
Error in str2lang(x) : <text>:2:0: unexpected end of input
1: ~
^
Do you have any idea what part of code may cause the issue?
Current Code
t <-
modelNames %>%
ddply('model', function(i){
print(i)
colnames <- names(d)
dep <-
models %>%
chain.filter('dep') %>%
filter(model == i) %>%
filter(dep == 1) %>%
.$variable
indep <-
models %>%
chain.filter('dep') %>%
filter(model == i) %>%
filter(indep == 1) %>%
.$variable
base <-
Reduce(intersect, list(indep, colnames))
interaction <-
expand.grid(base, base) %>%
mutate(
interaction = paste0(Var1, '*', Var2)
) %>%
.$interaction
interaction <-
Reduce(intersect, list(indep, interaction))
indep <-
c(base, interaction)
eq <-
paste(indep, collapse = ' + ') %>%
paste(dep, ., sep = ' ~ ') %>%
as.formula
s <-
lm(eq, d) %>%
summary(.) %>%
.$coefficient %>%
as.data.frame
r <-
lm(eq, d) %>%
summary(.) %>%
.$r.squared
n <- nobs(lm(eq, d))
t <- data.frame(
model = i,
variable = rownames(s),
estimate = s[, 1],
se = s[, 2],
group = 'Estimates'
) %>%
chain_stars(asterisk = c('', '', '\\textsuperscript{*}', '\\textsuperscript{**}')) %>%
rows_insert(tibble(variable = 'rsqr', estimate = as.character(easy.round4(r)), se = NA, group = 'Overall')) %>%
rows_insert(tibble(variable = 'obs', estimate = as.character(prettyNum(n, big.mark = ",", scientific = F)), se = NA, group = 'Overall')) %>%
gather(state, value, -c(group, variable))
t
}, .progress = 'text')

Unexpected outcome in text analysis using R with gutenbergr and cv.glmnet

hope that all of you are fine,
I'm trying to replicate a text analysis exercise ir R with the gutembergr library, and trying to run a machine learning model with the glmnet library.
The problem is that the code actually runs, but it returns the wrong outcome.
I leave the full code, which is not very extensive and is fully replicable.
First part of the code, runs fine
##### Carga de librerias sajtas #####
library(tidyverse)
library(tidytext)
library(udpipe)
library(gutenbergr)
library(rsample)
library(glmnet)
library(yardstick)
##### 1. Cargar los libros del gutenberg ####
twist_tale <- gutenberg_metadata %>%
filter(
title %in% c("A Tale of Two Cities", "Oliver Twist"),
has_text,
language == "en") %>%
pull(gutenberg_id) %>%
gutenberg_download(meta_fields = "title")
##### 2. Quitarle los blancos #####
twist_tale <- twist_tale %>%
filter(text != "")
View(twist_tale)
##### 3. Crear la varialbe lógica ######
twist_tale <- twist_tale %>%
mutate(
es_two_cities = case_when(
title == "A Tale of Two Cities" ~ 1L,
title == "Oliver Twist" ~ 0L
),
line_id = row_number()
)%>%
view()
##### 3.1. Guardar los resultados y contar las filas ####
twist_tale %>%
count(title)
##### 4. Preparar el dataset y modelar #####
dl <- udpipe_download_model(language = "english")
english_model <- udpipe_load_model(dl$file_model)
text <- twist_tale %>%
select(doc_id = line_id, text)
twist_tale_preprocesado <- udpipe(text, english_model, parallel.cores = 4L)
##### 4b. crear un algoritmo de entrenamiento #####
set.seed(1234L)
twist_tale_split <- initial_split(twist_tale)
twist_tale_training <- training(twist_tale_split)
twist_tale_testing <- testing(twist_tale_split)
##### 4a. Ponerlo en minúsculas y quitarle la mugre ####
sparse_train_data <- twist_tale_preprocesado %>%
mutate(lemma = str_to_lower(lemma)) %>%
anti_join(stop_words, by = c("lemma" = "word")) %>%
filter(upos %in% c("PUNCT", "SYM", "X", "NUM")) %>%
mutate(doc_id = as.integer(doc_id)) %>%
anti_join(twist_tale_testing, by = c("doc_id" = "line_id")) %>%
count(doc_id, lemma) %>%
cast_sparse(doc_id, lemma, n)
Until here, everything is fine. The problem arises running the cv.glmnet() model, since it doesn't return any error or warning message, but the outcome is a row vector, and I believe that it must be a matrix or tibble.
# The code that presents the problem
##### 5a. Excluir los resultados irrelevantes y guardarlos ####
y <- twist_tale_training %>%
filter(line_id %in% rownames(sparse_train_data)) %>%
pull(es_two_cities)
##### 6a. Calcular la regresión logística regularizada ####
model <- cv.glmnet(sparse_train_data, y, family = "binomial",
keep = T, trace.it=1) # THE PROBLEM IS ACTUALLY HERE
coeficientes <- model$glmnet.fit %>%
tidy() %>%
filter(lambda == model$lambda.1se)
coeficientes %>%
group_by(estimate > 0) %>%
slice_max(estimate, n = 5) %>%
ungroup()
coeficientes %>%
group_by(estimate > 0) %>%
slice_max(estimate, n = 5) %>%
ungroup() %>%
ggplot() +
geom_col(aes(x = fct_reorder(term, estimate), y = estimate, fill = estimate > 0)) +
coord_flip()
I Apologize for the extent of the question but was for showing the full context.
Haven't run your code but probably you need to make sure the x matrix and y response vector are in the same order. Something alongside the following will do that (replacing step 5a. and the beginning of your step 6)
library(udpipe)
y <- setNames(twist_tale_training$es_two_cities, twist_tale_training$line_id)
traindata <- dtm_align(x = sparse_train_data, y = y)
model <- cv.glmnet(x = traindata$x, y = traindata$y, family = "binomial", keep = T, trace.it = 1)

Reactive Function

Prior to start creating my app with Shiny I've created a function (NextWordPrediction) that updates my dataframe based on an user's input as follows:
If input exists in df increase its Frequency by 1
If input does't exist in df add it
Function code:
NextWordPrediction <- function(input) {
dat <- dat %>%
filter(., N_gram == str_count(input, "\\S+") + 1) %>%
filter(grepl(paste("^", tolower(str_squish(input)), sep = ""), Word)) %>%
arrange(., desc(Prop))
if (nrow(dat) != 0) {
assign("dat",
dat %>%
mutate(Frequency = ifelse(Word == input &
N_gram == str_count(input, "\\S+"),
Frequency + 1,
Frequency)) %>%
group_by(., N_gram) %>%
mutate(., Prop = Frequency/ sum(Frequency)) %>%
data.frame(.),
envir = .GlobalEnv)
val <- dat$Word_to_Predict[1]
ans <- paste(str_squish(input), val)
return(list(ans, head(dat,5)))
} else if (nrow(dat) == 0 & word(input, 1) != "NA") {
assign("dat",
dat %>%
add_row(., Word = tolower(input), Frequency = + 1, N_gram = str_count(input, "\\S+"),
Word_to_Predict = word(input, -1)) %>%
group_by(., N_gram) %>%
mutate(., Prop = Frequency/ sum(Frequency)) %>%
data.frame(.),
envir = .GlobalEnv)
input_1 <- Reduce(paste, word(input, 2:str_count(input,"\\S+")))
return(NextWordPrediction(input_1))
} else if (word(input, 1) == "NA") {
ans <- paste("Word not in dictionary. We added this to our database!")
return(ans)
}
}
As a next step I want to extend this functionality to a Shiny app and I've tried the following without success. The function usability is functional but after an input my df is not updated accordingly.
server.R
library(shiny)
dat <- read.csv("dat_all.csv")
shinyServer(function(input, output) {
NextWordPrediction <- function(input) {
dat <- dat %>%
filter(., N_gram == str_count(input, "\\S+") + 1) %>%
filter(grepl(paste("^", tolower(str_squish(input)), sep = ""), Word)) %>%
arrange(., desc(Prop))
if (nrow(dat) != 0) {
assign("dat",
dat %>%
mutate(Frequency = ifelse(Word == input &
N_gram == str_count(input, "\\S+"),
Frequency + 1,
Frequency)) %>%
group_by(., N_gram) %>%
mutate(., Prop = Frequency/ sum(Frequency)) %>%
data.frame(.),
envir = .GlobalEnv)
val <- dat$Word_to_Predict[1]
ans <- paste(str_squish(input), val)
return(list(ans, head(dat,5)))
} else if (nrow(dat) == 0 & word(input, 1) != "NA") {
assign("dat",
dat %>%
add_row(., Word = tolower(input), Frequency = + 1, N_gram = str_count(input, "\\S+"),
Word_to_Predict = word(input, -1)) %>%
group_by(., N_gram) %>%
mutate(., Prop = Frequency/ sum(Frequency)) %>%
data.frame(.),
envir = .GlobalEnv)
input_1 <- Reduce(paste, word(input, 2:str_count(input,"\\S+")))
return(NextWordPrediction(input_1))
} else if (word(input, 1) == "NA") {
ans <- paste("Word not in dictionary. We added this to our database!")
return(ans)
}
}
output$predictiontext = reactive({
NextWordPrediction(input$text)[1]
})
output$predictiontable = renderTable({
NextWordPrediction(input$text)[2]
})
})
ui.R
library(shiny)
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
titlePanel("NextWordPrediction"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
textInput("text",
"Type something...",
"")
),
# Show a plot of the generated distribution
mainPanel(
wellPanel(
# Link to report
helpText(a('More information on the app',
href=link,
target = '_blank')
),
# Link to repo
helpText(a('Code repository',
href=link,
target = '_blank')
),
textOutput("predictiontext"),
tableOutput('predictiontable')
)
)
))
)
Update 1: Data
df<- data.frame(Word = c("hello", "she was great", "this is", "long time ago in"), Frequency = c(4, 3, 10, 1),
N_gram = c(1, 3, 2, 4), Prop = c(4/18, 3/18, 10/18, 1/18), Word_to_Predict = c(NA, "great", "is", "in"))
NextWordPrediction("she was") ## returns "she was" & "great"
NextWordPrediction("hours ago") ## returns "hours ago" & "in"
NextWordPrediction("words not in data") ## returns "Word not in dictionary. We added this to our database!" after trying "not in data", "in data" and adds "words not in data" to dataset

Deploying arrange(desc(.)) on each variable passed previously via enquos

Background
Using rlang I've a simple summary function for dplyr that counts a number of missing observations within a variable per provided groups. I would like to return the results in a descending order of grouping variables.
Sample data
library("tidyverse")
set.seed(123)
test_data <- tibble(dates = seq.Date(
from = as.Date.character(x = "01-01-2000", format = "%d-%m-%Y"),
to = as.Date.character(x = "31-12-2010", format = "%d-%m-%Y"),
by = "day"
)) %>%
transmute(
t_year = lubridate::year(dates),
t_mnth = lubridate::month(dates),
t_day = lubridate::day(dates),
tst_var = if_else(rnorm(n()) > .8, NA_real_, rnorm(n()))
)
Summary function
Working version
quick_smry <- function(df, x, ...) {
group_by_vars <- enquos(...)
check_var <- enquo(x)
df %>%
group_by(!!!group_by_vars) %>%
summarise(num_missing = sum(is.na(!!check_var)))
}
Desired results
test_data %>%
group_by(t_year, t_mnth) %>%
summarise(num_missing = sum(is.na(tst_var))) %>%
arrange(desc(t_year), desc(t_mnth))
Problem
Implementing arrange(desc(x)) call so it can handle each of the variables passed initially via enquos. I.e. if there are 5 grouping variables passed via in enquos this should be equivalent of arrange(desc(var1)) .... arrange(desc(var5)).
Attempt
Naturally, this doesn't work:
quick_smry <- function(df, x, ...) {
group_by_vars <- enquos(...)
check_var <- enquo(x)
df %>%
group_by(!!!group_by_vars) %>%
summarise(num_missing = sum(is.na(!!check_var))) %>%
# Desc call should be created for each of the group variables
arrange(desc(!!!group_by_vars))
}
You can use arrange_at like this:
quick_smry <- function(df, x, ...) {
group_by_vars <- enquos(...)
check_var <- enquo(x)
df %>%
group_by(!!!group_by_vars) %>%
summarise(num_missing = sum(is.na(!!check_var))) %>%
arrange_at(group_by_vars, desc)
}
quick_smry(test_data, tst_var, t_year, t_mnth)

R Highcharter: Dynamic multi level drilldown in Shiny

I am trying to create a multi-layer drilldown graph using highcharter with dynamic data in shiny. I am able to accomplish this using just R code with a set input but when I put it in a shiny application and try to have it subset the data dynamically, it fails.
Below is the code that that works in R (only drilling down from Farm to Sheep):
library(shinyjs)
library(tidyr)
library(data.table)
library(highcharter)
library(dplyr)
x <- c("Farm","Farm","Farm","City","City","City","Ocean","Ocean")
y <- c("Sheep","Sheep","Cow","Car","Bus","Bus","Boat","Boat")
z <- c("Bill","Tracy","Sandy","Bob","Carl","Newt","Fig","Tony")
a <- c(1,1,1,1,1,1,1,1)
dat <- data.frame(x,y,z,a)
input <- "Farm"
input2 <- "Sheep"
#First Tier
datSum <- dat %>%
group_by(x) %>%
summarize(Quantity = sum(a)
)
datSum <- arrange(datSum,desc(Quantity))
Lvl1dfStatus <- tibble(name = datSum$x, y = datSum$Quantity, drilldown = tolower(name))
#Second Tier
datSum2 <- dat[dat$x == input,]
datSum2 <- datSum2 %>%
group_by(y) %>%
summarize(Quantity = sum(a)
)
datSum2 <- arrange(datSum2,desc(Quantity))
Lvl2dfStatus <- tibble(name = datSum2$y,y = datSum2$Quantity, drilldown = tolower(name))
#Third Tier
datSum2 <- dat[dat$x == input,]
datSum3 <- datSum2[datSum2$y == input2,]
datSum3 <- datSum3 %>%
group_by(z) %>%
summarize(Quantity = sum(a)
)
datSum3 <- arrange(datSum3,desc(Quantity))
Lvl3dfStatus <- tibble(name = datSum3$z,y = datSum3$Quantity)
#Graph
ClickedTest <- JS("function(event) {Shiny.onInputChange('ClickedInput', event.point.name);}")
highchart() %>%
hc_xAxis(type = "category") %>%
hc_add_series(Lvl1dfStatus, "column", hcaes(x = name, y = y), color = "#E4551F") %>%
hc_plotOptions(column = list(stacking = "normal",
events = list(click = ClickedTest))) %>%
hc_drilldown(
allowPointDrilldown = TRUE,
series = list(
list(id = tolower(input), type = "column", data = list_parse(Lvl2dfStatus)),
list(id = tolower(input2), type = "column", data = list_parse2(Lvl3dfStatus))
)
)
Below is the code that fails in Shiny when changing input to dynamic:
library (shinyjs)
library (tidyr)
library (data.table)
library (highcharter)
library (dplyr)
library (shinydashboard)
library (shiny)
x <- c("Farm","Farm","Farm","City","City","City","Ocean","Ocean")
y <- c("Sheep","Sheep","Cow","Car","Bus","Bus","Boat","Boat")
z <- c("Bill","Tracy","Sandy","Bob","Carl","Newt","Fig","Tony")
a <- c(1,1,1,1,1,1,1,1)
dat <- data.frame(x,y,z,a)
# input <- "Farm"
# input2 <- "Sheep"
header <- dashboardHeader()
body <- dashboardBody(
highchartOutput("Test"),
verbatimTextOutput("trial")
)
sidebar <- dashboardSidebar()
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output, session) {
Lvl1ClickHardCoded <- ""
output$Test <- renderHighchart({
#First Tier
datSum <- dat %>%
group_by(x) %>%
summarize(Quantity = sum(a)
)
datSum <- arrange(datSum,desc(Quantity))
Lvl1dfStatus <- tibble(name = datSum$x, y = datSum$Quantity, drilldown = tolower(name))
#Second Tier
rowcheck <- dat[dat$x == input$ClickedInput,]
if (nrow(rowcheck)!=0){
datSum2 <- dat[dat$x == input$ClickedInput,]
datSum2 <- datSum2 %>%
group_by(y) %>%
summarize(Quantity = sum(a)
)
datSum2 <- arrange(datSum2,desc(Quantity))
Lvl2dfStatus <- tibble(name = datSum2$y,y = datSum2$Quantity, drilldown = tolower(name))
Lvl1ClickHardCoded <<- input$ClickedInput
Lvl1id <<- tolower(input$ClickedInput)
}
else{
Lvl2dfStatus <- data.table(Group.1=numeric(), x=numeric())
Lvl2dfStatus <- tibble(name = Lvl2dfStatus$Group.1,y = Lvl2dfStatus$x)
Lvl1id <- ""
}
#Third Tier
rowcheck <- dat[dat$x == Lvl1ClickHardCoded,]
rowcheck <- rowcheck[rowcheck$y == input$ClickedInput,]
if (nrow(rowcheck)!=0){
datSum2 <- dat[dat$x == Lvl1ClickHardCoded,]
datSum3 <- datSum2[datSum2$y == input$ClickedInput,]
datSum3 <- datSum3 %>%
group_by(z) %>%
summarize(Quantity = sum(a)
)
datSum3 <- arrange(datSum3,desc(Quantity))
Lvl3dfStatus <- tibble(name = datSum3$z,y = datSum3$Quantity)
Lvl2id <<- tolower(input$ClickedInput)
}
else{
Lvl3dfStatus <- data.table(Group.1=numeric(), x=numeric())
Lvl3dfStatus <- tibble(name = Lvl3dfStatus$Group.1,y = Lvl3dfStatus$x)
Lvl2id <- ""
}
#Graph
ClickedTest <- JS("function(event) {Shiny.onInputChange('ClickedInput', event.point.name);}")
highchart() %>%
hc_xAxis(type = "category") %>%
hc_add_series(Lvl1dfStatus, "column", hcaes(x = name, y = y), color = "#E4551F") %>%
hc_plotOptions(column = list(stacking = "normal",
events = list(click = ClickedTest))) %>%
hc_drilldown(
allowPointDrilldown = TRUE,
series = list(
list(id = Lvl1id, type = "column", data = list_parse(Lvl2dfStatus)),
list(id = Lvl2id, type = "column", data = list_parse2(Lvl3dfStatus))
)
)
})
output$trial <- renderText({input$ClickedInput})
}
shinyApp(ui, server)
Your approach was kind of mislead by the click function. It is totally unnecessary, since (as can be seen in the non-shiny example) Highcharts has its own mechanisms to detect series clicks and can find and render drilldowns on its own.
You trying to catch the click event made the Highcharts chart building function re-render every time (resetting any drilldown) so you could not see any drilldown events at all.
The solution is to just copy your working Highcharts example into the renderHighchart function. You will immediately see that the "Farm" and "Sheep" dropdowns work.
I suppose that you were confusing yourself by using the terms "input" for the sublevel names as they are no input at all (in the shiny sense). What you have to do to get the drilldown working properly is to predefine the drilldown sets when you create the Highcharts chart. So you tell the Plugin in advance what drilldowns will be used and Highchart drills down only based on the IDs you specify.
I edited your code such that all the possible drilldowns are created in a loop and everything is working:
library (shinyjs)
library (tidyr)
library (data.table)
library (highcharter)
library (dplyr)
library (shinydashboard)
library (shiny)
x <- c("Farm","Farm","Farm","City","City","City","Ocean","Ocean")
y <- c("Sheep","Sheep","Cow","Car","Bus","Bus","Boat","Boat")
z <- c("Bill","Tracy","Sandy","Bob","Carl","Newt","Fig","Tony")
a <- c(1,1,1,1,1,1,1,1)
dat <- data.frame(x,y,z,a)
header <- dashboardHeader()
body <- dashboardBody(
highchartOutput("Working"),
verbatimTextOutput("trial")
)
sidebar <- dashboardSidebar()
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output, session) {
output$Working <- renderHighchart({
#First Tier #Copied
datSum <- dat %>%
group_by(x) %>%
summarize(Quantity = sum(a)
)
datSum <- arrange(datSum,desc(Quantity))
Lvl1dfStatus <- tibble(name = datSum$x, y = datSum$Quantity, drilldown = tolower(name))
#Second Tier # Generalized to not use one single input
# Note: I am creating a list of Drilldown Definitions here.
Level_2_Drilldowns <- lapply(unique(dat$x), function(x_level) {
# x_level is what you called 'input' earlier.
datSum2 <- dat[dat$x == x_level,]
datSum2 <- datSum2 %>%
group_by(y) %>%
summarize(Quantity = sum(a)
)
datSum2 <- arrange(datSum2,desc(Quantity))
# Note: The "drilldown" variable has to be unique, this is why we use level 1 plus level 2 names.
Lvl2dfStatus <- tibble(name = datSum2$y,y = datSum2$Quantity, drilldown = tolower(paste(x_level, name, sep = "_")))
list(id = tolower(x_level), type = "column", data = list_parse(Lvl2dfStatus))
})
#Third Tier # Generalized through all of level 2
# Note: Again creating a list of Drilldown Definitions here.
Level_3_Drilldowns <- lapply(unique(dat$x), function(x_level) {
datSum2 <- dat[dat$x == x_level,]
lapply(unique(datSum2$y), function(y_level) {
datSum3 <- datSum2[datSum2$y == y_level,]
datSum3 <- datSum3 %>%
group_by(z) %>%
summarize(Quantity = sum(a)
)
datSum3 <- arrange(datSum3,desc(Quantity))
Lvl3dfStatus <- tibble(name = datSum3$z,y = datSum3$Quantity)
# Note: The id must match the one we specified above as "drilldown"
list(id = tolower(paste(x_level, y_level, sep = "_")), type = "column", data = list_parse2(Lvl3dfStatus))
})
}) %>% unlist(recursive = FALSE)
highchart() %>%
hc_xAxis(type = "category") %>%
hc_add_series(Lvl1dfStatus, "column", hcaes(x = name, y = y), color = "#E4551F") %>%
hc_plotOptions(column = list(stacking = "normal")) %>%
hc_drilldown(
allowPointDrilldown = TRUE,
series = c(Level_2_Drilldowns, Level_3_Drilldowns)
)
})
output$trial <- renderText({input$ClickedInput})
}
shinyApp(ui, server)
If for any reason, you should not be satisfied with collecting all drilldowns beforehand, there is an api for adding drilldowns on the fly. Try searching for Highcharts and "addSeriesAsDrilldown". I am not sure, however, if this is accessible outside of JavaScript.

Resources