How to modify the plot sizes in shiny app? - r

I built a shiny app which present several plot types. However, the plots are cut from the top, and they are too wide. I tried modifying the width and height in the plotOutput function, did not work.
My code:
ui <- fluidPage(theme = shinytheme('united'),
titlePanel(title = h3("Graphs - ordered chronologically", align="center")),
selectInput("Plot",
"Choose what plots to present",
choices = list(Heatmap = "Heatmap", PCA = "PCA", VolcanoPlot = "VolcanoPlot", GSEA = 'GSEA')),
submitButton(text = "Show plots"),
verticalLayout( plotOutput(outputId = "PART.1", width = '70%'))
)
The problem is most prominent with the Heatmaps and Volcano plots. The volcano plot is cut from the top, and the heatmaps are too stretched wide:
How can I fix this? thank you.
EDIT:
A minimal version of my code:
library(data.table)
library(dplyr)
library(shiny)
library(shinythemes)
library(plotly)
library(compGenomRData)
library(BiocManager)
library(DESeq2)
library(org.Hs.eg.db)
library(TxDb.Hsapiens.UCSC.hg19.knownGene)
library(EnsDb.Hsapiens.v86)
library(AnnotationHub)
library(AnnotationDbi)
library(pheatmap)
library(EnhancedVolcano)
library(ggplot2)
library(FactoMineR)
library(devtools)
library(clusterProfiler)
library(ggnewscale)
library(enrichplot)
library(msigdbr)
library(readxl)
library(ExperimentHub)
library(annotate)
ui <- fluidPage(theme = shinytheme('united'),
titlePanel(title = h3("Graphs - ordered chronologically", align="center")),
selectInput("Plot",
"Choose which plots to present",
choices = list(Heatmap = "Heatmap", PCA = "PCA", VolcanoPlot = "VolcanoPlot", GSEA = 'GSEA')),
submitButton(text = "Show plots"),
verticalLayout( plotOutput(outputId = "PART.1", width = '70%'),
plotOutput(outputId = "PART.2", width = '70%'),
plotOutput(outputId = "PART.3", width = '70%'),
plotOutput(outputId = "PART.4", width = '70%'),
plotOutput(outputId = "PART.5", width = '70%'),
plotOutput(outputId = "PART.6", width = '70%'),
plotOutput(outputId = "PART.7", width = '70%'))
)
server <- function(input, output) {
# RNA-seq data
raw_counts <- frea
d('E-MTAB-7805-raw-counts.tsv', data.table = F)
metadata <- fread('E-MTAB-7805-experiment-design.tsv' ,data.table = F)
A=duplicated(raw_counts$`Gene ID`) # Check for duplicates and remove them
raw_counts = raw_counts[!A,]
A=duplicated(raw_counts$`Gene Name`) # Check for duplicates and remove them
raw_counts = raw_counts[!A,]
Hugo.Symbol <- raw_counts[,c(1:2)]
rownames(raw_counts) <- raw_counts$`Gene Name` # renaming rownames
raw_counts <- raw_counts[, -c(1:2)]
# metadata
C = duplicated(metadata$Run) # Check for duplicates and remove them
metadata = metadata[!C,]
rownames(metadata) <- metadata$Run
metadata <- metadata[,-1]
ind <- order(colnames(raw_counts), rownames(metadata))
raw_counts <- raw_counts[,ind]
# filter
target1 <- c("0 day", "1 day")
Meta_filter1 <- metadata %>% dplyr::filter(`Factor Value[time]` %in% target1)
Counts_filter1 <- raw_counts[intersect(names(raw_counts), rownames(Meta_filter1))]
rownames(Counts_filter1) <- Hugo.Symbol$`Gene Name`
# annotate
Meta_filter1$group <- plyr::mapvalues(Meta_filter1$`Factor Value[time]`, c("0 day", "1 day"),
c("CTRL", "CASE"))
ind <- order(colnames(Counts_filter1), rownames(Meta_filter1))
Counts_filter1 <- Counts_filter1[,ind]
dds <- DESeqDataSetFromMatrix(countData = Counts_filter1,
colData = Meta_filter1,
design = ~ group)
dds = DESeq(dds)
res = results(dds)
res$symbol <- rownames(res)
resOrder <- res[order(res$padj),]
# heatmap
dds.symbol = dds
rownames(dds.symbol) = mapIds(org.Hs.eg.db,
keys=rownames(dds),
column="SYMBOL",
keytype="SYMBOL",
multiVals="first")
rownames(dds.symbol)[is.na(rownames(dds.symbol))] = rownames(dds)[is.na(rownames(dds.symbol))]
rownames(dds.symbol) = make.unique(rownames(dds.symbol))
selectUp <- resOrder$symbol[resOrder$log2FoldChange>0][1:20]
selectDown <- resOrder$symbol[resOrder$log2FoldChange<0][1:20]
select = c(selectUp,selectDown)
df <- data.frame(row.names = colnames(dds.symbol),
group = colData(dds.symbol)$group)
normcounts = assay(vst(dds.symbol,blind=T, nsub = 2000))
# Functional enrichment
res = res[!is.na(res1$padj),]
mygenes <- rownames(res)
lfc = res1$log2FoldChange # get gene symbol
names(lfc) <- rownames(res)
lfc <- sort(lfc, decreasing = TRUE)
hallmarks <- msigdbr(species = "Homo sapiens", category = "H") %>%
dplyr::select(gs_name, gene_symbol)
## Output
output$PART.1 <- renderPlot({
if (input$Plot == 'Heatmap') {
pheatmap(normcounts[select,], cluster_rows=TRUE,
show_colnames = FALSE,cluster_cols=TRUE,
annotation_col=df, scale = 'row',cutree_cols = 2,cutree_rows = 2)
} else if (input$Plot == 'PCA') {
Var <- apply(normcounts, 1, var)
selectedVarGenes <- names(Var[order(Var, decreasing = T)][1:1000])
M <- t(normcounts[selectedVarGenes,])
pcaResults = prcomp(M)
qplot(pcaResults$x[,1],pcaResults$x[,2], col=dds1$group,size=2)
} else if (input$Plot == 'VolcanoPlot') {
EnhancedVolcano(resOrder,
lab = resOrder$symbol,
x = 'log2FoldChange',
y = 'padj',
labSize=4,
FCcutoff=2 )
} else {
em <- GSEA(lfc, TERM2GENE = hallmarks)
dotplot(em)
}
})
shinyApp(ui = ui, server = server)

Maybe if you include a call to par before calling pheatmap can help:
par(mar=c(5,4,6,2)) # bottom, left, top, right
pheatmap(
normcounts[select,], cluster_rows=TRUE,
show_colnames = FALSE, cluster_cols=TRUE,
annotation_col=df, scale = 'row',
cutree_cols = 2,cutree_rows = 2
)

Related

R shiny: How to copy data derived from plotly_selection events into a data frame/table and update each time by pressing an actionButton?

I'm putting together a shiny app to play around with some athlete GPS data. Essentially, I'm looking to structure my script so that each time the user selects an area of interest on the plotly plot and the "Add" actionButton is clicked, the table below will add the calculated Start_time, Time_at_peak, Max_velocity, Time_to_peak, and Distance_to_peak values.
The issue can be seen in the GIF below: - Once the area of interest is selected and the "Add" button clicked, the first values seem correct. However, when the user selects a second area of interest to add to the table, it overwrites the initial entry and will keep overwriting each time a new selection is made. This is seemingly because because the code is inside the observeEvent(event_data("plotly_selected"), which, confusingly, it needs to be in order to calculate the variables of interest.
I'm currently a little stumped and can't seem to find any relevant information. As such, any guidance would be greatly appreciated!
Here is a we transfer link to some test data that can be uploaded to the app: https://wetransfer.com/downloads/5a7c5da5a7647bdbe133eb3fdac79c6b20211119052848/afe3e5
library(shiny)
library(readr)
library(DT)
library(dplyr)
library(plotly)
library(lubridate)
library(tidyr)
library(purrr)
library(htmlwidgets)
library(shinydashboard)
library(dashboardthemes)
library(shinyjs)
x_df <- data.frame(Start_time = character(1), Time_at_peak = character(1), Max_velocity = integer(1),
Time_to_peak = integer(1), Distance_to_peak = integer(1))
x_df$Start_time <- as.character("0:00:00.0")
x_df$Time_at_peak <- as.character("0:00:00.0")
x_df$Max_velocity <- as.integer(0)
x_df$Time_to_peak <- as.integer(0)
x_df$Distance_to_peak <- as.integer(0)
runApp(shinyApp(
ui=(fluidPage(
titlePanel("Event to Table"),
mainPanel(
fileInput(
inputId = "filedata",
label = "Upload data file (.csv)",
accept = c(".csv")),
plotlyOutput('myPlot'),br(),br(),br(),br(),
DTOutput("testing"), br(), br(),
fluidRow(
valueBoxOutput("starttime", width = 2),
valueBoxOutput("endtime", width = 2),
valueBoxOutput("maxvelocity", width = 2),
valueBoxOutput("timediff", width = 3),
valueBoxOutput("distance", width = 3)
),
useShinyjs(),
fluidRow(
div(style = "text-align:center", actionButton("Add", "Add Data to Table"),
downloadButton("export", "Export Table as .CSV"))), br(),
DTOutput(outputId = "table")))
),
server = (function(input, output, session) {
data<-reactive({
req(input$filedata)
read.csv(input$filedata$datapath, header = TRUE)%>%
rename(Velocity = 'Speed..m.s.',
Player = 'Player.Display.Name',
Latitude = 'Lat',
Longtitude = 'Lon',
AccelImpulse = 'Instantaneous.Acceleration.Impulse',
HeartRate = 'Heart.Rate..bpm.')
})
observe({
thedata<-data()
updateSelectInput(session, 'y', choices = names(data))
})
output$myPlot = renderPlotly({
plot_ly(data = data(), x = ~Time, y = ~Velocity, height = 450,
marker =list(color = 'rgb(132,179,202)', size = 0.1),
line = list(color = 'rgb(132,179,202)', size = 0.1, width = 0.9),
type = 'scatter', mode = 'markers+lines') %>%
layout(dragmode = "select",
showlegend = F,
title = list(text = 'Velocity Trace', font = list(size = 20)),
xaxis = list(title = list(text = "", standoff = 0), nticks = 10),
yaxis = list(title = list(text = "Velocity (m/s)"), nticks = 5, gridcolor = "#46505a"),
font = list(color = 'black'),
margin = list(t = 70))
})
observeEvent(event_data("plotly_selected"), {
event.data <- event_data("plotly_selected")
if (max(event.data$y) < 1.5) {
maxvel <- (max(event.data$y))
maxpos <- match(maxvel, event.data$y)
}
else {
filter1 <- filter (event.data, event.data$y > 1.5)
maxvel <- (max(filter1$y))
maxpos <- match(maxvel, event.data$y)
}
zero_val <- function(x) x == 0
zero_index <- event.data$y[1:maxpos] %>% detect_index(zero_val, .dir = "backward")
if (zero_index==0) {starttime <- event.data$x[1]}
else {starttime <- event.data$x[zero_index]}
endvel <- which.max(event.data$y)
endtime <- event.data$x[endvel]
timediff <- paste(today(), endtime) %>% as_datetime() - paste(today(), starttime) %>% as_datetime()
sprint <- as_tibble(event.data$y[zero_index:endvel])
ms <- as_tibble(rep(0.1, count(sprint)))
time_vel <- cbind(ms, sprint)
distance <- sum(time_vel[1]*time_vel[2])
sprintselect <- as_tibble(cbind(Start_time = starttime,
Time_at_peak = endtime,
Max_velocity = round(maxvel, 2),
Time_to_peak = round(timediff, 1),
Distance_to_peak = round(distance, 1)))
values <- reactiveValues()
values$df <- x_df
addData <- observe({
if(input$Add > 0) {
newLine <- isolate(data.frame(Start_time = sprintselect$Start_time, Time_at_peak = sprintselect$Time_at_peak,
Max_velocity = sprintselect$Max_velocity,
Time_to_peak = sprintselect$Time_to_peak,
Distance_to_peak = sprintselect$Distance_to_peak,
stringsAsFactors= FALSE))
values$df <- isolate(rbind(values$df, newLine))}
})
output$testing <- renderDataTable({values$df})
})
})
))
I've managed to figure it out and thought I'd post an answer rather than delete the question - just in case someone out there is looking to do a similar thing and they are unsure how to do it.
Firstly, I removed the pre-populated table x_df from the beginning - it was no longer required.
Although I thought the code needed to sit inside the observeEvent(event_data("plotly_selected") to function correctly, it did not - thankfully, because that was at the root of the issue. Instead, I used observeEvent(input$Add, { (which is the correct code to use as opposed to if(input$Add > 0)) to anchor the event to the click of the Add button.
The values <- reactiveValues() was placed outside the observeEvent() and an IF statement was used to either add the data to the values$df data frame on it's own if it was the first selection, or bind it to the existing saved data.
Here's the new code and a GIF demonstrating.
library(shiny)
library(readr)
library(DT)
library(dplyr)
library(plotly)
library(lubridate)
library(tidyr)
library(purrr)
library(htmlwidgets)
library(shinydashboard)
library(dashboardthemes)
library(shinyjs)
runApp(shinyApp(
ui=(fluidPage(
titlePanel("Event to Table"),
mainPanel(
fileInput(
inputId = "filedata",
label = "Upload data file (.csv)",
accept = c(".csv")),
plotlyOutput('myPlot'),br(),br(),br(),br(),
DTOutput("testing"), br(), br(),
fluidRow(
valueBoxOutput("starttime", width = 2),
valueBoxOutput("endtime", width = 2),
valueBoxOutput("maxvelocity", width = 2),
valueBoxOutput("timediff", width = 3),
valueBoxOutput("distance", width = 3)
),
useShinyjs(),
fluidRow(
div(style = "text-align:center", actionButton("Add", "Add Data to Table"),
downloadButton("export", "Export Table as .CSV"))), br(),
DTOutput(outputId = "table")))
),
server = (function(input, output, session) {
values <- reactiveValues(df_data = NULL)
data<-reactive({
req(input$filedata)
read.csv(input$filedata$datapath, header = TRUE)%>%
rename(Velocity = 'Speed..m.s.',
Player = 'Player.Display.Name',
Latitude = 'Lat',
Longtitude = 'Lon',
AccelImpulse = 'Instantaneous.Acceleration.Impulse',
HeartRate = 'Heart.Rate..bpm.')
})
observe({
thedata<-data()
updateSelectInput(session, 'y', choices = names(data))
})
output$myPlot = renderPlotly({
plot_ly(data = data(), x = ~Time, y = ~Velocity, height = 450,
marker =list(color = 'rgb(132,179,202)', size = 0.1),
line = list(color = 'rgb(132,179,202)', size = 0.1, width = 0.9),
type = 'scatter', mode = 'markers+lines') %>%
layout(dragmode = "select",
showlegend = F,
title = list(text = 'Velocity Trace', font = list(size = 20)),
xaxis = list(title = list(text = "", standoff = 0), nticks = 10),
yaxis = list(title = list(text = "Velocity (m/s)"), nticks = 5, gridcolor = "#46505a"),
font = list(color = 'black'),
margin = list(t = 70))
})
observeEvent(input$Add, {
event.data <- event_data("plotly_selected")
if (max(event.data$y) < 1.5) {
maxvel <- (max(event.data$y))
maxpos <- match(maxvel, event.data$y)
}
else {
filter1 <- filter (event.data, event.data$y > 1.5)
maxvel <- (max(filter1$y))
maxpos <- match(maxvel, event.data$y)
}
zero_val <- function(x) x == 0
zero_index <- event.data$y[1:maxpos] %>% detect_index(zero_val, .dir = "backward")
if (zero_index==0) {starttime <- event.data$x[1]}
else {starttime <- event.data$x[zero_index]}
endvel <- which.max(event.data$y)
endtime <- event.data$x[endvel]
timediff <- paste(today(), endtime) %>% as_datetime() - paste(today(), starttime) %>% as_datetime()
sprint <- as_tibble(event.data$y[zero_index:endvel])
ms <- as_tibble(rep(0.1, count(sprint)))
time_vel <- cbind(ms, sprint)
distance <- sum(time_vel[1]*time_vel[2])
sprintselect <- as_tibble(cbind(Start_time = starttime,
Time_at_peak = endtime,
Max_velocity = round(maxvel, 2),
Time_to_peak = round(timediff, 1),
Distance_to_peak = round(distance, 1)))
newLine <- isolate(data.frame(Start_time = sprintselect$Start_time, Time_at_peak = sprintselect$Time_at_peak,
Max_velocity = sprintselect$Max_velocity,
Time_to_peak = sprintselect$Time_to_peak,
Distance_to_peak = sprintselect$Distance_to_peak,
stringsAsFactors= FALSE))
if (is.null(values$df)){
values$df <- newLine}
else {
values$df <- isolate(rbind(values$df, newLine))}
output$testing <- renderDataTable({values$df})
})
})
))

Scatter mapbox in shiny R will not render

I have been working on this shiny app for a while and it all seems to work till i get to the end. It is supposed to output a interactive scatter plot. Well I can get the plot to the point that it has a legend and the hover text pops up on a white blank background, but i am missing the visual points and the map. Outside of shiny i can make the plotly work just fine and i get my mapbox map and scatter plots. I have tired quite a few things but am still failing to render the points and the map. Is there a quark in shiny holding my map back from rendering with the points that i am missing here?
I also am getting this error that goes away when i remove the size or color function from my plot.
Error:
Warning: `line.width` does not currently support multiple values.
Ui:
library(readxl)
library(plyr)
library(dplyr)
library(plotly)
library(readr)
library(RColorBrewer)
library(data.table)
library(shiny)
library(shinydashboard)
library(shinythemes)
library(leaflet)
library(DT)
library(xtable)
ui <- fluidPage(theme = shinytheme("slate"), mainPanel(
navbarPage(
"Permian Plots", collapsible = TRUE, fluid = TRUE,
navbarMenu(
"County Plot",
tabPanel( "Data Frame",
fluidRow(box(DT::dataTableOutput("contents"))),
sidebarPanel( fileInput(
'file1',
'Choose CSV File',
accept = c('text/csv', 'text/comma-separated-values,text/plain', '.csv')
),
tags$hr(),
checkboxInput('header', 'Header', TRUE),
# App buttons comma and quote
radioButtons('sep', 'Separator',
c(
Comma = ',',
Semicolon = ';',
Tab = '\t'
), ','),
radioButtons(
'quote',
'Quote',
c(
None = '',
'Double Quote' = '"',
'Single Quote' = "'"
),
'"'
))
),
tabPanel("County Plot", plotlyOutput(
"plotMap", height = 1000, width = 1400
),
actionButton("btn", "Plot")
)
)
)
)
)
Server:
server <- function(input, output, session) {
options(shiny.maxRequestSize = 1000*1024^2)
data_set <- reactive({
inFile <- input$file1
if (is.null(inFile)){
return()
}
data_set <- read.csv(
inFile$datapath,
header = input$header,
sep = input$sep,
quote = input$quote
)
})
output$contents <- DT::renderDT({
withProgress(message = 'loading...', value = 0.1, {
datatab <- datatable(data_set(),
options = list(
"pageLength" = 10,
scrollX = TRUE))
extensions = 'Responsive'
setProgress(1)
datatab
})
})
observeEvent(
input$btn,
{
output$plotMap <- renderPlotly({withProgress(message = 'Plotting...', value = 0.1,{
plots <- function(f1){
f1 <- as.data.frame(f1)
f1$Date <- as.POSIXct(f1$Date)
f1$CNorm <- f1$Cell.Sum..Norm.
f1$year <- format(as.POSIXct(f1$Date,format="%y-%m-%d"), "%y")
f1$month <- format(as.POSIXct(f1$Date,format="%y-%m-%d"), "%m")
f1$Cell <- as.factor(f1$Cell)
z <- f1 %>%
group_by(.dots = c("year", "month", "Cell")) %>%
dplyr::summarise(yearMonth_Max_sum = max(CNorm))
f1 <- inner_join(f1,z, by = c("year", "month", "Cell"))
f1$Changed <- as.numeric(as.factor(f1$Changed))
f1$Changed[f1$Changed == 1] <- 0
f1$Changed[f1$Changed == 2] <- 1
z <- f1 %>%
group_by(.dots = c("year", "month", "Cell")) %>%
dplyr::summarise(ChangedX = max(Changed))
f1 <- inner_join(f1,z, by = c("year", "month", "Cell"))
f1$MY <- paste(f1$year, f1$month, sep = "-")
#preapring data for plotly
q <- matrix(quantile(f1$StdDev))
f1$qunat <- NA
up <- matrix(quantile(f1$StdDev, probs = .95))
f1$qunat <- ifelse((f1$StdDev > q[4:4,1]) & (f1$StdDev < up[1,1]), 1, 0)
z <- group_by(f1, Cell) %>%
dplyr::summarize(Median_Cell = median(CNorm), na.rm = FALSE)
f1 <- inner_join(f1,z, by = c("Cell"))
f1$NewMedian <- NA
f1$NewMedian[f1$Median_Cell > 4000] <- 0
f1$NewMedian[f1$Median_Cell <= 4000] <- 1
f1$NewSum <- NA
f1$NewSum <- f1$yearMonth_Max_sum * f1$ChangedX * f1$qunat * f1$NewMedian
f1$hover <- with(f1,paste("Sum", f1$yearMonth_Max_sum, "/<br>",
"Standard Dev", f1$StdDev, "/<br>",
"Mean", f1$Average, "/<br>",
"Median", f1$Median_Cell, "/<br>",
"Changed", f1$ChangedX, "/<br>",
"Latitude", f1$Lat , "/<br>",
"Longitude", f1$Lon))
f1 <- f1[which(f1$yearMonth_Max_sum < 9000), ]
f1 <<- f1[!duplicated(f1$yearMonth_Max_sum), ]
##################
Sys.setenv('MAPBOX_TOKEN' = '')
Sys.getenv("MAPBOX_TOKEN")
plot <- f1 %>%
plot_mapbox(
lon = ~Lon,
lat = ~Lat,
size = ~yearMonth_Max_sum,
color = ~NewSum,
frame = ~MY,
type = 'scattermapbox',
mode = "markers",
colors = c("green","blue")
) %>%
add_markers(text = ~f1$hover) %>%
layout(title = "County Plot",
font = list(color = "black"),
mapbox = list(style = "satellite-streets", zoom = 9,
center = list(lat = median(f1$Lat),
lon = median(f1$Lon))))
return(plot)
}
plots(data_set())
})
})
}
)
}
shinyApp(ui = ui, server = server)

Displaying data in the chart based on plotly_click in R shiny

Please run this script below, the following R script gives a shiny dashboard with two boxes. I want to reduce the width between two boxes and display data in the right chart. The data should be based on the on click event that we see in the ggplotly function. Also plotly can be used to do the job, I guess. I want the code to fast and efficient at the same time.
## app.R ##
library(shiny)
library(shinydashboard)
library(bupaR)
library(eventdataR)
library(lubridate)
library(dplyr)
library(XML)
library(edeaR)
library(xml2)
library(data.table)
library(ggplot2)
library(ggthemes)
library(glue)
library(tibble)
library(miniUI)
library(tidyr)
library(shinyTime)
library(magrittr)
library(plotly)
library(DT)
library(splitstackshape)
library(scales)
patients$patient = as.character(patients$patient)
a1 = patients$patient
a2 = patients$handling
a3 = patients$time
a123 = data.frame(a1,a2,a3)
patients_eventlog = simple_eventlog(a123, case_id = "a1",activity_id = "a2",
timestamp = "a3")
dta <- reactive({
tr <- data.frame(traces(patients_eventlog, output_traces = T, output_cases =
F))
tr.df <- cSplit(tr, "trace", ",")
tr.df$af_percent <-
percent(tr.df$absolute_frequency/sum(tr.df$absolute_frequency))
pos <- c(1,4:ncol(tr.df))
tr.df <- tr.df[,..pos]
tr.df <- melt(tr.df, id.vars = c("trace_id","af_percent"))
tr.df
})
patients10 <- reactive({
patients11 <- arrange(patients_eventlog, a1)
patients12 <- patients11 %>% arrange(a1, a2,a3)
patients12 %>%
group_by(a1) %>%
mutate(time = as.POSIXct( a2, format = "%m/%d/%Y %H:%M"),diff_in_sec = a2 -
lag( a2)) %>%
mutate(diff_in_sec = ifelse(is.na(diff_in_sec),0,diff_in_sec)) %>%
mutate(diff_in_hours = as.numeric(diff_in_sec/3600)) %>%
mutate(diff_in_days = as.numeric(diff_in_hours/24))
})
ui <- dashboardPage(
dashboardHeader(title = "Trace Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Trace Chart", status = "primary",height = "455" ,solidHeader =
T,
plotlyOutput("trace_plot"),style = "height:420px; overflow-y:
scroll;overflow-x: scroll;"),
box( title = "Trace Summary", status = "primary", height = "455",solidHeader
= T,
dataTableOutput("trace_table"))
)
)
server <- function(input, output)
{
output$trace_plot <- renderPlotly({
mp1 = ggplot(data = dta(), aes(x = variable,y = trace_id, fill = value,
label = value,
text=paste("Variable:",variable,"<br> Trace
ID:",trace_id,"<br>
Value:",value,"<br> Actuals:",af_percent))) +
geom_tile(colour = "white") +
geom_text(colour = "white", fontface = "bold", size = 2) +
scale_fill_discrete(na.value="transparent") +
theme(legend.position="none") + labs(x = "Traces", y = "Activities")
ggplotly(mp1, tooltip=c("text"), height = 1226, width = 1205)
})
output$trace_table <- renderDataTable({
req(event_data("plotly_click"))
Values <- dta() %>%
filter(trace_id == event_data("plotly_click")[["y"]]) %>%
select(value)
valueText <- paste0(Values[[1]] %>% na.omit(),collapse = "")
agg <- aggregate(a3~a1, data = patients10(), FUN = function(y){paste0(unique(y),collapse = "")})
currentPatient <- agg$a1[agg$a3 == valueText]
patients10_final <- patients10() %>%
filter(a1 %in% currentPatient)
datatable(patients10_final, options = list(paging = FALSE, searching = FALSE))
})
}
shinyApp(ui, server)
I have created an easy example how You can use coupled events from plotly with some sample data that is close to Your needs:
library(shiny)
library(plotly)
library(DT)
set.seed(100)
data <- data.frame(A=sample(c('a1','a2','a3'),10,replace=T),
B=1:10,
C=11:20,
D=21:30)
shinyApp(
ui = fluidPage(
plotlyOutput("trace_plot"),
DT::dataTableOutput('tbl')),
server = function(input, output) {
output$trace_plot <- renderPlotly({
plot_ly(data, x=~A,y=~B,z=~C, source = "subset") %>% add_histogram2d()})
output$tbl <- renderDataTable({
event.data <- event_data("plotly_click", source = "subset")
if(is.null(event.data) == T) return(NULL)
print(event.data[ ,c(3:4)])
})
}
)
As You can see by pressing on the first plot we get the subset of data below in the table (x and y values), further you can use it to merge with the primary data to display timestamps etc. .

Displaying the table details from sankey chart in R shiny

The script below works on the patients data from bupaR package,and creates a sankey plot listing the relation between a resource from the "employee" column with the activity he is involved in from the "handling" column in the patients data. Besides the plot there is a data table available from DT which gives details of every sankey plot path when clicked. I want a functionality such that when I click on any path, say path connecting "r1" employee and "Registration" handling activity, I want all the rows from patients data with both these fields available in the plot besides, similarly for all other paths, this should be dynamic as I shall apply the functionality on larger datasets. Attaching the snapshot for reference. Thanks and please help.
## app.R ##
library(shiny)
library(shinydashboard)
library(devtools)
library(ggplot2)
library(plotly)
library(proto)
library(RColorBrewer)
library(gapminder)
library(stringr)
library(broom)
library(mnormt)
library(DT)
library(bupaR)
ui <- dashboardPage(
dashboardHeader(title = "Sankey Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader = T,
plotlyOutput("sankey_plot")),
box( title = "Case Summary", status = "primary", height = "455",solidHeader = T,
dataTableOutput("sankey_table"))
)
)
server <- function(input, output)
{
output$sankey_plot <- renderPlotly({
sankeyData <- patients %>%
group_by(employee,handling) %>%
count()
sankeyNodes <- list(label = c(sankeyData$employee,sankeyData$handling))
trace2 <- list(
domain = list(
x = c(0, 1),
y = c(0, 1)
),
link = list(
label = paste0("Case",1:nrow(sankeyData)),
source = sapply(sankeyData$employee,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
target = sapply(sankeyData$handling,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
value = sankeyData$n
),
node = list(label = sankeyNodes$label),
type = "sankey"
)
data2 <- list(trace2)
p <- plot_ly()
p <- add_trace(p, domain=trace2$domain, link=trace2$link,
node=trace2$node, type=trace2$type)
p
})
output$sankey_table <- renderDataTable({
d <- event_data("plotly_click")
d
})
}
shinyApp(ui, server)
Hi I interpreted the output from event_data as such that pointNumber is the index of the link but I might be wrong here. Any way this is my Solution and it works for this data
library(shiny)
library(shinydashboard)
library(devtools)
library(ggplot2)
library(plotly)
library(proto)
library(RColorBrewer)
library(gapminder)
library(stringr)
library(broom)
library(mnormt)
library(DT)
library(bupaR)
library(dplyr)
ui <- dashboardPage(
dashboardHeader(title = "Sankey Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader = T,
plotlyOutput("sankey_plot")),
box( title = "Case Summary", status = "primary", height = "455",solidHeader = T,
dataTableOutput("sankey_table"))
)
)
server <- function(input, output)
{
sankeyData <- reactive({
sankeyData <- patients %>%
group_by(employee,handling) %>%
count()
sankeyNodes <- list(label = c(sankeyData$employee,sankeyData$handling) %>% unique())
trace2 <- list(
domain = list(
x = c(0, 1),
y = c(0, 1)
),
link = list(
label = paste0("Case",1:nrow(sankeyData)),
source = sapply(sankeyData$employee,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
target = sapply(sankeyData$handling,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
value = sankeyData$n
),
node = list(label = sankeyNodes$label),
type = "sankey"
)
trace2
})
output$sankey_plot <- renderPlotly({
trace2 <- sankeyData()
p <- plot_ly()
p <- add_trace(p, domain=trace2$domain, link=trace2$link,
node=trace2$node, type=trace2$type)
p
})
output$sankey_table <- renderDataTable({
d <- event_data("plotly_click")
req(d)
trace2 <- sankeyData()
sIdx <- trace2$link$source[d$pointNumber+1]
Source <- trace2$node$label[sIdx + 1 ]
tIdx <- trace2$link$target[d$pointNumber+1]
Target <- trace2$node$label[tIdx+1]
patients %>% filter(employee == Source & handling == Target)
})
}
shinyApp(ui, server)
hope it helps!

ShinyApp errors: selectInput, data-subsetting

I am creating shiny app. My goal is to visualize some data slices depending on the input.I am quite happy with the result.
However, my app has a few bugs while the app is loading. Before ploting the graph and visualizing inputs it shows some errors on screen (you can lauch the app and see the problem).
I believe, the first problem is with data filtering. I can't figure out how to deal with it and what is the problem. May I need to use other method or maybe other package? (see the output$Brand).
Error in grep(pattern, levels(vector)) : invalid 'pattern' argument
The second error comes when I am creating selectInput. I'd like to visualize all the brands of the specific category in one plot and to have an option to filter data by brand. However, my method is not working well. Any suggestions? (see the output$Brand).
Error in if (input$Brand == "All") { : argument is of length zero
Also, I enclose the code, which you can generate.
May you have any more suggestions how to simplify the code?
Thanks for the help!
library(shiny)
library(shinydashboard)
library(data.table)
library(ggplot2)
library(grid)
library(scales)
library(ggthemes)
# Header -----------------------------------------------------------
header <- dashboardHeader(title="Dashboard")
# Sidebar --------------------------------------------------------------
sm <- sidebarMenu(
menuItem(
text="Graph1",
tabName="Graph1",
icon=icon("home")
)
)
sidebar <- dashboardSidebar(sm)
# Body --------------------------------------------------
body <- dashboardBody(
# Layout --------------------------------------------
tabItems(
tabItem(
tabName="Graph1",
fluidPage(
fluidRow(
box(
title = "Inputs", status = "warning", width = 2, solidHeader = TRUE,
uiOutput("Year"),
uiOutput("Category"),
uiOutput("Brand"),
sliderInput("Finalas.Range", "Months:",
min = 1, max = 12, value = c(1,12))
),
box(
title = "Season", width = 10, status = "info", solidHeader = TRUE,
plotOutput("Graph1")
)
)
)
)
)
)
# Setup Shiny app UI components -------------------------------------------
ui <- dashboardPage(header, sidebar, body, skin="black")
# Setup Shiny app back-end components -------------------------------------
server <- function(input, output) {
# Generate data --------------------------------------
set.seed(1992)
n=99
Year <- sample(2013:2015, n, replace = TRUE, prob = NULL)
Month <- sample(1:12, n, replace = TRUE, prob = NULL)
Category <- sample(c("Car", "Bus", "Bike"), n, replace = TRUE, prob = NULL)
Brand <- sample("Brand", n, replace = TRUE, prob = NULL)
Brand <- paste0(Brand, sample(1:14, n, replace = TRUE, prob = NULL))
USD <- abs(rnorm(n))*100
df <- data.frame(Year, Month, Category, Brand, USD)
# Inputs --------------------------------------
output$Year <- renderUI({
selectInput("Year",
"Year:",
c(unique(as.character(df$Year))), selected = "2015")
})
output$Category <- renderUI({
selectInput("Category", "Choose category:",
choices = c("Car","Bus", "Bike" ))
})
output$Brand <- renderUI({
df2 <- (data.table(df))[like(df$Category,input$Category)]
selectInput("Brand",
"Brand:",
c("All", unique(as.character(df2$Brand))))
})
# Plot --------------------------------
output$Graph1 <- renderPlot({
df <- data.table(df)
if (input$Brand == "All") {
df <- df[like(df$Year, input$Year)]
df <- df[like(df$Category,input$Category)]
ggplot(df, aes(x=factor(Month,levels=1:12), y=USD, fill=Brand))+
geom_bar(stat='identity')+
scale_x_discrete('Month', breaks=factor(1:12), drop=FALSE)+
scale_fill_gdocs(guide = guide_legend(title = "Brand"))
} else {
df <- df[like(df$Year, input$Year)]
df <- df[like(df$Category,input$Category)]
df <- df[which(df$Brand == input$Brand),]
validate(
need(sum(df$USD)>0, paste(input$Brand, "was inactive in Year:",input$Year))
)
ggplot(df, aes(x=factor(Month,levels=1:12), y=USD, fill=Brand))+
geom_bar(stat='identity')+
scale_x_discrete('Month', breaks=factor(1:12), drop=FALSE)
}
})
# -----------------------------------------------------------------------------
}
# Render Shiny app --------------------------------------------------------
shinyApp(ui, server)
The following should eliminate these errors: for #1 the function like in datatable gives out the error so I changed it to %in% instead. and for #2 you have a null as a default so take care of that with an if statement
rm(list = ls())
library(shiny)
library(shinydashboard)
library(data.table)
library(ggplot2)
library(grid)
library(scales)
library(ggthemes)
# Header -----------------------------------------------------------
header <- dashboardHeader(title="Dashboard")
# Sidebar --------------------------------------------------------------
sm <- sidebarMenu(
menuItem(
text="Graph1",
tabName="Graph1",
icon=icon("home")
)
)
sidebar <- dashboardSidebar(sm)
# Body --------------------------------------------------
body <- dashboardBody(
# Layout --------------------------------------------
tabItems(
tabItem(
tabName="Graph1",
fluidPage(
fluidRow(
box(
title = "Inputs", status = "warning", width = 2, solidHeader = TRUE,
uiOutput("Year"),
uiOutput("Category"),
uiOutput("Brand"),
sliderInput("Finalas.Range", "Months:",
min = 1, max = 12, value = c(1,12))
),
box(
title = "Season", width = 10, status = "info", solidHeader = TRUE,
plotOutput("Graph1")
)
)
)
)
)
)
# Setup Shiny app UI components -------------------------------------------
ui <- dashboardPage(header, sidebar, body, skin="black")
# Setup Shiny app back-end components -------------------------------------
server <- function(input, output) {
# Generate data --------------------------------------
set.seed(1992)
n=99
Year <- sample(2013:2015, n, replace = TRUE, prob = NULL)
Month <- sample(1:12, n, replace = TRUE, prob = NULL)
Category <- sample(c("Car", "Bus", "Bike"), n, replace = TRUE, prob = NULL)
Brand <- sample("Brand", n, replace = TRUE, prob = NULL)
Brand <- paste0(Brand, sample(1:14, n, replace = TRUE, prob = NULL))
USD <- abs(rnorm(n))*100
df <- data.frame(Year, Month, Category, Brand, USD)
# Inputs --------------------------------------
output$Year <- renderUI({
selectInput("Year",
"Year:",
c(unique(as.character(df$Year))), selected = "2015")
})
output$Category <- renderUI({
selectInput("Category", "Choose category:",
choices = c("Car","Bus", "Bike" ))
})
output$Brand <- renderUI({
# first error
#df2 <- (data.table(df))[like(df$Category,input$Category)]
df2 <- df[df$Category %in% input$Category,]
selectInput("Brand",
"Brand:",
c("All", unique(as.character(df2$Brand))))
})
# Plot --------------------------------
output$Graph1 <- renderPlot({
df <- data.table(df)
if(is.null(input$Brand) || is.na(input$Brand)){return()}
else if (input$Brand == "All") {
df <- df[like(df$Year, input$Year)]
df <- df[like(df$Category,input$Category)]
ggplot(df, aes(x=factor(Month,levels=1:12), y=USD, fill=Brand))+
geom_bar(stat='identity')+
scale_x_discrete('Month', breaks=factor(1:12), drop=FALSE)+
scale_fill_gdocs(guide = guide_legend(title = "Brand"))
} else {
df <- df[like(df$Year, input$Year)]
df <- df[like(df$Category,input$Category)]
df <- df[which(df$Brand == input$Brand),]
validate(
need(sum(df$USD)>0, paste(input$Brand, "was inactive in Year:",input$Year))
)
ggplot(df, aes(x=factor(Month,levels=1:12), y=USD, fill=Brand))+
geom_bar(stat='identity')+
scale_x_discrete('Month', breaks=factor(1:12), drop=FALSE)
}
})
# -----------------------------------------------------------------------------
}
# Render Shiny app --------------------------------------------------------
shinyApp(ui, server)

Resources