I have read now the stackoverflow Q&A for several hours on various days and have also seen the latest specific Shiny debugging video from the Shiny developer conference (Jonathan McPherson):
Now the problem looks simple to me, but I went through lots of checks, revisions of the naming conventions and thought of various hypotheses: Making column titles starting with capital letters, calling the initial file similar to the template, renaming the column titles, ...
I like the interactive scatter plots from the Movie Gallery and would like to reproduce it with my own records, located in a cvs file, which I uploaded in my RStudio session with the name all_flexitime, which I understand now is not enough.
How do I connect or integrate my cvs file into the given template? I have renamed all necessary fields, I believe. The error I am getting says:
Error in eval(substitute(expr), envir, enclos) :
object 'Flexileave2015' not found
Flexileave2015 is, I believe, the first variable the server file is looking for to produce the scatter plot, but since the file needs to be found somewhere in the server file, it cannot find it there. I can see it in my Studio.
Can somebody confirm my understanding and possibly help, please.
My all_flexitime data frame is made of the following columns titles:
"Number", "First", "Last", "Contract", "Grade", "Flexileave2015", "Certifiedsickleave2015", "Uncertifiedsickleave2015", "Daysnotrecorded2015", "Excess2015".
My server.R is:
library(ggvis)
library(dplyr)
if (FALSE) library(RSQLite)
shinyServer(function(input, output, session) {
# Filter staff, returning a data frame
flexitimes <- reactive({
# Due to dplyr issue #318, we need temp variables for input values
flexileave2015 <- input$flexileave2015
certifiedsickleave2015 <- input$certifiedsickleave2015
uncertifiedsickleave2015 <- input$uncertifiedsickleave2015
daysnotrecorded2015 <- input$daysnotrecorded2015
excess2015 <- input$excess2015
# Apply filters
m <- all_flexitimes %>%
filter(
Flexileave2015 >= flexileave2015,
Excess2015 >= excess2015,
Certifiedsickleave2015 >= certifiedsickleave2015,
Uncertifiedsickleave2015 >= uncertifiedsickleave2015,
Daysnotrecorded2015 >= daysnotrecorded2015
) %>%
arrange(Flexileave2015)
# Optional: filter by Contract
if (input$contract != "All") {
contract <- paste0("%", input$contract, "%")
m <- m %>% filter(Contract %like% contract)
}
# Optional: filter by Grade
if (input$grade != "All") {
grade <- paste0("%", input$grade, "%")
m <- m %>% filter(Grade %like% grade)
}
# Optional: filter by Number
if (!is.null(input$number) && input$number != "") {
number <- paste0("%", input$number, "%")
m <- m %>% filter(Number %like% number)
}
# Optional: filter by Last Name
if (!is.null(input$last) && input$last != "") {
last <- paste0("%", input$last, "%")
m <- m %>% filter(Last %like% last)
}
m <- as.data.frame(m)
m
})
# Function for generating tooltip text
flexitime_tooltip <- function(x) {
if (is.null(x)) return(NULL)
if (is.null(x$Number)) return(NULL)
# Pick out the staff with this Number
all_flexitimes <- isolate(flexitimes())
flexitime <- all_flexitimes[all_flexitimes$Number == x$Number, ]
paste0("<b>", flexitime$First, flexitime$Last, "</b><br>",
flexitime$Grade, "<br>",
flexitime$Contract
)
}
# A reactive expression with the ggvis plot
vis <- reactive({
# Lables 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))
flexitimes %>%
ggvis(x = xvar, y = yvar) %>%
layer_points(size := 50, size.hover := 200,
fillOpacity := 0.2, fillOpacity.hover := 0.5,
key := ~ Number) %>%
add_tooltip(flexitime_tooltip, "hover") %>%
add_axis("x", title = xvar_name) %>%
add_axis("y", title = yvar_name) %>%
set_options(width = 500, height = 500)
})
vis %>% bind_shiny("plot1")
output$n_flexitimes <- renderText({ nrow(flexitimes()) })
})
The ui.R file is the following:
library(ggvis)
# For dropdown menu
actionLink <- function(inputId, ...) {
tags$a(href='javascript:void',
id=inputId,
class='action-button',
...)
}
shinyUI(fluidPage(
titlePanel("Overview of Flexitime usage"),
fluidRow(
column(3,
wellPanel(
h4("Filter"),
sliderInput("flexileave2015", "Flexileave 2015", 0, 14, 0, step = 1),
sliderInput("certifiedsickleave2015", "Certified sickleave 2015", 0, 230, 0, step = 1),
sliderInput("uncertifiedsickleave2015", "Uncertified sickleave 2015", 0, 13, 0, step = 1),
sliderInput("daysnotrecorded2015", "Days not recorded 2015", 0, 110, 0, step = 10),
sliderInput("excess2015", "Excess 2015", -100, 1500, 0, step = 50),
selectInput("contract", "Contract",
c("All", "Temporary Agent", "Contract Agent", "National Expert", "Interim")),
selectInput("grade", "Grade",
c("All", "AD05","AD06","AD07","AD08","AD09", "AD10","AD11", "AD12","AD13", "AD14","AD15","AST01","AST02","AST03","AST04","AST05","AST06","AST07",
"AST08","AST09","AST10","FGII.04","FGII.05","FGII.06","FGIII.08","FGIII.09","FGIII.10",
"FGIV.13","FGIV.14","FGIV.16","FGIV.18","SNE")),
textInput("number", "SAP Personnelnumber"),
textInput("last", "Initial of Last Name")
),
wellPanel(
selectInput("xvar", "X-axis variable", axis_vars, selected = "Flexileave2015"),
selectInput("yvar", "Y-axis variable", axis_vars, selected = "Uncertifiedsickleave2015"),
tags$small(paste0(
"Note: AD and AST are Temporary agent grades.",
" FG are Contract agent grades.",
" SNE is the only National expert grade.",
" Interims should not have an FG grade."
))
)
),
column(9,
ggvisOutput("plot1"),
wellPanel(
span("Number of staff members selected:",
textOutput("n_flexitimes")
)
)
)
)
))
I got external help for my shiny app, so I am posting how I sorted the problems in the end:
There was a spelling mistake for the all_flexitime data set, I changed it to be all_flexitimes.
In the preparatory work file (the one where I created the original database), I have made sure that the variables are read as characters and not as factors:
all_flexitimes$Grade <- as.character(all_flexitimes$Grade)
all_flexitimes$Contract <- as.character(all_flexitimes$Contract)
all_flexitimes$First <- as.character(all_flexitimes$First)
all_flexitimes$Last <- as.character(all_flexitimes$Last)
I have saved the all_flexitimes file into an .RData file via the following command, while I was in the RStudio working environment:
saveRDS(all_flexitimes, "all_flexitimes.RData")
In the global.R file I have added at the end the following line, so that the database can be read:
all_flexitimes <- readRDS("all_flexitimes.Rdata")
In the ui.file I used the following, as this was the safer option, as it avoids any misspelling:
selectInput("contract", "Contract",
c("All", sort(unique(all_flexitimes$Contract)))),
selectInput("grade", "Grade",
c("All", sort(unique(all_flexitimes$Grade)))),
In the server file, I have changed the manual filters to:
Optional: filter by Contract
if (input$contract != "All") {
contract <- paste0("%", input$contract, "%")
m <- m %>% filter(Contract == input$contract)
}
Optional: filter by Grade
if (input$grade != "All") {
grade <- paste0("%", input$grade, "%")
m <- m %>% filter(Grade == input$grade)
}
Optional: filter by Number
if (!is.null(input$number) && input$number != "") {
number <- paste0("%", input$number, "%")
m <- m %>% filter(Number == input$number)
}
Optional: filter by Last Name
if (!is.null(input$last) && input$last != "") {
last <- paste0("%", input$last, "%")
m <- m %>% filter(Last == input$last)
Related
I'm working on cancer data from TCGA.
Im new to shiny and creating web applications (learning it!!)
I'm working on a shiny tool to plot the volcanoplot using highcharter package.
sometimes I'm successfully able to plot the volcanoplot in the UI. but sometimes it fails to plot it and throws an error saying,
"An error has occurred!
could not find function "highchartOutput"
and one warning message is given for the error;
Listening on http://127.0.0.1:5335
Warning: Error in highchartOutput: could not find function "highchartOutput"
83: dots_list
82: div
81: tabPanel
I think there is some problem with the tabset panel.
is this error has anything to do with indentation? (wherever I adjust the brackets it works magically. not sure how it works for sometimes.)
I am attaching the UI and server files with this post.
code is attached for one type of comparison
UI file below:
library(shiny)
# Define UI for application
shinyUI(fluidPage(
# Application title
titlePanel("miR-Gyn-Explorer"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
## select the count matrix
selectInput("file", label = h3("Count Matrix"),
choices = list("Stage I - Normal" = list("TCGA-BRCA" = "Data/TCGA-BRCASI_NT.rda", "TCGA-UCEC" = "Data/TCGA-UCECSI_NT.rda"))),
## select the phenodata of samples
selectInput("phenofile", label = h3("Sample Phenodata"),
choices = list("Stage I - Normal" = list("TCGA-BRCA" = "Data/TCGA-BRCA_phenoSI_NT.rda", "TCGA-UCEC" = "Data/TCGA-UCEC_phenoSI_NT.rda"))),
submitButton("Update View")
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(
tabPanel("DEmiRNA", DT::dataTableOutput("DEmiRNA"),
"Volcano-Plot", highchartOutput("volcanoPlot", height = "500px"))
#tabPanel("miRNA-Targets", DT::dataTableOutput('miRTarget'),
#plotOutput("GO"))
)
)
)
)
)
server file:
library(shiny)
library(R.utils)
##function to find the DEmiRNA by edgeR method
library(limma)
library(edgeR)
library(DT)
library(dplyr)
library(multiMiR)
library(miRBaseConverter)
library(ggplot2)
#library(ggrepel)
library(tidyverse)
library(highcharter)
library(org.Hs.eg.db)
library(clusterProfiler)
library(purrr)
gdcDEmiRNA <- function(counts, groups, comparison, filter=TRUE) {
## method = edgeR
dge = DGEList(counts = counts, samples = groups)
group <- factor(groups$group)
design <- model.matrix(~0+group)
colnames(design) <- levels(group)
contrast.matrix <- makeContrasts(contrasts=comparison,
levels=design)
keep = filterByExpr(dge,design)
dge <- dge[keep,,keep.lib.sizes = TRUE]
dge <- calcNormFactors(dge)
dge <- estimateDisp(dge, design)
fit <- glmFit(dge, design)
lrt <- glmLRT(fit, contrast=contrast.matrix)
DEGAll <- lrt$table
DEGAll$FDR <- p.adjust(DEGAll$PValue, method = 'fdr')
o <- order(DEGAll$FDR)
DEGAll <- DEGAll[o,]
return (DEGAll)
}
# Define server logic required to perform the DEmiRNA analysis
server <- function(input, output) {
d <- reactive({
#DEmiRNA calculation
file <- load(input$file)
phenofile <- load(input$phenofile)
if(file == "SI_NT"){
if(phenofile == "phenoSI_NT"){
DEmiRNA <- gdcDEmiRNA(counts = SI_NT, groups = phenoSI_NT,
comparison = 'StageI-Normal')
}
}
})
output$DEmiRNA <- DT::renderDataTable({
mir <- d()
#mir <- mir[mir$FDR < input$FDR,]
})
output$volcanoPlot <- renderHighchart({
x <- d()
x$mirna <- rownames(x)
x$sig <- ifelse(x$PValue < 0.05 & abs(x$logFC) > 0.57, "DEmiRNA", "Not Regulated")
hc <- highchart() %>%
hc_add_series(x, "scatter", hcaes(logFC, -log10(PValue), group = sig, value = mirna),
color = c('rgba(67, 67, 72, 0.6)', 'rgba(124, 181, 236, 0.6)'),
enableMouseTracking = c(TRUE, TRUE),
showInLegend = TRUE, marker = list(radius = 4)) %>%
hc_tooltip(pointFormat = "{point.value}", headerFormat = "") %>%
hc_xAxis(title = list(text = "Log fold change"), gridLineWidth = 1,
tickLength = 0, startOnTick = "true", endOnTick = "true", min = -6, max = 6) %>%
hc_yAxis(title = list(text = "-Log10(p-value)")) %>%
hc_chart(zoomType = "xy", width=700) %>%
hc_exporting(enabled = TRUE, filename = "volcano")
hc
})
}
any comment and help from you guys is appreciated
Thank you in advance!
-Ankita
Trying to run a shiny app, but keep getting the error: Error in filter_impl: Result must have length 4090, not 0
I've tried:
debugging by removing individual filters to try isolate the issue.
using dplyr::filter to force dplr's filter
ensured all filters are in a reactive function
checked whether it was an issue of sharing inputs between ui.R and server.r
checked whether it is caused by a previous df transformation.
Spent about 3 hours trying to find the cause, with no success.
Can you please help?
Server.R
rm(list = ls())
library(shiny)
library(tidyverse)
library(shiny)
library(ggplot2)
library(singer)
library(ggvis)
library(dplyr)
# Set Up DataFrames
data(package = "singer")
data(singer_locations)
sdf <- singer_locations %>% filter(year != 0) # filter out songs with missing years for simplicity
sdf %>% skim() %>% kable() # Check to see missing and incomplete values
sdf <- sdf %>% filter(complete.cases(.)) # filter out songs with missing observations for simplicity
sdf %>% skim() %>% kable() # Check to see if missing and incomplete values have been ignored
sdf <- sdf %>% select(
track_id, title, song_id, release, artist_id, artist_name, year, duration,
artist_hotttnesss, artist_familiarity, name, city, longitude, latitude
)
# add new columns with rounded data (for nicer graphs later)
sdf$latitude_rounded <- round(sdf$latitude, 0)
sdf$longitude_rounded <- round(sdf$longitude, 0)
sdf$duration_rounded <- round(sdf$duration, 0)
# Add song_popularity & very_popular_song columns
pops <- sdf$artist_hotttnesss + sdf$artist_familiarity
sdf$artist_popularity <- round(pops, 0)
sdf$very_popular_song <- round(sdf$artist_popularity)
sdf$very_popular_song[sdf$very_popular_song < 1] <- "No"
sdf$very_popular_song[sdf$very_popular_song >= 1] <- "Yes"
# Select() relevant variables so they can be passed into server below (without having to use df[,"VAR"])
songs_list <- sdf %>% select(
track_id, title, song_id, release, artist_id, artist_name, year, duration_rounded, duration,
artist_hotttnesss, artist_familiarity, name, city, latitude_rounded, longitude_rounded, longitude,
latitude, artist_popularity, very_popular_song
)
#axis_variables <- reactive({
axis_variables <- c(
"Length of Song (Seconds)" = "duration_rounded",
"Rating" = "artist_hotttnesss",
"Rating" = "artist_familiarity",
"Year" = "year",
"Popularity Rating" = "artist_popularity"
)
################################### SHINY SERVER #########################################
function(input, output) {
songs <- reactive({ # Create Reactive Filtering Component
duration_s <- input$duration_s
artist_hotttnesss_s <- input$artist_hotttnesss_s
artist_familiarity_s <- input$artist_familiarity_s
latitude_s <- input$latitude_s
longitude_s <- input$longitude_s
year_s <- input$year_s
artist_popularity_s <- input$artist_popularity_s
# Apply filters
songs_df <- songs_list %>%
dplyr::filter(
duration_rounded >= duration_s,
artist_hotttnesss >= artist_hotttnesss_s,
artist_familiarity >= artist_familiarity_s,
latitude_rounded >= latitude_s,
longitude_rounded >= longitude_s,
year >= year_s,
artist_popularity >= artist_popularity_s
) %>%
arrange(duration_rounded)
# filter by city option
if (input$city_in != "All") {
city_in_temp <- paste0("%", input$city_in, "%")
songs_df <- songs_df %>% dplyr::filter(songs_df$city %like% city_in_temp)
}
# filter by artist_name option
if (input$artist_name_in != "" && !is.null(input$artist_name_in)) {
artist_name_temp <- paste0("%", input$artist_name_in, "%")
songs_df <- songs_df %>% dplyr::filter(songs_df$artist_name %like% artist_name_temp)
}
songs_df <- as.data.frame(songs_df)
songs_df # return df
})
# search fuction
song_search <- function(s) {
if (is.null(s)) return(NULL)
if (is.null(s$track_id)) return(NULL)
# Isolate the given ID
songs_df <- isolate(songs())
temp_song <- songs_df[songs_df$track_id == s$track_id, ]
paste0("<b>", temp_song$artist_name, "</b><br>",
temp_song$year, "<br>",
"popularity ", format(temp_song$artist_popularity, big.mark = ",", scientific = FALSE)
)
}
# A reactive expression with the ggvis plot
vis <- reactive({
# setting variablex & variabley (input names are type str)
variablex <- prop("x", as.symbol(input$variablex))
variabley <- prop("y", as.symbol(input$variabley))
# Lables for axes
xvar_name <- names(axis_variables)[axis_variables == input$variablex]
yvar_name <- names(axis_variables)[axis_variables == input$variabley]
songs %>%
ggvis(x = variablex, y = variabley) %>%
layer_points(size := 50, size.hover := 200,
fillOpacity := 0.2, fillOpacity.hover := 0.5,
stroke = ~artist_popularity, key := ~artist_name) %>%
add_tooltip(song_search, "hover") %>%
add_axis("x", title = xvar_name) %>%
add_axis("y", title = yvar_name) %>%
add_legend("stroke", title = "Very Popular", 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")
output$songs_selected <- renderText({ nrow(songs()) })
}
Ui.R
rm(list = ls())
library(tidyverse)
library(shiny)
library(ggplot2)
library(singer)
library(ggvis)
library(dplyr)
#axis_variables <- reactive({
axis_variables <- c(
"Length of Song (Seconds)" = "duration_rounded",
"Hotness Rating" = "artist_hotttnesss",
"Familiarity Rating" = "artist_familiarity",
"Year" = "year",
"Popularity Rating" = "artist_popularity"
)
# Define UI for application that draws a histogram
shinyUI(fluidPage(
shinythemes::themeSelector(),
titlePanel("Artist & Song Data"),
fluidRow(
column(3,
wellPanel(
h4("Filter By"),
# Slider Options for Data Exploration
sliderInput("duration_s", "Minimum duration of song (seconds)", 10, 500, 100, step = 10),
sliderInput("year_s", "Year released", 1900, 2018, value = c(1980, 2018)),
sliderInput("artist_hotttnesss_s", "Ranking / 10 for popularity", 0, 2, 0, step = 0.1),
sliderInput("artist_familiarity_s", "Ranking / 10 for familiarity", 0, 2, 0, step = 0.1),
sliderInput("artist_popularity", "Ranking / 10 for familiarity", 0, 2, 0, step = 0.1),
# Filter by custom input condition
textInput("city_in", "Name of the city"),
textInput("artist_name_in", "Artist's name contains (e.g Pink f)")
),
wellPanel(
selectInput("variablex", "X-axis", axis_variables, selected = "year"),
selectInput("variabley", "Y-axis", axis_variables, selected = "duration_rounded")
)
),
column(9,
ggvisOutput("plot1"),
wellPanel(
span("Degrees of Freedom",
textOutput("songs_selected")
)
)
)
)
It looks like you are filtering using data created by input$XXX. Try to put req(input$XXX, req(input$YYY, ...) at the beginning of your reactive element(s).
Also read this tweet about starting with rm(list = ls()).
asked this on the shiny google group, w no help yet: I'm struggling with how to pass an input switch to dplyr's group_by_ in the code below.
I bolded the two parts of relevant code in the not-so-MRE below (ie, lines 9:11, and 24).
effectively, if the user selects "daily" in the UI, the resultant grouping should be group_by(year = year(my_date), month = month(my_date), day = day(my_date) in line 24, or remove ANY grouping as the data is already daily.
selecting "monthly", should yield group_by(year = year(my_date), month = month(my_date))
"yearly", should yield group_by(year = year(my_date))
I welcome meta-suggestions/ criticism about how my code/ structures are organized.
Thank you
library(shiny)
library(dplyr)
library(lubridate)
ui <- fluidPage(
dateInput("start", label = "start date", value = "2010-01-01"),
dateInput("end", label = "end date", value = "2020-01-01"),
selectInput("grouping_freq", label = "Granularity",
choices = list("daily" = 1,"monthly" = 2, "Yearly" = 3),
selected = 2),
tableOutput("my_table")
)
server <- function(input, output) {
df <- reactive({ data_frame(my_date = seq(input$start, input$end, by = 'day')) }) ## 10 years of daily data
df2 <- reactive({ df() %>% mutate(dummy_data = cumsum(rnorm( nrow( df() ) ))) })
output$my_table <- renderTable({
df2() %>% group_by(year = year(my_date), month = month(my_date)) %>%
summarise(dummy_data = sum(dummy_data), my_date = as.Date(min(my_date)))
})
}
shinyApp(ui = ui, server = server)
You can use the value chosen in selectInput to create a list of formulas that are passed into group_by_, the version of dplyr::group_by that uses standard evaluation.
group_list <- switch(input$grouping_freq,
list(yr=~year(my_date), mn=~month(my_date), dy=~day(my_date)),
list(yr=~year(my_date), mn=~month(my_date))
list(yr=~year(my_date)))
or if you prefer if statements,
group_list <- if (input$grouping_freq == 1) {
list(yr=~year(my_date), mn=~month(my_date), dy=~day(my_date))
} else if (input$grouping_freq == 2) {
list(yr=~year(my_date), mn=~month(my_date))
} else if (input$grouping_freq == 3) {
list(yr=~year(my_date))
} else {
list()
}
and then you can pass group_list into the renderTable expression
output$my_table <- renderTable({
df2() %>%
group_by_(.dots=group_list) %>%
summarise(dummy_data = sum(dummy_data), my_date = as.Date(min(my_date)))
})
I am not sure what you meant by "remove ANY grouping as the data is already daily." but if the data might already be grouped you can use the ungroup function to remove any groups before applying the groupings in group_list.
Edit: Forgot to include ~ in the list elements so that they evaluate correctly.
I am trying to make the colors in a ggvis plot remain consistent whenever the data is re-plotted based on the factors (unfortunately I apparently lack enough reputation to include pictures to show you).
I could only find one other post about this controlling-color-of-factor-group-in-ggvis-r but none of his solutions or workarounds work in my situation.
my data looks like this:
month year date entity_name prefix module module_entry_key entity_table_name count
0 January 2011 2011.000 AbLibrary LIB Base BS AB_LIBRARY 0
1 February 2011 2011.083 AbLibrary LIB Base BS AB_LIBRARY 0
2 March 2011 2011.167 AbLibrary LIB Base BS AB_LIBRARY 0
3 April 2011 2011.250 AbLibrary LIB Base BS AB_LIBRARY 0
4 May 2011 2011.333 AbLibrary LIB Base BS AB_LIBRARY 0
5 June 2011 2011.417 AbLibrary LIB Base BS AB_LIBRARY 0
3000 January 2011 2011.000 Vector VEC Base BS VECTOR 0
3001 February 2011 2011.083 Vector VEC Base BS VECTOR 0
3002 March 2011 2011.167 Vector VEC Base BS VECTOR 0
3003 April 2011 2011.250 Vector VEC Base BS VECTOR 569
3004 May 2011 2011.333 Vector VEC Base BS VECTOR 664
3005 June 2011 2011.417 Vector VEC Base BS VECTOR 775
I'm using a shiny app to display the page in a browser, and the relevant code is:
# render the plot, filtering for entities within the module minus any entities selected from the exclude panel
plot <- reactive({
if (input$filter==1){
data <- dplyr::filter(.data=melted, module_entry_key %in% input$module)
}
else{
data <- dplyr::filter(.data=melted, entity_name == input$entity)
}
data <- dplyr::filter(.data=data, !entity_name %in% input$excluded)
data$entity_name <- factor(data$entity_name)
data %>%
ggvis(x = ~date, y = ~count, fill = ~entity_name, key := ~id, fillOpacity := 0.5, fillOpacity.hover := 0.9) %>%
add_legend("fill", title="Entities") %>%
layer_points() %>%
add_tooltip(tooltipText, "hover") %>%
add_axis("y", title = "Count", title_offset = 50) %>%
add_axis("x", title="Date", title_offset=50, subdivide=6, tick_size_minor=3, format=parseDate(~year, ~month))
})
the filter is creating the subset of "melted" as "data" based on the filters in the UI (see picture)
since as far as I can tell there is no way to associate a fill color to a factor (the entity name) explicitly and the color is chosen by alphabetical order of the factors, whenever I make a new subset of data the colors are changed.
Is there any way to work around this?
(full shiny code)
server.R
library(ggvis)
library(shiny)
library(dplyr)
shinyServer(function(input, output, session){
modules_list <- as.character(c("Base" = "BS",
"Screening" = "SC",
"Protein Engineering" = "EN",
"Protein Production" = "PP",
"CD",
"PT",
"PD"))
#melted <- read.table(file="~/dataOut.txt", sep="\t", strip.white=TRUE, row.names=1, header=TRUE);
modules <- as.character(as.vector(unique(melted$module_entry_key)))
modules <- modules[modules != "null"]
entities <- as.character(as.vector(unique(melted$entity_name)))
entities <- entities[entities != "null"]
for (i in entities){
melted <- rbind(melted, data.frame(month=NA, year=NA, date=NA, entity_name=i, prefix=NA, module=NA, module_entry_key=NA, entity_table_name=NA, count=NA))
}
melted$id <- 1:nrow(melted)
#create ui checkbox for modules in the data
output$module_list <- renderUI({
checkboxGroupInput(inputId = "module",
label = "Module",
choices = modules,
selected = "BS")
})
#create the ui list for entities
output$entity_list <- renderUI({
checkboxGroupInput(
inputId = "entity",
label = "Entity",
choices = entities,
selected = "Vector"
)
})
#ex <- entities
#create the checkboxGroupInput with entities to 'exclude'
output$exclusion_entities <- renderUI({
checkboxGroupInput(inputId = "excluded", label = "Exclude",
choices = entities)
})
#update the excluded entities list with entities within a particular module
observe({
if (input$filter==1)
ex1 <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=ex1, selected = input$excluded )
})
# render the plot, filtering for entities within the module minus any entities selected from the exclude panel
plot <- reactive({
if (input$filter==1){
data <- dplyr::filter(.data=melted, module_entry_key %in% input$module)
}
else{
data <- dplyr::filter(.data=melted, entity_name == input$entity)
}
data <- dplyr::filter(.data=data, !entity_name %in% input$excluded)
data$entity_name <- factor(data$entity_name)
data %>%
ggvis(x = ~date, y = ~count, fill = ~entity_name, key := ~id, fillOpacity := 0.5, fillOpacity.hover := 0.9) %>%
add_legend("fill", title="Entities") %>%
layer_points() %>%
add_tooltip(tooltipText, "hover") %>%
add_axis("y", title = "Count", title_offset = 50) %>%
add_axis("x", title="Date", title_offset=50, subdivide=6, tick_size_minor=3, format=parseDate(~year, ~month))
})
#function to add color and mouse-over effect to layer_points() (unused in this code)
points <- reactive({
layer_points(fillOpacity := 0.5, fillOpacity.hover := 1, fill.hover := "red")
})
#d3 date format for formatting x-axis text
parseDate <- function(year, month){
paste("d3.time.format(\"%Y\").parse(", year, ")", sep="")
}
#function for what to display in mouse-hover tooltip
tooltipText <- function(x) {
if(is.null(x)) return(NULL)
row <- melted[melted$id == x$id, ]
paste(row$entity_name, ": ", row$count, sep="")
}
#bind the plot to the UI
plot %>% #layer_points(fill = ~factor(entity_name)) %>%
bind_shiny("ggvis")
#select all button for modules
observe({
if (input$selectall ==0){
return(NULL)
}
else if ((input$selectall%%2)==0){
updateCheckboxGroupInput(session, inputId = "module", "Module", choices = modules)
}
else{
updateCheckboxGroupInput(session, inputId = "module", "Module", choices=modules, selected=modules)
}
})
#select all button for excluded entities
observe({
list <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
if (input$exclude_all ==0){
return(NULL)
}
else if ((input$exclude_all%%2)==0){
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=list )
}
else{
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=list, selected=list )
}
})
#---general output / debugging stuff ----#
output$table <- renderTable({dataInput()})
output$entity_selected = renderPrint({
list <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
entities[!entities %in% input$excluded & entities %in% list]
})
output$filter_value = renderPrint({input$filter})
output$modules = renderPrint({input$module})
output$link = renderPrint(input$selectall%%2)
#----------------------------------------#
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("DB Analysis"),
sidebarLayout(
sidebarPanel(
width=3,
radioButtons(inputId="filter",
label="Filter",
choices = list("By Module" = 1, "By Entity" = 2),
selected = 1),
conditionalPanel(condition = "input.filter == 1",
uiOutput("module_list"),
actionButton("selectall", "Select All"),
uiOutput("exclusion_entities"),
actionButton("exclude_all", "Select All")
),
conditionalPanel(condition = "input.filter == 2",
uiOutput("entity_list")
)
),
mainPanel(
h2("Cumulative Entity Counts over Time (years)", align="center"),
#verbatimTextOutput("value"),
#verbatimTextOutput("filter_value"),
#verbatimTextOutput("modules"),
#tableOutput("table"),
ggvisOutput("ggvis"),
verbatimTextOutput("link"),
verbatimTextOutput("entity_selected")
#textOutput("entities_plot")
)
)
)
)
This is probably the best way to do it. Try something like this:
df[which(df$entity_name == "AbLibrary"),]$color <- "FF0000"
df[which(df$entity_name == "Vector"),]$color <- "#FFB90F"
For each one in your data frame. Set your fill then to color each time. The only problem is trying to make a legend. (I have been trying to figure that out, so if I find it I will edit this post.
I want to have a tooltip on my bar graph that shows detailed info about a customer when hovered over. The problem is that without a defined key the tooltip does not function and with a defined key the barplot does not function properly anymore. Here is the data I used:
CustomerData:
id;CustomerID;CLV;Gender;Channel;Age
1;1;300;male;facebook;24
2;2;2000;female;google ads;34
3;3;500;female;other;43
4;4;1300;male;google ads;34
5;5;100;male;other;46
6;6;400;female;other;32
7;7;600;female;google ads;43
8;8;1000;male;other;46
9;9;200;female;other;75
10;10;1700;male;google ads;35
11;11;1600;female;google ads;23
12;12;800;female;other;54
13;13;400;female;other;34
14;14;700;male;google ads;42
15;15;500;male;facebook;18
16;16;200;male;other;42
17;17;1900;male;google ads;46
18;18;400;female;other;23
19;19;600;male;other;45
20;20;200;female;other;42
21;21;1400;male;facebook;57
22;22;1200;female;facebook;54
Ui Code:
#this is the ui code
shinyUI(pageWithSidebar(
headerPanel("CLV Reporting"),
sidebarPanel(
navbarMenu(
checkboxGroupInput("gender", 'Gender:',
c("female" = "female",
"male" = "male"))),
navbarMenu(
checkboxGroupInput("channel", 'Channel:',
c("Facebook" = "facebook",
"Google Ads" = "google ads",
"Other" = "other"))),
navbarMenu(
sliderInput("age", "Age Range:",
min = 0, max = 100, value = c(20,50)))
),
mainPanel(
ggvisOutput("barplot"),
textOutput("mean"),
textOutput("price")
)
))
Server Code:
#this is the server code
library(ggvis)
library(dplyr)
library(ggplot2)
library(shiny)
shinyServer(function(input, output, session) {
report <- reactive({
gender <- input$gender
channel <- input$channel
minage <- input$age[1]
maxage <- input$age[2]
rep <- CustomerData %>%
filter(
Gender %in% gender,
Channel %in% channel,
Age >= minage,
Age <= maxage
)
})
#tooltip input
Customer_tooltip <- function (x) {
if (is.null(x)) return(NULL)
if (is.null(x$id)) return(NULL)
CustomerData <- isolate(report())
customer <- CustomerData[CustomerData$id == x$id, ]
paste0("<b>", "Customer ID: ", customer$CustomerID, "</b><br>",
"Gender: ", customer$Gender, "</b><br>",
"Channel: ", customer$Channel, "</b><br>",
"Age: ", customer$Age, "<br>",
"CLV: $", format(customer$CLV, big.mark = "'", scientific = FALSE)
)
}
# output
vis <- reactive({
report %>%
ggvis(x = ~factor(CustomerID), y = ~CLV) %>%
layer_bars(fillOpacity := 0.5, fillOpacity.hover := 1, key := ~id) %>%
add_tooltip(Customer_tooltip, "hover") %>%
add_axis("x", title = "Customer") %>%
add_axis("y", title = "CLV", title_offset = 60) %>%
set_options(width = 500, height = 300)
})
vis %>% bind_shiny("barplot")
output$mean <- renderText({
m <- report()
if (nrow(m) != 0) {paste("The mean CLV of the selected customers is: $", round(mean(m$CLV)))}
else {"There are no customers with these specifications."}
})
output$price <- renderText({
m <- report()
if (nrow(m) != 0) {paste("We recommend to spend $", round(mean(m$CLV)/12)*nrow(m), " on retaining these customers.")}
else {""}
})
})
I added the id column because I thought this could solve the problem (using a key which is not used by anything else in the code). Just in case you wondered why there were two variables with the exact same values ;)
(edit) I uploaded the newest version to gisthub:
https://gist.github.com/anonymous/f04325078f9c0656ab72
packages needed: shiny, ggvis, dplyr and ggplot2