I created a shinyapp and there are three vital buttons.
The three buttons works well
And the click3 can output a plot and a table togather.
Now in my app they just refresh each other but only the table still stay each time.
My question is now I want to modify some parts, I hope:
plot1 and plot2 will not refresh click3(plot3 and table) and click3 will not refresh plot1 or plot2.
######### EDIT:2021-04-22 21:09:43
Sorry about that I didn't clarify my question.
Now p1(),p2(), myPlot can refresh each other.
But I hope myPlot and myTable can keep stay until new click3 refresh themself. p1() and p2() can refresh each other but will not affect myPlot and myTable
So that p1() or p2() could stay togather with myPlot and myTable in mainparnel.
My reproducible code and data here:
library(shiny)
library(ggplot2)
## load("04.21_3.RData")
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
sd_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(runif(1000, 5, 10), nrow = 20)
)
names(sd_data)[-1] <- c(paste0("Gene_", 1:50))
############
ui <- fluidPage(
sidebarPanel(
selectizeInput(
"selectGeneSymbol",
"Select:",
choices = NULL,
multiple =F,
width = 400,
selected = NULL,
options = list(placeholder = 'e.g. gene here',create = F)
),
actionButton("plot1", "click1"),
actionButton("plot2", "click2"),
actionButton("dataTable", "click3")
),
mainPanel(
uiOutput("all"),
# plotOutput("myPlot"),
tableOutput("myTable")
)
)
server <- function(input, output, session) {
updateSelectizeInput(session, "selectGeneSymbol", choices = colnames(mean_data[,-1]), server = TRUE)
global <- reactiveValues(out = NULL,
p1 = NULL,
p2 = NULL)
plotdata <- eventReactive(input$plot1,{
df <- mean_data %>% mutate(sd = sd_data[,input$selectGeneSymbol])
})
output$all <- renderUI({ ##
global$out
})
observeEvent(input$plot1, {
global$out <- plotOutput("plot1")
})
##
observeEvent(input$plot2, {
global$out <- plotOutput("plot2")
myData(NULL)
})
observeEvent(input$dataTable, {
global$out <- plotOutput("myPlot")
myData(NULL)
})
####
myPlot = reactiveVal()
myData = reactiveVal()
observeEvent(input$dataTable, {
data_cor<-mean_data[,-1]
tm <- corr.test(data_cor[,input$selectGeneSymbol,drop=FALSE],
y = data_cor, use = "pairwise", "spearman", adjust="none",
alpha=0.05, ci=F, minlength=5)
res <-setNames(as.data.frame(t(do.call(rbind, tm[c("r", "p")]))), c("Correlation", "P_value"))
res<-res[-which(rownames(res)== input$selectGeneSymbol),]
res<-data.frame(Gene=rownames(res),res)
res
##############
data_correlation=t(mean_data[, -1])
data_subset=data_correlation[c(input$selectGeneSymbol, as.vector(head(res$Gene, 10))), ]
myPlot(
pheatmap(log2(data_subset+1), show_colnames = F,fontsize_row =12,
cluster_rows = F, cluster_cols = F, gaps_row = 1)
)
myData(res)
})
output$myPlot = renderPlot({
myPlot()
})
output$myTable = renderTable({
myData()
})
####
p1 <- eventReactive(input$plot1,
{
ggplot(data =plotdata(), aes(x = Name, y = .data[[as.name(input$selectGeneSymbol)]])) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
theme(legend.position = "none") +
labs(title = paste(input$selectGeneSymbol), x = NULL, y = "666666") })
p2 <- eventReactive(input$plot2,
{
ggplot(data = plotdata(), aes(x = Name, y = .data[[as.name(input$selectGeneSymbol)]], fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
theme(legend.position = "none") +
labs(title = paste(input$selectGeneSymbol), x = NULL, y = "777777") })
output$plot1 <- renderPlot({
p1()})
output$plot2 <- renderPlot({
p2()})
}
shinyApp(ui, server)
Perhaps this is your expectation
library(shiny)
library(ggplot2)
## load("04.21_3.RData")
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
sd_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(runif(1000, 5, 10), nrow = 20)
)
names(sd_data)[-1] <- c(paste0("Gene_", 1:50))
############
ui <- fluidPage(
sidebarPanel(
selectizeInput(
"selectGeneSymbol",
"Select:",
choices = NULL,
multiple =F,
width = 400,
selected = NULL,
options = list(placeholder = 'e.g. gene here',create = F)
),
actionButton("plot1", "click1"),
actionButton("plot2", "click2"),
actionButton("dataTable", "click3")
),
mainPanel(
uiOutput("all"),
plotOutput("myPlot"),
tableOutput("myTable")
)
)
server <- function(input, output, session) {
updateSelectizeInput(session, "selectGeneSymbol", choices = colnames(mean_data[,-1]), server = TRUE)
global <- reactiveValues(out = NULL,
p1 = NULL,
p2 = NULL)
plotdata <- eventReactive(input$plot1,{
df <- mean_data %>% mutate(sd = sd_data[,input$selectGeneSymbol])
})
output$all <- renderUI({ ##
global$out
})
observeEvent(input$plot1, {
global$out <- plotOutput("plot1")
#myData(NULL)
})
##
observeEvent(input$plot2, {
global$out <- plotOutput("plot2")
#myData(NULL)
})
# observeEvent(input$dataTable, {
# global$out <- plotOutput("myPlot")
#
# })
####
myPlot = reactiveVal()
myData = reactiveVal()
observeEvent(input$dataTable, {
# data_cor<-mean_data[,-1]
# tm <- corr.test(data_cor[,input$selectGeneSymbol,drop=FALSE],
# y = data_cor, use = "pairwise", "spearman", adjust="none",
# alpha=0.05, ci=F, minlength=5)
# res <-setNames(as.data.frame(t(do.call(rbind, tm[c("r", "p")]))), c("Correlation", "P_value"))
# res<-res[-which(rownames(res)== input$selectGeneSymbol),]
# res<-data.frame(Gene=rownames(res),res)
# res
# ##############
# data_correlation=t(mean_data[, -1])
# data_subset=data_correlation[c(input$selectGeneSymbol, as.vector(head(res$Gene, 10))), ]
# myPlot(
# pheatmap(log2(data_subset+1), show_colnames = F,fontsize_row =12,
# cluster_rows = F, cluster_cols = F, gaps_row = 1)
# )
# myData(res)
myData(mtcars)
})
p3 <- eventReactive(input$dataTable, {
hist(runif(500))
})
output$myPlot = renderPlot({
p3()
#myPlot()
})
output$myTable = renderTable({
myData()
})
####
p1 <- eventReactive(input$plot1,
{
ggplot(data =plotdata(), aes(x = Name, y = .data[[as.name(input$selectGeneSymbol)]])) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
theme(legend.position = "none") +
labs(title = paste(input$selectGeneSymbol), x = NULL, y = "666666") })
p2 <- eventReactive(input$plot2,
{
ggplot(data = plotdata(), aes(x = Name, y = .data[[as.name(input$selectGeneSymbol)]], fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
theme(legend.position = "none") +
labs(title = paste(input$selectGeneSymbol), x = NULL, y = "777777") })
output$plot1 <- renderPlot({
p1()})
output$plot2 <- renderPlot({
p2()})
}
shinyApp(ui, server)
Related
I created a shinyapp and there are three vital buttons.
The three buttons works well
And the click3 can output a plot and a table togather.
Now I met a problem that plot1, plot2 and plot3(plot3 and the heatmap output togather) can refresh each other ideally.But it works doesn't look like that.
The output table always keep stay there no matter click1 or click2 clicked.
I tried modifying my code but it didn't work.
I hope somebody could give me some advice that the table will diappear with the heatmpa no matter which button clicked.
My reproducible code and data here:
library(shiny)
library(ggplot2)
## load("04.21_3.RData")
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
sd_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(runif(1000, 5, 10), nrow = 20)
)
names(sd_data)[-1] <- c(paste0("Gene_", 1:50))
############
ui <- fluidPage(
sidebarPanel(
selectizeInput(
"selectGeneSymbol",
"Select:",
choices = NULL,
multiple =F,
width = 400,
selected = NULL,
options = list(placeholder = 'e.g. gene here',create = F)
),
actionButton("plot1", "click1"),
actionButton("plot2", "click2"),
actionButton("dataTable", "click3")
),
mainPanel(
uiOutput("all"),
# plotOutput("myPlot"),
tableOutput("myTable")
)
)
server <- function(input, output, session) {
updateSelectizeInput(session, "selectGeneSymbol", choices = colnames(mean_data[,-1]), server = TRUE)
global <- reactiveValues(out = NULL,
p1 = NULL,
p2 = NULL)
plotdata <- eventReactive(input$plot1,{
df <- mean_data %>% mutate(sd = sd_data[,input$selectGeneSymbol])
})
output$all <- renderUI({ ##
global$out
})
observeEvent(input$plot1, {
global$out <- plotOutput("plot1")
})
##
observeEvent(input$plot2, {
global$out <- plotOutput("plot2")
})
observeEvent(input$dataTable, {
global$out <- plotOutput("myPlot")
})
####
myPlot = reactiveVal()
myData = reactiveVal()
observeEvent(input$dataTable, {
data_cor<-mean_data[,-1]
tm <- corr.test(data_cor[,input$selectGeneSymbol,drop=FALSE],
y = data_cor, use = "pairwise", "spearman", adjust="none",
alpha=0.05, ci=F, minlength=5)
res <-setNames(as.data.frame(t(do.call(rbind, tm[c("r", "p")]))), c("Correlation", "P_value"))
res<-res[-which(rownames(res)== input$selectGeneSymbol),]
res<-data.frame(Gene=rownames(res),res)
res
##############
data_correlation=t(mean_data[, -1])
data_subset=data_correlation[c(input$selectGeneSymbol, as.vector(head(res$Gene, 10))), ]
myPlot(
pheatmap(log2(data_subset+1), show_colnames = F,fontsize_row =12,
cluster_rows = F, cluster_cols = F, gaps_row = 1)
)
myData(res)
})
output$myPlot = renderPlot({
myPlot()
})
output$myTable = renderTable({
myData()
})
####
p1 <- eventReactive(input$plot1,
{
ggplot(data =plotdata(), aes(x = Name, y = .data[[as.name(input$selectGeneSymbol)]])) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
theme(legend.position = "none") +
labs(title = paste(input$selectGeneSymbol), x = NULL, y = "666666") })
p2 <- eventReactive(input$plot2,
{
ggplot(data = plotdata(), aes(x = Name, y = .data[[as.name(input$selectGeneSymbol)]], fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
theme(legend.position = "none") +
labs(title = paste(input$selectGeneSymbol), x = NULL, y = "777777") })
output$plot1 <- renderPlot({
p1()})
output$plot2 <- renderPlot({
p2()})
}
shinyApp(ui, server)
Try this
observeEvent(input$plot1, {
global$out <- plotOutput("plot1")
myData(NULL)
})
observeEvent(input$plot2, {
global$out <- plotOutput("plot2")
myData(NULL)
})
Here is my sample data:
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
The column is Gene sets.
I mean when I input one gene and the click the actionbutton, the barplot will appear but I tried several times it doesn't work.
My code here:
library(shiny)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gridExtra)
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
sd_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(runif(1000, 5, 10), nrow = 20)
)
names(sd_data)[-1] <- c(paste0("Gene_", 1:50))
###
ui <- fluidPage(
pageWithSidebar(
headerPanel("123"),
sidebarPanel(
selectInput(
"selectGeneSymbol",
"123:",
choices = colnames(mean_data)[-1],
multiple =F,
width = 400,
selected = 1
),
actionButton(inputId = "plot1", label = "FPKM"),
),
mainPanel(
uiOutput("all")
)
)
)
server <- function(input, output, session) {
plot_data1 <- reactive({
subset(mean_data, colnames(mean_data)[-1] %in% input$selectGeneSymbol)
})
global <- reactiveValues(out = NULL)
observeEvent(input$plot1, {
global$out <- plotOutput("plot1", height=500)
})
output$all <- renderUI({
global$out
})
p1 <- eventReactive(list(input$plot1,
input$all), {
ggplot(data = mean_data, aes(x = mean_data$Name, y = mean_data[,input$selectGeneSymbol],fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
geom_errorbar(aes(ymin = mean_data[,input$selectGeneSymbol] - sd_data[,input$selectGeneSymbol], ymax = mean_data[,input$selectGeneSymbol] + sd_data[,input$selectGeneSymbol]), width = .2, position = position_dodge(0.9)) +
theme_classic2() +
rotate_x_text(angle = 45) +
theme(legend.position = "none") +
labs(title = input$selectGeneSymbol, x = NULL, y = "123_value")
})
output$plot1 <- renderPlot({ p1() })
output$plot3 <- renderPlot({ grid.arrange(p1(),p2(), ncol=1) })
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
I combined mean_data and sd_data before and it works well.
Now I use both of them and choose the column of mean_data as the input but the actionbutton doesn't work .The barplot always appear before clicking the button.
I tried several times but I don't know where the code I have to change.
It appears that errorbar reacts instantly if you keep sd in a separate dataframe. Once you put sd into mean_data it works as desired.
library(shiny)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gridExtra)
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
sd_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(runif(1000, 5, 10), nrow = 20)
)
names(sd_data)[-1] <- c(paste0("Gene_", 1:50))
###
ui <- fluidPage(
pageWithSidebar(
headerPanel("123"),
sidebarPanel(
selectInput(
"selectGeneSymbol",
"123:",
choices = colnames(mean_data)[-1],
multiple =F,
width = 400,
selected = 1
),
actionButton(inputId = "plot1", label = "FPKM"),
),
mainPanel(
plotOutput("plot")
#uiOutput("all")
)
)
)
server <- function(input, output, session) {
## put sd into mean_data
plotdata <- eventReactive(input$plot1, {
df <- mean_data %>% mutate(sd = sd_data[,input$selectGeneSymbol])
})
p1 <- eventReactive(input$plot1, {
req(plotdata())
ggplot(data = plotdata(), aes(x = Name, y = .data[[as.name(input$selectGeneSymbol)]], fill=Name,
ymin = .data[[as.name(input$selectGeneSymbol)]] - sd, ymax = .data[[as.name(input$selectGeneSymbol)]] + sd )) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
# geom_errorbar(aes(ymin = plotdata()[,input$selectGeneSymbol] - sddata()[,input$selectGeneSymbol], ymax = plotdata()[,input$selectGeneSymbol] + sddata()[,input$selectGeneSymbol]), width = .2, position = position_dodge(0.9)) +
geom_errorbar(width = .2, position = position_dodge(0.9)) +
theme_classic2() +
rotate_x_text(angle = 45) +
theme(legend.position = "none") +
labs(title = paste(input$selectGeneSymbol), x = NULL, y = "123_value")
})
output$plot <- renderPlot({
p1()
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
so I have recently adapted some code that I found on StackOverflow to create a dynamic number of plots based on user input. However, I now cannot figure out how to save all of those dynamic plots in one file; when I use ggsave() in downloadHandler, it only saves the last plot generated, as the plots are created inside of a for loop, inside of an observe function. I have tried saving the for loop as a separate function and saving that instead of last plot, I have tried saving the observe() as a function and calling that inside ggsave(), but nothing works. Any idea how I can save all of the generated plots to one file?
ui <- fluidPanel(
sidebarLayout(
sidebarPanel(
#this is the input widget for dataset selection
selectInput(inputId = "dataset_selec",
label = "Choose which Dataset to explore:",
choices = list("NK AD Dataset (Zhang, 2020)",
"APPPS1 Dataset (Van Hove, 2019)",
"Aging T Cell Dataset (Dulken, 2019)"),
selected = "APPPS1 Dataset (Van Hove, 2019)"))
mainPanel(
fluidRow(
column(4,
textInput(inputId = "gene_fp",
label = "Enter gene(s) of interest here, separated by commas: ")
),
column(4,
br(),
checkboxInput("split_fp", "Split the graph?")
),
column(4,
conditionalPanel(condition = "input.split_fp == true",
#display choices to split by
selectInput(inputId = "metadata_split_fp",
label = "Choose how to split the Seurat data: ",
choices = list("Genotype", "Timepoint")))
)
),
#ask users if they want to split the graphs
br(),
fluidRow(
column(4,
textInput("save_name_fp",
label = "Enter a file name: ")
),
column(4,
conditionalPanel(condition = "input.save_name_fp.length > 0",
selectInput("fp_device",
label = "Select file type: ",
choices = list("PNG", "JPEG", "PDF", "TIFF",
"BMP", "SVG")))
),
column(4,
br(),
conditionalPanel(condition = "input.save_name_fp.length > 0",
downloadButton("fp_save", label = "Save Feature Plot"))
)
),
#plot the actual plot
uiOutput("fp_plots")
)
)
)
server <- function(input, output, session) {
datasetInput <- reactive({
switch(input$dataset_selec,
"NK AD Dataset (Zhang, 2020)" = nk_data,
"APPPS1 Dataset (Van Hove, 2019)" = appps1_data,
"Aging T Cell Dataset (Dulken, 2019)" = tcellinfil_data)
})
output$fp_plots <- renderUI({
#validate is to prevent an error message from being displayed when a gene hasn't been entered yet
validate(
need(input$gene_fp !="", "Please enter a gene.")
)
fp_genes <- input$gene_fp
fp_genes <- gsub(" ", "", fp_genes)
fp_genes <- unlist(strsplit(fp_genes, split = ","))
n <- length(fp_genes)
plot_output_list <- lapply(1:n, function(i) {
plotname <- paste("plot", i, sep = "")
if (input$split_fp == TRUE) {plotOutput(plotname, height = 580, width = 1100)}
else {plotOutput(plotname, height = 580, width = 550)}
})
do.call(tagList, plot_output_list)
})
#Here, we take the input of genes, and turn it into a character vector, so that we can iterate
#over it. This needs to be under observe({}) because it involves an input.
#Next, we iterate through the list of genes using a for loop, and within that for loop we assign
#the plots that we want to be displayed to each plotname, which is also sequentially created within
#this for loop, and assign it to the tagList we generated earlier. Basically, we're adding objects to
#list of names we made earlier.
#This needs to be under local({}) control, otherwise each graph doesn't get its own number,
#because of when renderPlot is evaluated
observe({
fp_genes <- input$gene_fp
fp_genes <- gsub(" ", "", fp_genes)
fp_genes <- unlist(strsplit(fp_genes, split = ","))
for (i in 1:length(fp_genes)) {
local({
plotname <- paste("plot", i, sep = "")
gene <- fp_genes[i]
output[[plotname]] <- renderPlot({
if (input$split_fp == TRUE) {FeaturePlot(datasetInput(), features = gene, split.by = input$metadata_split_fp)}
else {FeaturePlot(datasetInput(), features = gene)}
})
})
}
})
output$fp_save <- downloadHandler(
filename = function() {
paste(input$save_name_fp, tolower(input$fp_device), sep = ".")
},
content = function(file) {
ggsave(file, device = tolower(input$fp_device))
}
)
}
Create a list of plots, use grid.arrange to save it in a format you wish, and then save it. Perhaps you can adapt this code.
library(shiny)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gridExtra)
mean_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(sample(1:1000, 1000, replace = T), nrow = 20)
)
names(mean_data)[-1] <- c(paste0("Gene_", 1:50))
sd_data <- data.frame(
Name = c(paste0("Group_", LETTERS[1:20])),
matx <- matrix(runif(1000, 5, 10), nrow = 20)
)
names(sd_data)[-1] <- c(paste0("Gene_", 1:50))
# Prepare dataset.
# 1. Bind mean and sd data
# 2. Reshape
data <- bind_rows(list(
mean = mean_data,
sd = sd_data
), .id = "stat")
data_mean_sd1 <- data %>%
pivot_longer(-c(Name, stat), names_to = "Gene", values_to = "value") %>%
pivot_wider(names_from = "stat", values_from = "value")
###
ui <- fluidPage(
pageWithSidebar(
headerPanel("Gene_FPKM Value Barplot"),
sidebarPanel(
selectInput(
"selectGeneSymbol",
"Select Gene Symbol:",
choices = unique(data_mean_sd1$Gene),
multiple =F,
width = 400,
selected = 1 #"Igfbp7"
),
selectInput(
"selectGeneSymbol2",
"Select Gene Symbol2:",
choices = unique(data_mean_sd1$Gene),
multiple =F,
width = 400,
selected = 1 #"Igfbp7"
),
selectInput("fp_device",
label = "Select file type: ",
choices = list("PNG", "JPEG", "PDF", "TIFF","BMP", "SVG")
),
actionButton(inputId = "plot1", label = "FPKM"),
actionButton(inputId = "plot2", label = "logFC"),
actionButton(inputId = "all",label = "logFC&FPKM"),br(),
downloadButton("fp_save", label = "Save Feature Plot")
),
mainPanel(
uiOutput("all")
)
)
)
server <- function(input, output, session) {
plot_data1 <- reactive({
subset(data_mean_sd1, Gene %in% input$selectGeneSymbol)
})
plot_data2 <- reactive({
subset(data_mean_sd1, Gene %in% input$selectGeneSymbol2)
})
global <- reactiveValues(out = NULL)
observeEvent(input$plot1, {
global$out <- plotOutput("plot1", height=750)
})
observeEvent(input$plot2, {
global$out <- plotOutput("plot2", height=750)
})
observeEvent(input$all, {
global$out <- plotOutput("plot3", height=1150)
})
output$all <- renderUI({
global$out
})
p1 <- eventReactive(list(input$plot1,
input$all), {
ggplot(data = plot_data1(), aes(x = Name, y = mean,fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = .2, position = position_dodge(0.9)) +
theme_classic2() +
rotate_x_text(angle = 45) +
theme(legend.position = "none") +
labs(title = input$selectGeneSymbol, x = NULL, y = "FPKM_value") +
theme(plot.title = element_text(hjust = 0.5)) +
theme(plot.margin = unit(c(20, 5, 1, 5), "mm"))+
theme(axis.text.x=element_text(vjust=1,size=12))
})
p2 <- eventReactive(list(input$plot2,
input$all), {
ggplot(data = plot_data2(), aes(x = Name, y = mean,fill=Name)) +
geom_bar(stat = "identity", position = position_dodge(0.9), width = 0.9) +
geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = .2, position = position_dodge(0.9)) +
theme_classic2() +
rotate_x_text(angle = 45) +
theme(legend.position = "none") +
labs(title = input$selectGeneSymbol2, x = NULL, y = "FPKM_value") +
theme(plot.title = element_text(hjust = 0.5)) +
theme(plot.margin = unit(c(20, 5, 1, 5), "mm"))+
theme(axis.text.x=element_text(vjust=1,size=12))
})
#plotlist <- do.call(tagList, list(p1(),p2()))
output$plot1 <- renderPlot({ p1() })
output$plot2 <- renderPlot({ p2() })
output$plot3 <- renderPlot({ grid.arrange(p1(),p2(), ncol=1) })
observe({
plots <- list(p1(),p2())
myplots <- do.call(grid.arrange, c(plots, ncol = 1))
output$fp_save <- downloadHandler(
filename = function() {
paste("myplots", tolower(input$fp_device), sep = ".")
},
content = function(file) {
ggsave(file, plot=myplots, device = tolower(input$fp_device))
}
)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
I am trying to use a logical vector from a reactive expression. This generates an error in a function xor() when I try to perform a logical operation on this vector in another reactive expression. I would like to generate a reactive expression (logical vector), and then use it in another reactive function. A toy example below. The error appears when points on the plot are clicked.
In the original here, keeprows() is not reactive, but I would like to make this structured as on the schematic below (from Shiny website). The fist object is input for a reactive expression, and then a second (reactive) object (which is a user-subsetted table) is used for point selection, etc. The elements after bifurcation are the tables with the kept and excluded points. I have a problem in making this last subsetting to work.
Could someone explain to me the root of this problem?
library(ggplot2)
library(shiny)
library(dplyr)
ui <- fluidPage(
fluidRow(
column(width = 6,
plotOutput("plot1", height = 350,
click = "plot1_click",
brush = brushOpts(
id = "plot1_brush"
)
),
actionButton("exclude_toggle", "Toggle points"),
sliderInput(inputId = "efficiency", value = 20, label = "MPG", min = min(mtcars$mpg), max = max(mtcars$mpg))
)
)
)
server <- function(input, output) {
# For storing which rows have been excluded
mt_subset <- reactive(mtcars %>% filter(mpg > input$efficiency))
vals <- reactiveValues()
vals$keeprows <- reactive(rep(TRUE, nrow(mt_subset()), label = "TuProblem", quoted = FALSE))
output$plot1 <- renderPlot({
# Plot the kept and excluded points as two separate data sets
keep <- mt_subset()[ vals$keeprows(), , drop = FALSE]
exclude <- mt_subset()[!vals$keeprows(), , drop = FALSE]
ggplot(keep, aes(wt, mpg)) + geom_point() +
geom_smooth(method = lm, fullrange = TRUE, color = "black") +
geom_point(data = exclude, shape = 21, fill = NA, color = "black", alpha = 0.25) +
coord_cartesian(xlim = c(1.5, 5.5), ylim = c(5,35))
})
# Toggle points that are clicked
observeEvent(input$plot1_click, {
res <- nearPoints(mt_subset(), input$plot1_click, allRows = TRUE)
vals$keeprows <- xor(as.logical(vals$keeprows()), as.logical(res$selected_))
})
# Toggle points that are brushed, when button is clicked
observeEvent(input$exclude_toggle, {
res <- brushedPoints(mt_subset(), input$plot1_brush, allRows = TRUE)
vals$keeprows <- xor(vals$keeprows(), res$selected_)
})
}
shinyApp(ui, server)
I'm not sure if this is the output you're looking for, but this code reads in a local file and then performs the brushing point selection, greying out the brushed points after "toggle points" is hit and also adjusting the correlation.
library(ggplot2)
library(Cairo) # For nicer ggplot2 output when deployed on Linux
library(shiny)
library(readxl)
data(iris)
write.xlsx(x = iris, file = "iris.xlsx")
ui <- fluidPage(
fluidRow(
fileInput(inputId = "file",
label = "Load file"),
column(width = 6,
plotOutput("plot1", height = 350,
click = "plot1_click",
brush = brushOpts(
id = "plot1_brush"
)
),
actionButton("exclude_toggle", "Toggle points"),
actionButton("exclude_reset", "Reset")
)
)
)
server <- function(input, output) {
# Get file
getFile <- reactive({ if (is.null(input$file)) {
return(NULL)
} else {
return(input$file)
}})
# Read data
data <- reactive({ if (is.null(getFile())) {
return(NULL)
} else {
as.data.frame(read_excel(getFile()$datapath))
}})
# For storing which rows have been excluded
vals <- reactiveValues()
observeEvent(data(), {
vals$keeprows <- rep(T, nrow(data()))
})
# Toggle points that are clicked
observeEvent(input$plot1_click, {
res <- nearPoints(data(), input$plot1_click, allRows = TRUE)
vals$keeprows <- xor(vals$keeprows, res$selected_)
})
# Toggle points that are brushed, when button is clicked
observeEvent(input$exclude_toggle, {
res <- brushedPoints(data(), input$plot1_brush, allRows = TRUE)
vals$keeprows <- xor(vals$keeprows, res$selected_)
})
# Reset all points
observeEvent(input$exclude_reset, {
vals$keeprows <- rep(TRUE, nrow(data()))
})
output$plot1 <- renderPlot({
if (is.null(data())) {
return(NULL)
} else {
# Indices for keep and exclude
keep_v <- which(vals$keeprows)
exclude_v <- which(!vals$keeprows)
# Subset data
keep <- data()[keep_v, , drop = F]
exclude <- data()[exclude_v, , drop = F]
ggplot(keep, aes(Sepal.Length, Sepal.Width)) + geom_point() +
geom_smooth(method = lm, fullrange = TRUE, color = "black") +
geom_point(data = exclude, shape = 21, fill = NA, color = "black", alpha = 0.25)
}
})
}
shinyApp(ui, server)
Solved:
library(ggplot2)
library(shiny)
library(dplyr)
ui <- fluidPage(
fluidRow(
column(width = 6,
plotOutput("plot1", height = 350,
click = "plot1_click",
brush = brushOpts(
id = "plot1_brush"
)
),
actionButton("exclude_toggle", "Toggle points"),
sliderInput(inputId = "efficiency", value = 20, label = "MPG", min = min(mtcars$mpg), max = max(mtcars$mpg))
)
)
)
server <- function(input, output) {
mt_subset <- reactive(mtcars %>% filter(mpg > input$efficiency))
vals <- reactiveValues()
observeEvent(mt_subset(), {
vals$keeprows <- rep(TRUE, nrow(mt_subset()), label = "TuProblem", quoted = FALSE)
})
output$plot1 <- renderPlot({
# Plot the kept and excluded points as two separate data sets
keep <- mt_subset()[ vals$keeprows, , drop = FALSE]
exclude <- mt_subset()[!vals$keeprows, , drop = FALSE]
ggplot(keep, aes(wt, mpg)) + geom_point() +
geom_smooth(method = lm, fullrange = TRUE, color = "black") +
geom_point(data = exclude, shape = 21, fill = NA, color = "black", alpha = 0.25) +
coord_cartesian(xlim = c(1.5, 5.5), ylim = c(5,35))
})
observeEvent(input$plot1_click, {
res <- nearPoints(mt_subset(), input$plot1_click, allRows = TRUE)
vals$keeprows <- xor(vals$keeprows, res$selected_)
})
observeEvent(input$exclude_toggle, {
res <- brushedPoints(mt_subset(), input$plot1_brush, allRows = TRUE)
vals$keeprows <- xor(vals$keeprows, res$selected_)
})
}
shinyApp(ui, server)
I have a shiny app, example shown below that should be reproducible where I am trying to show a ggplot2 scatterplot with points which can be excluded as shown in this example here. I am also using modules, which might be part of this issue here.
https://gallery.shinyapps.io/106-plot-interaction-exclude/
I keep getting this "Error in eval: object 'xaxis' not found" message. Any ideas? I put the module code up front then the rest of the code for the app.R file.
library(ggplot2)
library(scales)
library(shiny)
library(shinydashboard)
###### MODULE CODE ###############
scatter_graphUI <- function(id, tab_panel_name, height = "500px") {
ns <- NS(id)
tabPanel(tab_panel_name,
plotOutput(ns("scatter_1"), height = height, click = "plot1_click", brush =
brushOpts(id = "plot1_brush")),
actionButton(ns("exclude_toggle"), "Toggle points"),
actionButton(ns("exclude_reset"), "Reset")
)
}
scatter_graph <- function(input, output, session, scatter_data, col_select) {
scatter_data_df <- reactive({
mtcars
})
vals <- reactiveValues()
data_df <- reactive({
scatter_df <- scatter_data_df()
main_df <- scatter_df[,col_select]
vals$keeprows = rep(TRUE,nrow(main_df))
main_df
})
output$scatter_1 <- renderPlot({
graph_df <- data_df()
# Plot the kept and excluded points as two separate data sets
keep <- graph_df[ vals$keeprows,]
exclude <- graph_df[!vals$keeprows,]
final_df <- keep
title = paste(colnames(final_df)[1], "vs", colnames(final_df)[2])
line_method = "quad"
axis_text = 12
title_text = 16
split_colors = TRUE
colors = c("red","black")
# create red points for negative x axis returns if split_colors is TRUE
if (split_colors == TRUE) {
final_df[,"color"] <- ifelse(final_df[,2,drop=F]<0,colors[1],colors[2])
} else {
final_df[,"color"] <- ifelse(final_df[,2,drop=F]<0,colors[2],colors[2])
}
# create a generic graphing final_df
colnames(final_df) <- c("xaxis","yaxis","color")
# setup the graph
gg <- ggplot(final_df, aes(x = xaxis, y = yaxis)) + geom_point(color = final_df[,"color"])
gg <- gg + geom_point(data = exclude, shape = 21, fill = NA, color = "black", alpha = 0.25) +
coord_cartesian(xlim = c(1.5, 5.5), ylim = c(5,35))
if (line_method == "loess") {
gg <- gg + stat_smooth(span = 0.9)
} else if (line_method == "quad") {
gg <- gg + stat_smooth(method = "lm", formula = y ~ poly(x, 2), size = 1)
} else if (line_method == "linear") {
gg <- gg + stat_smooth(method = "lm")
} else {
}
gg <- gg + theme_bw()
gg <- gg + labs(x = colnames(final_df)[2], y = colnames(final_df)[3], title = title)
gg
})
# Toggle points that are clicked
observeEvent(input$plot1_click, {
main_df <- data_df()
res <- nearPoints(main_df, input$plot1_click, allRows = TRUE)
vals$keeprows <- xor(vals$keeprows, res$selected_)
})
# Toggle points that are brushed, when button is clicked
observeEvent(input$exclude_toggle, {
main_df <- data_df()
res <- brushedPoints(main_df, input$plot1_brush, allRows = TRUE)
vals$keeprows <- xor(vals$keeprows, res$selected_)
})
# Reset all points
observeEvent(input$exclude_reset, {
main_df <- data_df()
vals$keeprows <- rep(TRUE, nrow(main_df))
})
}
########################################
##### REST OF APP CODE ######
header <- dashboardHeader(
title = 'Test Dashboard'
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "scatter_eval",
tabBox(
title = "Scatter",
selected = "Selected",
height = "600px", side = "right",
scatter_graphUI("selected_scatter", "Selected")
)
)
)
)
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Scatter Evaluation", icon = icon("th"), tabName = "scatter_eval")
)
)
ui <- dashboardPage(skin = "blue",
header,
sidebar,
body
)
server <- function(input, output, session) {
callModule(scatter_graph, id ="selected_scatter", scatter_data = reactive(selected_scatter_data()),
col_select = c(1,2))
}
shinyApp(ui = ui, server = server)
########
The issue is the two lines:
gg <- ggplot(final_df, aes(x = xaxis, y = yaxis)) + geom_point(color = final_df[,"color"])
gg <- gg + geom_point(data = exclude, shape = 21, fill = NA, color = "black", alpha = 0.25) +
coord_cartesian(xlim = c(1.5, 5.5), ylim = c(5,35))
Because you have not set a new aes for the exclude object, it inherits the aes from your ggplot call. It therefore needs to find a column named xaxis and yaxis in the exclude dataset. Since you only renamed final_df, it throws this error.
A graph is displayed when you change:
colnames(final_df) <- c("xaxis","yaxis","color")
to:
colnames(final_df) <- c("xaxis","yaxis","color")
colnames(exclude) <- c("xaxis","yaxis")