Skip to content

Commit d345a01

Browse files
Start implementing process reactives #15, adding sankey
The whole concept of grabbing a reactive and being able to evaluate it outside of shiny so that it can be tested. Not sure it's a good idea. Also, added a sankey output to ShinyHierarchy, which shows hierarchical relationships b/w reactive blocks smarterly. Closes #16
1 parent 6aba729 commit d345a01

File tree

7 files changed

+142
-38
lines changed

7 files changed

+142
-38
lines changed

DESCRIPTION

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
Package: ShinyTester
22
Type: Package
33
Title: Functions to Minimize Bonehead Moves While Working with 'shiny'
4-
Version: 0.1.5
5-
Author: Amit Kohli
4+
Version: 0.1.6
5+
Author: Amit Kohli, Joshua Kunst
66
Maintainer: Amit Kohli <amit@amitkohli.com>
77
BugReports: https://github.com/mexindian/ShinyTester/issues
88
Description: It's my experience that working with 'shiny' is intuitive once you're
99
into it, but can be quite daunting at first. Several common mistakes are fairly
1010
predictable, and therefore we can control for these. The functions in this
11-
package help match up the assets listed in the UI and the SERVER files, and
12-
Visualize the ad hoc structure of the 'shiny' App.
11+
package help match up the assets listed in the UI and the SERVER files,
12+
Visualize the ad hoc structure of the 'shiny' App, and run all the reactives.
1313
License: GPL-2
1414
URL: https://github.com/mexindian/ShinyTester
1515
Imports:
@@ -18,7 +18,8 @@ Imports:
1818
readr,
1919
stringr,
2020
tidyr,
21-
visNetwork
21+
visNetwork,
22+
networkD3
2223
Encoding: UTF-8
2324
LazyData: true
2425
RoxygenNote: 6.0.1

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ importFrom(dplyr,left_join)
1212
importFrom(dplyr,mutate)
1313
importFrom(dplyr,select)
1414
importFrom(dplyr,slice)
15+
importFrom(networkD3,sankeyNetwork)
1516
importFrom(purrr,map)
1617
importFrom(purrr,map_chr)
1718
importFrom(purrr,map_df)

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22

33
* Initial release
44

5+
# ShinyTester 0.2.0 (in development)
6+
7+
* Added parameters to ShinyHierarchy: showInternalFunctions, showCommentedOutChunks parameters, and fixed a bug in Chunking
8+
* ShinyHierarchy now is able to ouptut a Sankey Chart as well
9+
* Added new function: ProcessReactives... not operational yet.
10+
511

612

