Related
I'm sorry my code is too complex to create a MRE. I am currently trying to dynamically output n numbers of plots & inputSliders based on the number of calculation columns inputted. I have looked almost everywhere, however I can not seem to find a previously posted question that connects dynamically produced plots & sliders.
Goals: Upload n plots & inputSlider based up a file upload. Two reactive vertical lines on top of the plot that move based on the respective inputSlider range.
What actually happens: The correct number of plots & sliderInputs output, however the inputSliders aren't reactive to the created plots AND the vertical line doesn't appear.
I don't receive any error messages, however I am almost certain that the issues lies in that my inputSlider information returns NULL.
I've tried to change the possible inputs for the ggplot code to hopefully show the respective plots by doing:
...+geom_vline(xintercept = input$plotSlider[1])+ geom_vline(xintercept = input$plotSlider[2])
...+geom_vline(xintercept = output$plotSlider[1])+geom_vline(xintercept = output$plotSlider[2])
..+geom_vline(xintercept = plotSlider[1]) +geom_vline(xintercept = plotSlider[2])
I also have tried rendering the sliders before the plots, since the input variable wouldn't have been created yet.
This here is a sample csv file:
structure(list(X10.9 = c(11.1, 11.6, 12, 12.5, 13, 13.4), X = c(NA,
NA, NA, NA, NA, NA), X.0.095 = c(-0.0911, -0.07, -0.0891, -0.1021,
-0.1019, -0.1019), X.1 = c(NA, NA, NA, NA, NA, NA), X1.4241 = c(1.4396,
1.4439, 1.4454, 1.4498, 1.4513, 1.4513), X.2 = c(NA, NA, NA,
NA, NA, NA), X1.4353 = c(1.4498, 1.4648, 1.474, 1.4819, 1.485,
1.4866), X.3 = c(NA, NA, NA, NA, NA, NA), X0.6736 = c(0.6943,
0.7066, 0.7141, 0.7179, 0.7193, 0.7182)), row.names = c(NA, 6L
), class = "data.frame")
My Code so far:
library(shiny)
library(dplyr, warn.conflicts = FALSE)
library(ggplot2)
#library(MeltR)
library(shiny)
library(glue)
# Define UI ----
ui <- navbarPage(title = "MeltShiny",
id = "navbar",
navbarMenu("File",
tabPanel("Add Data",
fluidPage(
sidebarLayout(
sidebarPanel(
textInput(label="Enter the Pathlength for each Absorbance Reading(separated by commas)",
placeholder = "E.g: 2,5,3,2,...",
inputId = "pathlengths"),
fileInput(label = "Add Data",
inputId = "inputFile",
multiple = FALSE,
accept = ".csv")
),
mainPanel(
tableOutput("contents")
)
)
)
)
),tabPanel(
value = "vizPanel",
title = "Data Visualization",
uiOutput("sliders"),
uiOutput("plots")
)
)
server <- function(input,output){
#Reactive list variable
values <- reactiveValues(masterFrame=NULL,up=NULL,loaded=NULL)
plots <- reactiveValues()
#Upload Project File
upload <- observeEvent(eventExpr =input$inputFile,
handlerExpr = {
req(input$inputFile)
#Declaring variables
pathlengths <- c(unlist(strsplit(input$pathlengths,",")))
req(input$inputFile)
fileName = input$inputFile$datapath
cd <- read.csv(file = fileName,header=FALSE)
df <- cd %>% select_if(~ !any(is.na(.)))
#Creating temporary frame to store sample data
columns <- c("Sample", "Pathlength", "Temperature", "Absorbance")
tempFrame <- data.frame(matrix(nrow = 0, ncol = 4))
colnames(tempFrame) <- columns
readings <- ncol(df)
#Loop that appends sample data
counter <- 1
for (x in 2:readings){
col <- df[x]
sample<-rep(c(counter),times=nrow(df[x]))
pathlength<-rep(c(pathlengths[counter]),times=nrow(df[x]))
col <- df[x]
t <- data.frame(sample,pathlength,df[1],df[x])
names(t) <- names(tempFrame)
tempFrame <- rbind(tempFrame, t)
counter <- counter + 1
}
values$numReadings <- counter-1
values$masterFrame <- tempFrame
values$up <- 1
}
)
output$contents <- renderTable({
return(values$masterFrame)})
observeEvent(eventExpr = input$navbar == "vizPanel",
handlerExpr = {
req(input$inputFile)
print("Observe Triggered")
for(i in 1:values$numReadings){
local({
myI <- i
plotName = paste0("plot",myI)
plotSlider = paste0("plotSlider",myI)
output[[plotName]] <- renderPlot({
data = values$masterFrame[values$masterFrame$Sample == myI,]
ggplot(data, aes(x = Temperature,
y = Absorbance,
color = factor(Sample))) +geom_point() +theme_classic()+geom_vline(xintercept = input$plotSlider[1]) +geom_vline(xintercept = input$plotSlider[2])
})
})
values$loaded <- 1
}
}
)
output$plots <- renderUI({
req(values$loaded)
plot_output_list <- lapply(1:values$numReadings, function(i){
plotName <- paste0("plot",i)
plotOutput(plotName,height=280,width=250)
})
do.call(tagList,plot_output_list)
})
output$sliders <- renderUI({
req(input$inputFile)
print("slider")
slider_output_list <- lapply(1:values$numReadings, function(i){
plotSlider <- paste0("plotSlider",i)
data = values$masterFrame[values$masterFrame$Sample == i,]
xmin = min(data$Temperature)
xmax = max(data$Temperature)
sliderInput(plotSlider,"Range of values",min=xmin,max=xmax,value=c(xmin,xmax))
})
do.call(tagList,slider_output_list)
})
}
# Run the app
shinyApp(ui = ui, server = server)
Any suggestions would be greatly appreciated!
Appropriate syntax for input$plotSlider will make it work. Try this
library(shiny)
library(dplyr, warn.conflicts = FALSE)
library(ggplot2)
#library(MeltR)
library(shiny)
library(glue)
# Define UI ----
ui <- navbarPage(title = "MeltShiny",
id = "navbar",
navbarMenu("File",
tabPanel("Add Data",
fluidPage(
sidebarLayout(
sidebarPanel(
textInput(label="Enter the Pathlength for each Absorbance Reading(separated by commas)",
placeholder = "E.g: 2,5,3,2,...",
inputId = "pathlengths"),
fileInput(label = "Add Data",
inputId = "inputFile",
multiple = FALSE,
accept = ".csv")
),
mainPanel(
tableOutput("contents")
)
)
)
)
),tabPanel(
value = "vizPanel",
title = "Data Visualization",
uiOutput("sliders"),
uiOutput("plots")
)
)
server <- function(input,output){
#Reactive list variable
values <- reactiveValues(masterFrame=NULL,up=NULL,loaded=NULL)
plots <- reactiveValues()
#Upload Project File
upload <- observeEvent(eventExpr =input$inputFile,
handlerExpr = {
req(input$inputFile)
#Declaring variables
pathlengths <- c(unlist(strsplit(input$pathlengths,",")))
req(input$inputFile)
fileName = input$inputFile$datapath
cd <- read.csv(file = fileName,header=TRUE)
df <- cd %>% select_if(~ !any(is.na(.)))
#Creating temporary frame to store sample data
columns <- c("Sample", "Pathlength", "Temperature", "Absorbance")
tempFrame <- data.frame(matrix(nrow = 0, ncol = 4))
colnames(tempFrame) <- columns
readings <- ncol(df)
#Loop that appends sample data
counter <- 1
for (x in 2:readings){
# local({
# x <- x
col <- df[x]
sample<-rep(c(counter),times=nrow(df[x]))
pathlength<-rep(c(pathlengths[counter]),times=nrow(df[x]))
col <- df[x]
t <- data.frame(sample,pathlength,df[1],df[x])
names(t) <- names(tempFrame)
tempFrame <- rbind(tempFrame, t)
counter <- counter + 1
#})
}
values$numReadings <- counter-1
values$masterFrame <- tempFrame
values$up <- 1
}
)
output$contents <- renderTable({
return(values$masterFrame)})
# observeEvent(eventExpr = input$navbar == "vizPanel",
# handlerExpr = {
observe({
req(input$inputFile)
#print(input[[paste0("plotSlider1")]])
print("Observe Triggered")
for(i in 1:values$numReadings){
local({
myI <- i
plotName = paste0("plot",myI)
plotSlider = paste0("plotSlider",myI)
output[[plotName]] <- renderPlot({
data = values$masterFrame[values$masterFrame$Sample == myI,]
ggplot(data, aes(x = Temperature,
y = Absorbance,
color = factor(Sample))) +
geom_point() + theme_classic()+
geom_vline(xintercept = input[[paste0("plotSlider",myI)]][1]) +
geom_vline(xintercept = input[[paste0("plotSlider",myI)]][2])
})
})
values$loaded <- 1
}
})
output$plots <- renderUI({
req(values$loaded)
plot_output_list <- lapply(1:values$numReadings, function(i){
plotName <- paste0("plot",i)
plotOutput(plotName,height=280,width=250)
})
do.call(tagList,plot_output_list)
})
output$sliders <- renderUI({
req(input$inputFile)
slider_output_list <- lapply(1:values$numReadings, function(i){
plotSlider <- paste0("plotSlider",i)
data = values$masterFrame[values$masterFrame$Sample == i,]
xmin = min(data$Temperature)
xmax = max(data$Temperature)
sliderInput(plotSlider,"Range of values",min=xmin,max=xmax,value=c(xmin,xmax))
})
do.call(tagList,slider_output_list)
})
}
# Run the app
shinyApp(ui = ui, server = server)
I want to exclude certain data points that are selected by the user by clicking, like in this example (but using plotly).
I tried to do it with the code i show below but it doesnt work.
What i'm triying to do is identify the position of the data point and then once i get the position, set the var delete as TRUE if the row_number() is in the set of selected data points and then just filter is delete is TRUE.
I dont know if this is the most effient form to perfom that.
I would appreciate any help or guidance.
library(shiny)
library(plotly)
library(dplyr)
n <- 20
x <- 1:n
y <- cumsum(rnorm(n))
z <- runif(n,10,200)
cat <- sample(letters[1:5],n,replace = TRUE)
delete <- FALSE
df<-data.frame(cat,x,y,z, delete)
ui <- fluidPage(
selectInput("var","var", c("y","z"), "y"),
mainPanel(plotlyOutput("plot")),
verbatimTextOutput("selection"),
actionButton("delete","Delete", style = "display:inline-block;"),
actionButton("reset","Reset", style = "display:inline-block;"),
)
server <- function(input, output, session) {
myData <- reactive({df})
output$plot <- renderPlotly({
plot_ly(myData(),
x = ~x,
y = ~get(input$var),
type = "scatter",
mode = "markers",
text = ~cat,
marker = list(size = 10),
source = "A")
})
p1 <- reactive({
event_data("plotly_click", source = "A")
})
p2 <- reactiveValues(points = c())
observeEvent(p1(),{
p2$points <- c(p2$points,as.list(p1())$pointNumber)
})
observeEvent(input$reset,{
p2$points <- c()
})
output$selection <- renderPrint({ if(length(p2$points+1)<1){"Select data points to delete"}else{(p2$points+1)} })
observeEvent(input$delete,{
myData() <- myData() %>%
mutate(delete = ifelse(row_number() %in% c(p2$puntos+1),TRUE,delete)) %>%
filter(!delete)
})
}
shinyApp(ui, server)
Nice trick with event_data there! I think all that's needing done differently is to make myData$df a named reactiveValue (with one small correction to p2$points lower down). This works for me now:
library(shiny)
library(plotly)
library(dplyr)
n <- 20
x <- 1:n
y <- cumsum(rnorm(n))
z <- runif(n,10,200)
cat <- sample(letters[1:5],n,replace = TRUE)
delete <- FALSE
df<-data.frame(cat,x,y,z, delete)
ui <- fluidPage(
selectInput("var","var", c("y","z"), "y"),
mainPanel(plotlyOutput("plot")),
verbatimTextOutput("selection"),
actionButton("delete","Delete", style = "display:inline-block;"),
actionButton("reset","Reset", style = "display:inline-block;"),
)
server <- function(input, output, session) {
myData <- reactiveValues(df = df)
output$plot <- renderPlotly({
plot_ly(myData$df,
x = ~x,
y = ~get(input$var),
type = "scatter",
mode = "markers",
text = ~cat,
marker = list(size = 10),
source = "A")
})
p1 <- reactive({
event_data("plotly_click", source = "A")
})
p2 <- reactiveValues(points = c())
observeEvent(p1(),{
p2$points <- c(p2$points,as.list(p1())$pointNumber)
})
observeEvent(input$reset,{
p2$points <- c()
})
output$selection <- renderPrint({ if(length(p2$points+1)<1){"Select data points to delete"}else{(p2$points+1)} })
observeEvent(input$delete,{
# browser()
myData$df <- myData$df %>%
mutate(delete = ifelse(row_number() %in% c(p2$points+1),TRUE,delete)) %>%
filter(!delete)
# And clear input?
p2$points <- c()
})
}
shinyApp(ui, server)
I have an app that is creating a dynamic number of images, based on various user inputs. The plotting is being done using renderUI following this link, but with modifications required for my own setup. I now need to export these plots, but can't figure out how to make that happen. I know how to export an individual plot (which is included in the example below), but am looking to modify the code below to be able to export a dynamic number of models.
Would appreciate any suggestions!
library(shiny)
library(dplyr)
library(ggplot2)
# fake data
df <- data.frame(x = 1:10, y = letters[1:10]) %>%
mutate(Plot = x %/% 3.1 + 1)
# function for plotting dynamic number of plots
get_plot_output_list <- function(input_n, df) {
# Insert plot output objects the list
plot_output_list <- lapply(1:input_n, function(i) {
sub <- df %>% filter(Plot == i)
plotname <- paste("plot", i, sep="")
plot_output_object <- plotOutput(plotname, height = 280, width = 250)
plot_output_object <- renderPlot({
ggplot(sub) + geom_point(aes(x = x, y = y))
})
})
do.call(tagList, plot_output_list) # needed to display properly.
}
ui <- navbarPage("My app", id = "nav",
tabPanel("Single plot",
fluidRow(column(9, plotOutput("plot1")),
column(2, downloadButton('ExportPlot1', label = "Download plot1")))),
tabPanel("Multiple plots",
fluidRow(column(9,
selectInput("NPlots", label = "Select number of plots to make", choices = 1:3, selected = 1),
uiOutput("plots")),
column(2, downloadButton('ExportPlots', label = "Download all dynamic plots")))))
server <- (function(input, output) {
observe({
output$plots <- renderUI({ get_plot_output_list(input$NPlots, df) })
})
plot.calc <- reactive({
p <- ggplot(df) + geom_point(aes(x = x, y = y))
output <- list(p = p)
})
output$plot1 <- renderPlot({ plot.calc()$p })
output$ExportPlot1 <- downloadHandler(
filename = 'Plot1.html',
content = function(file) {
src <- normalizePath(c('Plot1.Rmd')) # SEE HERE
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, c('Plot1.Rmd'), overwrite = TRUE) # SEE HERE
params <- list(Plot1 = plot.calc()$p)
Sys.setenv(RSTUDIO_PANDOC="C:/Program Files/RStudio/bin/pandoc")
out <- rmarkdown::render('Plot1.Rmd', output_file = file, params = params, envir = new.env(parent = globalenv()))
file.rename(out, file)
})
})
shinyApp(ui, server)
Rmd file:
---
title: "Untitled"
author: "test"
date: "24 3 2021"
output: html_document
params:
Plot1: NA
---
My plot
```{r, echo = FALSE, warning = FALSE, fig.width = 6.4, fig.height = 3.5}
params$Plot1
```
When you separate the plot generation and the actual plotting, you can pass the generated plots to the Rmd. BTW you don't need observe when you work with reactives like input$NPlots:
library(shiny)
library(dplyr)
library(ggplot2)
# fake data
df <- data.frame(x = 1:10, y = letters[1:10]) %>%
mutate(Plot = x %/% 3.1 + 1)
generate_plots <- function(input_n, df) {
plot_output_list <- lapply(1:input_n, function(i) {
sub <- df %>% filter(Plot == i)
p <- ggplot(sub) + geom_point(aes(x = x, y = y))
p
})
plot_output_list
}
ui <- navbarPage("My app", id = "nav",
tabPanel("Single plot",
fluidRow(column(9, plotOutput("plot1")),
column(2, downloadButton('ExportPlot1', label = "Download plot1")))),
tabPanel("Multiple plots",
fluidRow(column(9,
selectInput("NPlots", label = "Select number of plots to make", choices = 1:3, selected = 1),
uiOutput("plots")),
column(2, downloadButton('ExportPlots', label = "Download all dynamic plots")))))
server <- (function(input, output) {
plot_data <- reactive({
generate_plots(input$NPlots, df)
})
output$plots <- renderUI({
plot_output_list <- lapply(seq_len(length(plot_data())), function(i) {
plotname <- paste("plot", i, sep="")
plot_output_object <- plotOutput(plotname, height = 280, width = 250)
plot_output_object <- renderPlot({
plot_data()[[i]]
})
})
do.call(tagList, plot_output_list) # needed to display properly.
})
plot.calc <- reactive({
p <- ggplot(df) + geom_point(aes(x = x, y = y))
output <- list(p = p)
})
output$plot1 <- renderPlot({ plot.calc()$p })
output$ExportPlot1 <- downloadHandler(
filename = 'Plot1.html',
content = function(file) {
src <- normalizePath(c('Plot1.Rmd')) # SEE HERE
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, c('Plot1.Rmd'), overwrite = TRUE) # SEE HERE
params <- list(Plot1 = plot.calc()$p,
Plot_list = plot_data())
Sys.setenv(RSTUDIO_PANDOC="C:/Program Files/RStudio/bin/pandoc")
out <- rmarkdown::render('Plot1.Rmd', output_file = file, params = params, envir = new.env(parent = globalenv()))
file.rename(out, file)
})
output$ExportPlots <- downloadHandler(
filename = 'Plots.html',
content = function(file) {
src <- normalizePath(c('Plots.Rmd')) # SEE HERE
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, c('Plots.Rmd'), overwrite = TRUE) # SEE HERE
params <- list(Plot_list = plot_data())
Sys.setenv(RSTUDIO_PANDOC="C:/Program Files/RStudio/bin/pandoc")
out <- rmarkdown::render('Plots.Rmd', output_file = file, params = params, envir = new.env(parent = globalenv()))
file.rename(out, file)
})
})
shinyApp(ui, server)
Plots.Rmd
---
title: "Untitled"
author: "test"
date: "24 3 2021"
output: html_document
params:
Plot_list: NA
---
Multiple Plots
```{r, echo = FALSE, warning = FALSE, fig.width = 6.4, fig.height = 3.5}
purrr::walk(params$Plot_list, print)
```
I am trying to create an application where a user selection determines the number of plots to be placed into a carousel. I have a MWE below, where a user "selects" anywhere between 1-10 of the lines in the parallel coordinate plot on the left. After doing so, on the right, 1-10 plots are created (one for each of the lines the user selected). This all seems to be working, and the dynamic number of plots are stored in a tagList() object.
With larger datasets, the number of lines the user can select can be large and the output plots can look crowded. Hence, I am trying to put the output plots into a carousel. Currently, I have all output plots in a carousel - but they are all shoved into the first page of the carousel.
I would be grateful to hear any advice on how I can tweak this MWE so that each page of the carousel only contains one of the output plots.
library(shiny)
library(plotly)
library(data.table)
library(dplyr)
library(tidyr)
library(bsplus)
ui <- shinyUI(pageWithSidebar(
headerPanel("Dynamic number of plots"),
sidebarPanel(
plotlyOutput("plot")
),
mainPanel(
# This is the dynamic UI for the plots
bs_carousel(id = "tabPrev", use_indicators = TRUE) %>%
bs_append(content = uiOutput("plots"))
)
)
)
server <- shinyServer(function(input, output) {
set.seed(1)
dat <- data.frame(ID = paste0("ID",1:10), A.1 = runif(10), A.2 = runif(10), A.3 = runif(10), B.1 = runif(10), B.2 = runif(10), B.3 = runif(10))
dat$ID <- as.character(dat$ID)
# Convert DF from scatterplot to PCP
datt <- data.frame(t(dat))
names(datt) <- as.matrix(datt[1, ])
datt <- datt[-1, ]
datt[] <- lapply(datt, function(x) type.convert(as.character(x)))
setDT(datt, keep.rownames = TRUE)[]
colnames(datt)[1] <- "x"
dat_long <- melt(datt, id.vars ="x" )
dat_long <- separate(dat_long, x, c("group", "rep"), remove=FALSE)
dat_long$group <- factor(dat_long$group)
output$plot <- renderPlotly({
plot_ly(dat_long, x= ~x, y= ~value, type = 'scatter', mode = 'lines+markers', color = ~variable) %>% layout(dragmode="box", showlegend = FALSE)
})
d <- reactive(event_data("plotly_selected"))
observeEvent(d(),{
# Insert the right number of plot output objects into the web page
output$plots <- renderUI({
lengthY <- reactive((length(unique(d()$curveNumber))))
if (lengthY()<1){
plot_output_list <- list()
}
else{
plot_output_list <- lapply(1:lengthY(), function(i) {
plotname <- paste("plot", i, sep="")
plotlyOutput(plotname, height = 280, width = 250)
})
}
# Convert the list to a tagList - this is necessary for the list of items
# to display properly.
do.call(tagList, plot_output_list)
})
})
# Call renderPlot for each one. Plots are only actually generated when they
# are visible on the web page.
observeEvent(d(),{
lengthY <- reactive(length(unique(d()$curveNumber)))
for (i in 1:lengthY()) {
# Need local so that each item gets its own number. Without it, the value
# of i in the renderPlot() will be the same across all instances, because
# of when the expression is evaluated.
local({
my_i <- i
curveY <- reactive(d()$curveNumber[my_i])
plotname <- paste("plot", my_i, sep="")
ax <- list(title = "", showticklabels = TRUE)
ay <- list(title = "Read Count")
indDat <- as.data.frame(dat_long[variable %in% dat[curveY()+1,]$ID])
g1 <- levels(indDat$group)[1]
g2 <- levels(indDat$group)[2]
g1m <- mean(filter(indDat, group==g1)$value)
g2m <- mean(filter(indDat, group==g2)$value)
output[[plotname]] <- renderPlotly({
indDat %>% plot_ly(x = ~group, y = ~value, type = "scatter", marker = list(size = 10), color = ~group, colors = "Set2", hoverinfo = "text", text = paste0("Read count = ", format(round(indDat$value, 2), nsmall = 2))) %>% layout(xaxis = ax, yaxis = ay, legend = list(x = 0.35, y = -0.26)) %>% add_segments(x = g1, xend = g2, y = g1m, yend = g2m, showlegend = FALSE, line = list(color='#000000')) %>% add_trace(x = g1, y= g1m, showlegend = FALSE, hoverinfo = "text", text = paste0("Mean Read Count = ", round(g1m, digits = 2)), marker = list(color='#000000')) %>% add_trace(x = g2, y= g2m, showlegend = FALSE, hoverinfo = "text", text = paste0("Mean Read Count = ", round(g2m, digits = 2)), marker = list(color='#000000'))
})
})
}
})
})
shinyApp(ui, server)
The way I would do this is embedding the bs_carousel inside the renderUI. It does work but I couldn't manage to remove the plots object totally, which sometimes plots... If I remove it, only the first plot appears in the carousel.
1- Change the ui to :
ui <- shinyUI(pageWithSidebar(
headerPanel("Dynamic number of plots"),
sidebarPanel(
plotlyOutput("plot")
),
mainPanel(
uiOutput("car_ui"),
uiOutput("plots")
)
)
)
2- Add this code in the first observeEvent, just above the output$plots
output$car_ui <- renderUI({
lengthY <- length(unique(d()$curveNumber))
if (lengthY<1){
plot_output_list <- list()
}
else{
plot_output_list <- lapply(1:lengthY, function(i) {
plotname <- paste("plot", i, sep="")
plotlyOutput(plotname, height = 280, width = 250)
})
}
car <- bs_carousel(id = "carousel", use_indicators = TRUE)
Reduce(bs_append, plot_output_list, init=car)
})
Also note you don't have to put all your calculations (lengthY...) in a reactive
How can we get interactive coordinates(x and y) of multiple histograms in shiny. I have tried this code
#server.R
library(xts)
shinyServer(function(input, output,session) {
output$info <- renderText({
paste0("x=", input$plot_click$x, "\ny=", input$plot_click$y)
})
output$plot<- renderPlot({
set.seed(3)
Ex <- xts(1:100, Sys.Date()+1:100)
df = data.frame(Ex,matrix(rnorm(100*3,mean=123,sd=3), nrow=100))
df<-df[,-1]
par(mfrow = c(2,2))
for(i in names(df)){
hist(df[[i]] , main=i,xlab="x",freq=TRUE,label=TRUE,plot = TRUE)
}
})
})
ui.R
#ui.r
mainPanel(
tabsetPanel(type="tab",tabPanel("plot", plotOutput("plot",click = "plot_click"), verbatimTextOutput("info"))
)
The problem with above code is I get random coordinates of the whole plot like this
x=124.632301932263
y=20.4921068342051
instead I want to get coordinates of individual plots with its corresponding values. For example if I click any place in X1's chart I should get x and y coordinates of that chart . How can I do this?
I originally was going to say that this occurs because the click is governed by the pixels of the plot instead of the data, but I am proved wrong here:
Notice that the x and y coordinates are scaled to the data, as opposed to simply being the pixel coordinates. This makes it easy to use those values to select or filter data.
I instead am going to honestly guess that within a graphics device Shiny can't tell the difference between the individual plots, to which a solution would be to create individual devices for each plot:
ui.R
library(shiny)
shinyUI(
tabsetPanel(type="tab",
tabPanel("plot",
uiOutput("coords"),
uiOutput("plots")
)
)
)
server.R
library(xts)
set.seed(3)
Ex <- xts(1:100, Sys.Date() + 1:100)
df <- data.frame(Ex, matrix(rnorm(100*3, mean = 123, sd = 3), nrow = 100))
cn <- colnames(df)
df <- df[, cn[cn != "Ex"]]
n_seq <- seq(ncol(df))
shinyServer(function(input, output, session) {
output$plots <- renderUI({
plot_output_list <- lapply(n_seq, function(i) {
plotOutput(paste0("plot", i), click = paste0("plot_click", i),
height = 250, width = 300)
})
})
for (i in n_seq) {
output[[paste0("plot", i)]] <- renderPlot({
hist(df[[i]] , main = i, xlab = "x", freq = TRUE, label = TRUE)
})
}
output$coords <- renderUI({
coords_output_list <- lapply(n_seq, function(i) {
renderText({
set <- input[[paste0("plot_click", i)]]
paste0("Plot ", i, ": x=", set$x, "\ny=", set$y)
})
})
})
})