I'm trying to take my Shiny apps and break them into smaller files to make collaborating via git with coworkers much easier. This question helped me figure out how to source() in files to my server.r by using source(...,local=T). Now I'm trying to do the same thing with my UI layer.
Consider this toy Shiny app:
library(shiny)
ui <- bootstrapPage(
plotOutput("test"),
numericInput("n","Number of points",value=100,min=1)
)
server <- function(input, output, session) {
output$test = renderPlot({
x = rnorm(input$n)
y = rnorm(input$n)
plot(y~x)
})
}
shinyApp(ui, server)
This app does what you would expect, one overly-wide graph of 100 random data points. Now, what if I want to move just the plotOutput to a separate file (the real use case is in moving whole tabs of UI to separate files). I make a new file called tmp.R and it has:
column(12,plotOutput("test"),numericInput("n","Number of points",value=100,min=1))
The reason for wrapping it in the column statement is because the comma's can't just be hanging out. Now I update my UI to:
library(shiny)
ui <- bootstrapPage(
source("tmp.R",local=T)
)
server <- function(input, output, session) {
output$test = renderPlot({
x = rnorm(input$n)
y = rnorm(input$n)
plot(y~x)
})
}
shinyApp(ui, server)
Now, the word "TRUE" is just hanging out at the bottom of the page.
How do I eliminate this word from showing up? Why is it there?
Try source("tmp.R",local = TRUE)$value maybe
Related
I'm new to shiny, so don't mind me if my question is simple.
I want to take a path as an input from the user and generate the data frame. I've done this so far:
library(shiny)
ui <- fluidPage(
textInput("data_path", "Please enter the path of your data: ")
tableOutput("data_glimpse")
)
server <- function(input, output){
data <- read.csv(input$data_path)
output$data_glimpse <- renderTable({
glimpse(data)
})
}
shinyApp(ui = ui, server = server)
But it's not working right. I don't get any pages to enter my path!
Any help?
I think it is easier to upload the file directly. But if you want to keep this structure, you can try the following. To make it work you have to add to your path the name of the file plus .csv, e.g. /sample.csv
library(shiny)
ui <- fluidPage(
textInput("data_path", "Please enter the path of your data: "),
tableOutput("data_glimpse")
)
server <- function(input, output){
dataTable <- reactive({
data <- read.csv(input$data_path)
})
output$data_glimpse <- renderTable({
dplyr::glimpse(dataTable())
})
}
shinyApp(ui = ui, server = server)
This is my first post here so I hope I can explain my problem clearly. I am currently getting into shiny and want to start off by doing basic stuff. I decided to challenge myself by making an app that takes two numeric inputs and plots them whenever I press an actionbar. The problem is that I want to keep the previous points that I plot. I can't get it to work as it keeps resetting the plot. I've tried many different ways and I dont really know how points() works on shiny. Here is the code:
library(shiny)
ui <- fluidPage(
actionButton(inputId="execute",label="Execute"),
numericInput(inputId="numY",label="Y",value=0),
numericInput(inputId="numX",label="X",value=0),
plotOutput("plot")
)
server <- function(input, output) {
coordx <- eventReactive(input$execute,{input$numX})
coordy <- eventReactive(input$execute,{input$numY})
if(!exists("input$execute"))
{
output$plot <- renderPlot({
plot(x=coordx(),y=coordy())
})
}
else
output$plot <- renderPlot({
points(x=coordx(),y=coordy())
})
}
shinyApp(ui = ui, server = server)
Thank you in advance!
As the commenters #Limey and #fvall said, the issue seems to be the eventReactive() which overwrites each time. What I did instead is place the x and y coordinates in a reactiveValues(). Then I placed an observeEvent() for any time input$execute was pressed, writing the x and y coordinates to update the reactiveValues(). This will keep both the old and new values. I also added a little tableOutput() just to keep track of the values:
library(shiny)
ui <- fluidPage(
actionButton(inputId="execute",label="Execute"),
numericInput(inputId="numY",label="Y",value=0),
numericInput(inputId="numX",label="X",value=0),
plotOutput("plot"),
tableOutput("TABLE")
)
server <- function(input, output) {
coord<-reactiveValues("x" = NULL, "y" = NULL)
observeEvent(input$execute, {
req(input$numY, input$numX)
tempx<-c(isolate(coord$x), input$numX)
tempy<-c(isolate(coord$y), input$numY)
coord$x <- tempx
coord$y <- tempy
})
output$plot <- renderPlot({
req(input$execute)
plot(x=isolate(coord$x),y=isolate(coord$y))
})
output$TABLE<-renderTable({
data.frame("x" = coord$x, "y" = coord$y)
})
}
shinyApp(ui = ui, server = server)
Best of luck! Though I had hiccups along the way, I really enjoyed learning Shiny myself, and I hope you do too!
I have the following example:
library(shiny)
ui <- fluidPage(
textOutput("out"),
actionButton("plusX", "Increase X"),
actionButton("redraw", "redraw")
)
server <- function(input, output, session) {
x <- 0
observeEvent(input$plusX, {x <<- x+1})
output$out <- renderText({
input$redraw
x
})
}
shinyApp(ui, server)
Is this considered an anti-pattern in Shiny to modify a non-reactive variable in this way? Obviating the super assignment which can be problematic by itself.
I know this could be done, for example with a reactiveVal to store X, and isolate to obtain a similar result. This second way seems clearer and that would be my usual choice, but I was wondering if there any caveats in the first one, or it is possible way of doing that.
library(shiny)
ui <- fluidPage(
textOutput("out"),
actionButton("plusX", "Increase X"),
actionButton("redraw", "redraw")
)
server <- function(input, output, session) {
x <- reactiveVal(0)
observeEvent(input$plusX, {x(x()+1)})
output$out <- renderText({
input$redraw
isolate(x())
})
}
shinyApp(ui, server)
In this example there is no important difference between both codes as you are not using the benefit of ReactiveVal.
The benefit of ReactiveVal is that it has a reactive nature and thus can interact with other reactive elements.
Try for example to add a table to your code that depends on x:
output$tab <- renderTable({data.frame(y = x)})
(x() in the case of ReactiveVal)
The difference you will see that in the case of ReactiveVal the table automatically updates with plusX whereas in the case of the regular variable it does not update.
I have a Shiny app where I have a dynamically created tabsetPanel where each tab contains a table. I do not know how many tabs/tables will be created in each session by users. I understand that it is bad practice to put render* functions inside observe or observeEvent calls but I can't think of any other way to do this. A minimal example of what I'm trying to do is shown below, which just picks a data set randomly to display on a given tab. Essentially, I'm trying to figure out how to call my table renderers without putting them inside an observe. More generally, although I have read it is bad practice to do this, I would also appreciate an explanation of exactly why it's not a good thing to do:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput("tabs", "Number of tabs", value = 5),
),
mainPanel(
uiOutput("mytabset")
)
)
)
server <- function(input, output) {
output$mytabset <- renderUI({
mytabs <- lapply(seq_len(input$tabs), function(x) {
tabPanel(
paste("Tab", x),
tableOutput(paste0("tab", x))
)
})
do.call(tabsetPanel, mytabs)
})
observe({
set.seed(1)
lapply(seq_len(input$tabs), function(x) {
output[[paste0("tab", x)]] <- renderTable({
sample(list(mtcars, iris, trees, cars), 1)
})
})
})
}
shinyApp(ui = ui, server = server)
I haven't used them in a while, but I think if you use modules, you can call them from outside of a reactive context, and won't need an observe..? :)
I am trying to have multiple html outputs in my shiny App but it seems like it can only show one at a time.
My UI is:
# ui.R
shinyUI(
mainPanel(
tableOutput("view"),
plotOutput("view2")
))
And my server is:
# server.R
library(googleVis)
library(RMySQL)
shinyServer(function(input, output) {
datasetInput <- reactive({
"try2" = subset(try1, idCampaign == input$inputId)
})
output$view <- renderGvis({
gvisTable(datasetInput(),options=list(width=1000, height=270, col='blue'))
})
output$view2 <- renderGvis({
gvisScatterChart(datasetInput2())
})
})
in the output to view2 you use datasetInput2() , this should be datasetInput(). Here datasetInput() just represents a dynamic version of a dataframe, you can use it in as many functions as you want, there is no need to index it.
alternatively i think you can use the tabsetPanel to divide your main page into certain parts and assign output objects to each of your tabPanel.