R/ShinyTester.R

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ ShinyDummyCheck <- function(directory = ".", ui = "ui.R", server = "server.R"){
143143
#' @param showInternalFunctions a boolean that specifies whether to show the functions internal to each node. These are shown
144144
#' on mouse_over in the hierarchy chart. FALSE by default.
145145
#' @param showCommentedOutChunks a boolean that specifies whether to show the chunks that have been commented out. FALSE by default.
146-
#'
146+
#' @param output a character string that specifies what kind of plot should be outputted: either "network" or "sankey" are accepted.
147147
#'
148148
#' @return
149149
#' It returns a very very nice network chart with BASICALLY three-ish ROWS of nodes.
@@ -163,10 +163,11 @@ ShinyDummyCheck <- function(directory = ".", ui = "ui.R", server = "server.R"){
163163
#' @importFrom tidyr unnest separate
164164
#' @importFrom stats setNames runif
165165
#' @importFrom visNetwork visNetwork visEdges visLegend visHierarchicalLayout visOptions
166+
#' @importFrom networkD3 sankeyNetwork
166167
#' @export
167168
ShinyHierarchy <- function(directory=getwd(),ui="ui.R",server="server.R",
168169
offsetReactives=T,showInternalFunctions=F,
169-
showCommentedOutChunks=F){
170+
showCommentedOutChunks=F,output="network"){
170171

171172
## Get input again
172173
a <- read_file(paste(directory,"/",server,sep=""))
@@ -335,39 +336,78 @@ ShinyHierarchy <- function(directory=getwd(),ui="ui.R",server="server.R",
335336
edges <- data.frame(to=nodes$id[match(x = BofDF$ChunkName,table = nodes$Thingie)],
336337
from=nodes$id[match(x = BofDF$Input,table = nodes$Thingie)])
337338

338-
visNetwork(nodes,edges) %>% visEdges(arrows = 'to') %>%
339+
## Now output network or sankey
340+
if(output=="network"){
341+
visNetwork(nodes,edges) %>% visEdges(arrows = 'to') %>%
339342
visLegend() %>% visHierarchicalLayout() %>%
340343
visOptions(highlightNearest = list(enabled = T, degree = 1, hover = T))
344+
} else if (output=="sankey"){
345+
## make links unique
346+
edges <- edges %>%
347+
group_by(from,to) %>%
348+
summarize(value=n())
349+
## zero indexing
350+
edges$from <- edges$from-1
351+
edges$to <- edges$to-1
352+
353+
sankeyNetwork(Links=edges,Nodes = nodes,Source = 'from',NodeID = 'Thingie',
354+
Target = 'to', Value = 'value',NodeGroup = 'group',fontSize = 15)
341355

356+
} else {
357+
stop("Only 'network' or 'sankey' are accepted as outputs")
358+
}
342359
}
343360

344361

345-
ProcessReactives <- function(directory=getwd(),ui="ui.R",server="server.R",
346-
showCommentedOutChunks=F){
347-
348-
## Get input again
349-
a <- read_file(paste(directory,"/",server,sep=""))
350-
b <- gsub("\r?\n","",a)
351-
## Identify code chunks, basically each little shiny minifunction
352-
Chunks <- str_extract_all(b, "[a-zA-Z0-9\\._]+ *\\<\\- *[a-zA-Z0-9\\._]+?\\(\\{.+?\\}\\)",
353-
simplify = F) %>% .[[1]]
354-
if (length(Chunks)==0) stop("Hrm, I can't detect any chunks. I expect assignments to use '<-'... so if
355-
you're using '=' or '->' assignments or 'source'ing stuff in, then that would be why.")
356-
357-
## Identify only the reactive chunks
358-
Chunks <- Chunks[grep("reactive\\(",Chunks)]
359-
360-
## get only the guts
361-
Chunks2 <- str_extract(string = Chunks,"(?<=\\(\\{).+(?=\\}\\))")
362-
363-
## And make stuff evaluatable by replacing multiple space w/ semicolon, however, except the first one.
364-
Chunks3 <- gsub(" +","; ",str_trim(Chunks2),perl=T)
365-
366-
## But deal w/ pipes
367-
Chunks4 <- gsub("\\%;","\\%",Chunks3)
368-
369-
for(i in 1:length(Chunks4)){
370-
# eval(parse(text = Chunks4[i]))
371-
eval(parse(text = str_split(Chunks4[i],";")[[1]]))
372-
}
373-
}
362+
#' #' ProcessReactives
363+
#' #'
364+
#' #' This function runs all the guts from reactive blocks in console (for local testing/debugging).
365+
#' #'
366+
#' #' For now, it only works where the server and ui files are seperate (ie, it doesn't work for `app.R` yet)
367+
#' #'
368+
#' #' @param directory the directory or website containing the files for the Shiny App. Defaults to current working directory
369+
#' #' @param ui a character vector size 1 containing the name of the UI files. defaults to "ui.R"
370+
#' #' @param server a character vector size 1 containing the names of the SERVER file. defaults to "server.R"
371+
#' #' @param inputs a 1 row dataframe containing values for all the inputs that would be required by the reactive scripts (so as to simulate a live version of the Shiny app)
372+
#' #'
373+
#' #' @return
374+
#' #' Returns nothing, but loads all items into memory
375+
#'
376+
#' #' @examples
377+
#' #' ProcessReactives(directory = system.file("example2", package = "ShinyTester"))
378+
#' #'
379+
#' #' @details You can test with your own app, go to your shiny app, make that your
380+
#' #' working directory, and then type `ProcessReactives()`
381+
#' #' @importFrom stringr str_extract_all str_extract str_trim str_split
382+
#' #' @importFrom readr read_file
383+
#' #' @export
384+
#'
385+
#' ProcessReactives <- function(directory=getwd(),ui="ui.R",server="server.R",
386+
#' inputs=inputs){
387+
#'
388+
#' ## Get input again
389+
#' a <- read_file(paste(directory,"/",server,sep=""))
390+
#' b <- gsub("\r?\n","",a)
391+
#' ## Identify code chunks, basically each little shiny minifunction
392+
#' Chunks <- str_extract_all(b, "[a-zA-Z0-9\\._]+ *\\<\\- *[a-zA-Z0-9\\._]+?\\(\\{.+?\\}\\)",
393+
#' simplify = F) %>% .[[1]]
394+
#' if (length(Chunks)==0) stop("Hrm, I can't detect any chunks. I expect assignments to use '<-'... so if
395+
#' you're using '=' or '->' assignments or 'source'ing stuff in, then that would be why.")
396+
#'
397+
#' ## Identify only the reactive chunks
398+
#' Chunks <- Chunks[grep("reactive\\(",Chunks)]
399+
#'
400+
#' ## get only the guts
401+
#' Chunks2 <- str_extract(string = Chunks,"(?<=\\(\\{).+(?=\\}\\))")
402+
#'
403+
#' ## And make stuff evaluatable by replacing multiple space w/ semicolon, however, except the first one.
404+
#' Chunks3 <- gsub(" +","; ",str_trim(Chunks2),perl=T)
405+
#'
406+
#' ## But deal w/ pipes
407+
#' Chunks4 <- gsub("\\%;","\\%",Chunks3)
408+
#'
409+
#' for(i in 1:length(Chunks4)){
410+
#' # eval(parse(text = Chunks4[i]))
411+
#' eval(parse(text = str_split(Chunks4[i],";")[[1]]))
412+
#' }
413+
#' }

inst/example2/server.R

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# RStudio example based on: http://rstudio.github.io/shiny/tutorial/#reactivity
2+
3+
library(shiny)
4+
library(dplyr)
5+
6+
# Define server logic required to summarize and view the selected dataset
7+
shinyServer(function(input, output) {
8+
9+
# By declaring datasetInput as a reactive expression we ensure that:
10+
#
11+
# 1) It is only called when the inputs it depends on changes
12+
# 2) The computation and result are shared by all the callers (it
13+
# only executes a single time)
14+
#
15+
datasetInput <- reactive({
16+
# iris %>% filter(Species == input$dataset)
17+
iris[iris$Species == input$dataset,]
18+
})
19+
20+
21+
# The output$view depends on both the databaseInput reactive expression
22+
# and input$obs, so will be re-executed whenever input$dataset or
23+
# input$obs is changed.
24+
output$view <- renderTable({
25+
datasetInput <- datasetInput()
26+
datasetInput
27+
})
28+
})

inst/example2/ui.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# based on RStudio example from: http://rstudio.github.io/shiny/tutorial/#reactivity
2+
3+
library(shiny)
4+
5+
# Define UI for dataset viewer application
6+
shinyUI(pageWithSidebar(
7+
8+
# Application title
9+
headerPanel("Reactivity"),
10+
11+
# Sidebar with controls to select a dataset, and
12+
# specify the number of observations to view. Note that changes made
13+
# to the caption in the textInput control are updated in the output
14+
# area immediately as you type
15+
sidebarPanel(
16+
selectInput("dataset", "Choose a Species:",
17+
choices = c("setosa","versicolor","virginica" ))
18+
),
19+
20+
21+
# Show the caption, a summary of the dataset and an HTML table with
22+
# the requested number of observations
23+
mainPanel(
24+
tableOutput("view")
25+
)
26+
))

man/ShinyHierarchy.Rd

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)