I hope you can help me again as I stumbled over another problem in Shiny:
I would like a graphic to change in the moment it is clicked on. Here's a minimal example:
ui.R (shows a clickable graphic and a text frame)
shinyUI(fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("graph", width = "100%", click = "plot_click"),
verbatimTextOutput("click_info")
)
)
)
)
server.R (graphic just contains "A","B","C","D", on click I get the nearest letter in the text frame)
shinyServer(function(input, output, session) {
# Visualization output:
observe({
output$graph <- renderPlot({
data <- data.frame(x=c(1,2,1,2), y=c(1,1,2,2),
values=c("A","B","C","D"), stringsAsFactors=FALSE)
plot(data$x, data$y, pch=data$values)
})
})
# interaction click in graph
observe({
click <- c(input$plot_click$x, input$plot_click$y)
data <- data.frame(x=c(1,2,1,2), y=c(1,1,2,2),
values=c("A","B","C","D"), stringsAsFactors=FALSE)
nearest_point <- which.min(apply(data[,1:2], 1, function(a) sum(((click-a)^2))))
id <- data$values[nearest_point]
output$click_info <- renderPrint({
id
})
})
})
Now what I want is to mark the letter I clicked on in the graph, for example by another color. But all my tries failed so far.
Try this:
ui <- shinyUI(fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("graph", width = "100%", click = "plot_click"),
verbatimTextOutput("click_info")
)
)
)
)
server <- shinyServer(function(input, output, session) {
data <- data.frame(x=c(1,2,1,2), y=c(1,1,2,2),
values=c("A","B","C","D"), stringsAsFactors=FALSE)
# Visualization output:
observe({
output$graph <- renderPlot({
plot(data$x, data$y, pch=data$values)
})
})
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
click <- c(input$plot_click$x, input$plot_click$y)
print(click)
nearest_point <- which.min(apply(data[,1:2], 1, function(a) sum(((click-a)^2))))
id <- data$values[nearest_point]
output$click_info <- renderPrint({
id
})
color <- rep("black",length(data$x))
color[data$values==id] <- "red"
isolate({
output$graph <- renderPlot({
plot(data$x, data$y, pch=data$values, col=color)
})
})
})
})
shinyApp(ui=ui,server=server)
With ggplot2
Edited as per #bunks suggestions:
library(ggplot2)
library(shiny)
ui <- shinyUI(fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("graph", width = "100%", click = "plot_click"),
verbatimTextOutput("click_info")
)
)
))
server <- shinyServer(function(input, output, session) {
data <- data.frame(x=c(1,2,1,2),
y=c(1,1,2,2),
values=c("A","B","C","D"),
stringsAsFactors=FALSE,
color=rep("1",4))
makeReactiveBinding('data')
output$graph <- renderPlot({
ggplot(data=data,aes(x=x,y=y,label=values,color=color))+geom_text()+theme_classic()+guides(colour=FALSE)
})
observeEvent(input$plot_click, {
# Get 1 datapoint within 15 pixels of click, see ?nearPoints
np <- nearPoints(data, input$plot_click, maxpoints=1 , threshold = 15)
output$click_info <- renderPrint({np$values})
data$color <<- rep("1",length(data$x))
data$color[data$values==np$values] <<- "2"
})
})
shinyApp(ui=ui,server=server)
Related
I have a code as follows and I want to add a Save button to points that are brushed. Many thanks in advance.
library(shiny)
ui <- basicPage(
plotOutput("plot1", brush = "plot_brush"),
verbatimTextOutput("info")
)
server <- function(input, output) {
x <- NULL
output$plot1 <- renderPlot({
plot(mtcars$wt, mtcars$mpg)
})
output$info <- renderPrint({
x <<- brushedPoints(mtcars, input$plot_brush, xvar = "wt", yvar = "mpg")
x
})
}
shinyApp(ui, server)
Add an actionButton when clicked saves the brushed dataframe. Also made output of brushedPoints as reactive so we can use it multiple times in the code.
library(shiny)
ui <- basicPage(
plotOutput("plot1", brush = "plot_brush"),
verbatimTextOutput("info"),
actionButton("save", "Save")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
plot(mtcars$wt, mtcars$mpg)
})
data <- reactive({
brushedPoints(mtcars, input$plot_brush, xvar = "wt", yvar = "mpg")
})
output$info <- renderPrint({data()})
observeEvent(input$save, {
write.csv(data(), 'brushed_data.csv', row.names = FALSE)
})
}
shinyApp(ui, server)
Here is a sample code to generate a plot upon clicking the actionButton.
shinyApp(
shinyUI(fluidPage(
inputPanel(
numericInput("n", "n", 10),
actionButton("update", "Update")
),
plotOutput("plot")
)),
shinyServer(function(input, output) {
values <- reactiveValues()
values$data <- c()
obs <- observe({
input$update
isolate({ values$data <- c(values$data, runif(as.numeric(input$n), -10, 10)) })
}, suspended=TRUE)
obs2 <- observe({
if (input$update > 0) obs$resume()
})
output$plot <- renderPlot({
dat <- values$data
hist(dat)
})
})
)
I would like to display a default plot which is in www/test.png to appear when the application is launched. And then change the plot after clicking the actionButton as per the user input.
First, I create a simple plot, export it as an image (manually, not in code) and name it Rplot.png (save it where you want):
plot(mtcars$mpg)
Then, in the shiny app, we have to distinguish two situations :
when the app starts, no button is clicked yet, we render the image with renderImage
when we click on the button, we replace renderImage with renderPlot and render an interactive plot
This means that we must use uiOutput in ui part so that we can choose the output to be an image or a plot according to the situation.
Here's an example (I didn't adapt your code but it should not be too difficult):
library(shiny)
# determine your path to image here (you should use the package "here" to do so)
ui <- fluidPage(
selectInput("choice", "Choose", choices = names(mtcars)),
actionButton("run", "Run"),
uiOutput("some_ui")
)
server <- function(input, output, session) {
### "Static" part: no click on actionButton yet
output$some_ui <- renderUI({
imageOutput("image_plot")
})
output$image_plot <- renderImage({
list(src = "Rplot.png",
contentType = 'image/png')
}, deleteFile = FALSE) # Do not forget this option
### Click on actionButton
observeEvent(input$run, {
output$some_ui <- renderUI({
plotOutput("dynamic_plot")
})
output$dynamic_plot <- renderPlot({
plot(mtcars[[input$choice]])
})
})
}
shinyApp(ui, server)
The key is to use renderUI, so you can either show an image or a R plot. This should do what you desire:
shinyApp(
shinyUI(fluidPage(
inputPanel(
numericInput("n", "n", 10),
actionButton("update", "Update")
),
uiOutput("out")
)),
shinyServer(function(session, input, output) {
values <- reactiveValues()
# check if plot has been already rendered
check <- reactiveVal(FALSE)
values$data <- c()
observeEvent(input$update, {
# set check to TRUE
check(TRUE)
input$update
values$data <- c(values$data, runif(as.numeric(input$n), -10, 10))
dat <- values$data
output$plot <- renderPlot({
hist(dat)
})
})
# initial picture.
output$picture <- renderImage({
list(src = "temp.png")
}, deleteFile = FALSE)
output$out <- renderUI({
# in the beginning, check is FALSE and the picture is shown
if (!check()) {
imageOutput("picture")
} else {
# as soon as the button has been pressed the first time,
# the plot is shown
plotOutput("plot")
}
})
})
)
I know, that this has been solved a while, but I needed a solution, without uiOutput. Plus I find this much simpler.
library(shiny)
if (interactive()) {
shinyApp(
ui = fluidPage(
actionButton("btn", "Click me"),
br(),
plotOutput('some_plot', width = '100%')
),
server = function(input, output) {
output$some_plot <- renderPlot({
if (!input$btn) {
# default plot
plot(1, 1, col = 'red')
} else{
# updated plot
plot(1000, 1000, col = 'green')
}
})
}
)
}
I am working on an Interactive Shiny App. To display the next plot on a mouse click, I have to track the very previous value of a variable. But when I click on the plot All the variables reset. Can you please suggest me a way to stop a variable from resetting on every iteration.
For example:
library(shiny)
ui <- shinyUI(fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
actionButton("Reset", label="Reset Graph")
),
mainPanel(
plotOutput("graph", width = "100%", click = "plot_click"),
verbatimTextOutput("click_info")
)
)
)
)
server <- shinyServer(function(input, output, session) {
level <- "Value1"
observeEvent(input$Reset,{
output$graph <- renderPlot({ plot(1, 1) }) }, ignoreNULL = F)
print(level)
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
x <- sample(20:30,1,F)
level <- "Value2"
isolate({
output$graph <- renderPlot({
draw.single.venn(x)
})
})
})
})
shinyApp(ui=ui,server=server)
I have changed the level variable to "Value2". But on next iteration, it again turns to "Value1" due to the first line of code. Can you help me to remain it as "Value2"?
You can define it as a reactive value:
server <- shinyServer(function(input, output, session) {
level_init <- reactiveValues(level="Value1")
level_react <- reactive({
level_init$level <- "Value2"
})
print(isolate(level_init$level))
observeEvent(input$Reset,{
output$graph <- renderPlot({ plot(1, 1) }) }, ignoreNULL = F)
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
x <- sample(20:30,1,F)
level_react()
print(level_init$level)
isolate({
output$graph <- renderPlot({
draw.single.venn(x)
})
})
})
})
shinyApp(ui=ui,server=server)
I am working on an R-Shiny Application. I have used the following code(demo code) to interact with the plot.
ui <- shinyUI(fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
plotOutput("graph", width = "100%", click = "plot_click"),
verbatimTextOutput("click_info")
)
)
)
)
server <- shinyServer(function(input, output, session) {
observe({
output$graph <- renderPlot({
plot(1, 1)
})
})
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
x <- sample(20:30,1,F)
isolate({
output$graph <- renderPlot({
draw.single.venn(x)
})
})
})
})
shinyApp(ui=ui,server=server)
It can change the plot on a mouse click. I want to get back to the very first plot using a reset button. Kindly help.
I added a reset button to your sidebar. Hope that's helpful. This link provides more info on how to do this type of functionality.
library(shiny)
ui <- shinyUI(fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(
actionButton("Reset", label="Reset Graph")
),
mainPanel(
plotOutput("graph", width = "100%", click = "plot_click"),
verbatimTextOutput("click_info")
)
)
)
)
server <- shinyServer(function(input, output, session) {
observeEvent(input$Reset,{ output$graph <- renderPlot({ plot(1, 1) }) }, ignoreNULL = F)
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
x <- sample(20:30,1,F)
isolate({
output$graph <- renderPlot({
draw.single.venn(x)
})
})
})
})
shinyApp(ui=ui,server=server)
I have made a shiny app which takes in any data and shows column names depending on the data.
c1 <- rnorm(10,0,1)
c2 <- c(rep("txA",5),rep("txB",5))
c3 <- c(1:4,1:4,1:2)
c4 <- rep(LETTERS[1:5],2)
mydata <- data.frame(c1,c2,c3,c4)
ui <- fluidPage(
fileInput(inputId = "file",
label = "import file"),
tableOutput("tb"),
sidebarLayout(
sidebarPanel(
uiOutput(outputId = "aa")
),
mainPanel(textOutput("a"),
verbatimTextOutput("info"),
verbatimTextOutput("summary"),
plotOutput("plot", click = "plot_click")
)
)
)
server <- function(input,output) {
output$aa <- renderUI({
validate(need(input$file != "", ""))
mydata <- read.csv(input$file$datapath)
selectInput(inputId = "aa", #can be any name?
label="Select:",
choices = colnames(mydata))
})
output$tb <- renderTable({
data <- input$file
if (is.null(data))return()
read.table(data$datapath,sep=",")
})
output$summary <- renderPrint({
summary(mydata)
})
output$plot <- renderPlot({
plot(mydata)
})
output$info <- renderText({
paste0("x=", input$plot_click$x, "\ny=", input$plot_click$y)
})
}
shinyApp(ui=ui, server=server)
If I run this I get the following:
I am trying to make a shiny app which shows a basic plot depending on the columns that I choose. How would I do this?
Something like this would do, make sure to uncomment the file input
library(shiny)
c1 <- rnorm(10,0,1)
c2 <- c(rep("txA",5),rep("txB",5))
c3 <- c(1:4,1:4,1:2)
c4 <- rep(LETTERS[1:5],2)
mydata <- data.frame(c1,c2,c3,c4)
ui <- fluidPage(
fileInput(inputId = "file",
label = "import file"),
tableOutput("tb"),
sidebarLayout(
sidebarPanel(
uiOutput(outputId = "aa")
),
mainPanel(textOutput("a"),
verbatimTextOutput("info"),
verbatimTextOutput("summary"),
plotOutput("plot", click = "plot_click")
)
)
)
server <- function(input,output) {
output$aa <- renderUI({
#validate(need(input$file != "", ""))
#mydata <- read.csv(input$file$datapath)
## Since your output$aa already has name aa you cant use it twice!
selectInput(inputId = "aa2", #can be any name?
label="Select:",
choices = colnames(mydata))
})
output$tb <- renderTable({
data <- input$file
if (is.null(data))return()
read.table(data$datapath,sep=",")
})
mysubsetdata <- eventReactive(input$aa2,{
mydata[[input$aa2]]
})
output$summary <- renderPrint({
summary(mysubsetdata())
})
output$plot <- renderPlot({
plot(mysubsetdata())
})
output$info <- renderText({
paste0("x=", input$plot_click$x, "\ny=", input$plot_click$y)
})
}
shinyApp(ui=ui, server=server)
Added eventReactive to listen to selectInput
All widgets must have unique id so you cannot use aa twice, one for renderui and one for selectInput