I am relatively new to Shiny and Plotly and have the following code snippet:
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
library(plotly)
library(odbc)
library(DBI)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Demo"),
#Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 0,
max = 100,
value = 70)
),
# Show a plot of the generated distribution
mainPanel(
tabPanel("Heading", plotlyOutput("tbTable"))
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
QueriedData <- reactive({
connn <- DBI::dbConnect(odbc::odbc(),.connection_string = "XXX", uid = "AB", pwd = "CD")
lat_rec.df <- dbGetQuery(connn, "PQR")
dbDisconnect(connn)
lat_rec.df1
})
output$tbTable <- renderPlotly({
plot_ly(QueriedData(),x = ~TotalCount, y = ~MyScore, type = 'scatter', mode = 'markers')
})
}
# Run the application
shinyApp(ui = ui, server = server)
As you can see above, I am plotting a scatter plot of my dataframe which I have read from the Database (as mentioned in the reactive function). I have a couple of questions here:
I want to use the slider bar input as my Y Axis (MyScore). How do I do that? I am currently unable to link slider bar (bins) into my plotly graph. I want the scatter plot to update as per the slider input.
I am slightly confused about reactive functions. Does it mean that each time, I change the slider bar, the DB is going to get called (in reactive function)? How does it work?
If I have other Database tables to read and plot in other areas, do I include it in the reactive function? Please advice.
Thanks in advance for all your help! Cheers!
My solutions/answers to your three questions.
1.As you want to know how to control Y axis with sliderInput below code explains how to do it.
library(shiny)
library(plotly)
library(DBI)
library(pool)
pool <- dbPool(drv = RMySQL::MySQL(),dbname = "db",host = "localhost",username = "root",password = "psw", port = 3306)
data <- dbGetQuery(pool, "SELECT * FROM testTable;")
ui <- fluidPage(
titlePanel("Demo"),
sidebarLayout(
sidebarPanel(
sliderInput("bins", "Number of bins:", min = 0, max = 100, value = 70)
),
mainPanel(
tabPanel("Heading", plotlyOutput("tbTable"),
plotOutput("basicPlot") # Added extra as an Example for 3rd question
)
)
)
)
server <- function(input, output, session) {
QueriedData <- reactive({
df <- data[data$total <= input$bins,] # filtering datafarme based on sliderInput
return(df)
})
output$tbTable <- renderPlotly({
plot_ly(QueriedData(), x = ~count, y = ~total, type = 'scatter', mode = 'markers')
})
# Added extra as an Example for 3rd question
output$basicPlot <- renderPlot({
data_for_plot <- dbGetQuery(pool, "SELECT * FROM dummyTable WHERE uid = 2018;")
plot(x = data_for_plot$category, y = data_for_plot$performance, type = "p")
})
}
shinyApp(ui = ui, server = server)
2.For reactivity it is better to fetch the table into a dataframe once, then place that dataframe in reactive environment. So that you can avoid multiple database calls. You can check in above code for the same.
3.Using of reactive environment purely depends on the requirement when you want to have interactivity with your shiny application. If you want to fetch the data from other tables and use in different plots, then no need to place your database connection string in reactive environment. Just query the database according to your requirement like in above code.
Related
I'm a math student studying data science.
I'm trying to take the user's decision of which columns to use for the graph(plotly), unfortunately, the graph is blank.
I would like the graph a scatter or line plot to show date vs nbrskieur as a default and be able to change either x, y, or both according to the user's preference.
I have not been able to find any tutorials or answers on how to plot with user-chosen columns from an RDS.
help would be much appreciated, thank you
library(shiny)
library(plotly)
# Define UI for the application that draws a plotly from RDS data
ui <- fluidPage(
# App title ----
titlePanel("ploting RDS data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose rds File",
multiple = FALSE,
accept = ".rds"),
selectInput("var1","select the x variable from the file", choices = c("Date","jour","report","noubre de skieur","ndemj", "nbrtotal")),
selectInput("var2","select the y variable from the file", choices = c("Date","jour","report","noubre de skieur","ndemj", "nbrtotal")),
),
# Main panel for displaying outputs ----
mainPanel(
plotlyOutput("skieurdist")
)
)
)
# Define server logic required to draw a plotly with default columns of dates and nbrskieur(number of skiers)
server <- function(input, output) {
output$skieurdist <- renderPlotly({
tbl_rds <- readRDS(input$file1$datapath)
plot.obj <<-list()
plot.obj$tbl_rds <<- tbl_rds
xcol <- as.numeric(input$var1)
ycol <- as.numeric(input$var2)
#p <- plot_ly(plot.obj$table_rds, x = input$var2, y = ycol, type = "scatter")
skieur <- plot_ly(plot.obj$tbl_rds, x = xcol, y = ycol, type = "bar")
# p %>% layout(legend = list(x = 1, y = 0.5 , bgcolor = "#E2E2E2"))
#require(input$submit)
})
}
# Run the application
shinyApp(ui = ui, server = server)
[here is some example of the data that I have][1]```
[1]: https://i.stack.imgur.com/AcZsP.png
I want to design a reactive interaction graph for a time series for shiny.
It is used for when I have a time series. I change the first point of the time series.
Then I can get the reactive graph changed for the point changed.
I have trouble for how to assign the value input into the function. Specifically, for the
yinput<-sensi(num). I want to the input be some number range from 0.1 to 0.9.but my sensitive's
function only allow to enter one input.
Is there any idea for that?
Thanks
library(ggplot2)
sensi<-function(input)
{
y<-c(input,5,12,21,30,50,90,100)
return(y)
}
Date = c("2020/07/16","2020/07/23","2020/07/30","2020/08/06","2020/08/13","2020/08/20","2020/08/27","2020/09/13")
num<-c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9)
yinput<-sensi(num)
df <- data.frame(yinput, Date = as.Date(Date))
ui <- fluidPage(
titlePanel(title=h4("plot1", align="center")),
sidebarPanel(
sliderInput("num", "Number:",min = 0, max = 0.9,value=0.5)),
mainPanel(plotOutput("plot2")))
server <- function(input,output){
dat <- reactive({
test <- df[df$num %in% seq(from=min(input$num),to=max(input$num),by=1),]
print(test)
test
})
output$plot2<-renderPlot({
ggplot(df) + aes(Date, y) + geom_line()})}
shinyApp(ui, server)
Here's a very basic example
You should be doing your 'thinking' inside your 'server' function.
Hopefully this example will show you how reactive inputs and outputs relate to each other, and you can extend it to your plot.
require(shiny)
ui <- fluidPage(
sliderInput("num", "Number:", min = 0.1, max = 0.9, value = 0.5),
textOutput("number_display")
)
server <- function(input, output){
output$number_display <-
renderText({
as.character(input$num)
})
}
shinyApp(ui = ui, server = server)
Where I've said as.character(input$num), you'll want to do something with num to make your plot.
Example shiny app:
library(tidyverse)
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("example"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
selectInput(inputId = "cut",
label = "cut",
# choices = unique(diamonds$cut), # works
choices = unique(my_diamonds$cut), # does not work
selected = "Ideal")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
my_diamonds <- diamonds
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- my_diamonds$carat
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
In this case I am using a faux data frame 'my_diamonds'. In my real code I am connecting to a database using dbplyr and then making some transformations to it, so duplicating that in ui section seems wasteful.
What is the 'right' way to use a dataframe defined in server section to get the unique values, in this case my_diamonds$cut to use as a select input's drop down choices?
Instead of using selectInput in the UI, you can instead use UIoutput in the UI and then define the UI element within the server function using renderUI.
So given that you have defined a UIOutput element called otn_race_selection_op, then we can define that as a selectInput object using the below code. Here getData is a reactive element that updates itself to the latest data. So based on that, you can modify the input choices for your selectInput object
output$otn_race_selection_op <- renderUI({
df <- getData()
options <- sort(unique(df$Race))
selectInput(
inputId = "otn_race_selection",
label = "Race",
choices = c("All", options)
,
selected = "All"
)
})
I'm new to shiny, and I am trying to do a simple density plot where there are 2 groups of data, with reactive 'shifts' in the mean etc.
A simplified summary of this is that one set of data has a mean of 0, and variance of 1. The second set of data has a mean of shift, which is defined in a slider.
I have tried to use reactiveValues, as shown in the code below to store the matrix of observations d1, generated from the density function y values, and the corresponding x values are stored in x.
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("shift",
"shift of 2nd set",
min = -1,
max = 1,
value = 0)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
data <- reactiveValues({
d1 <- matrix(nrow=100, ncol=512)
for(i in 1:70){
d1[i,] <- density(rnorm(1000),from = -3, to = 3)$y
}
for(i in 71:100){
d1[i,] <- density(rnorm(1000, input$shift),from = -3, to = 3)$y
}
x <- density(rnorm(1000),from = -3, to = 3)$x
})
output$distPlot <- renderPlot({
matplot(data$x, t(data$d1), type = "l", lty = 1, col = c(rep(1,70),rep(2,30)))
})
}
# Run the application
shinyApp(ui = ui, server = server)
The above code is largely from the example shiny app, so please excuse any generic references. It should still work.
I was expecting a shiny plot with a slider on the left, and a plot on the right with 100 density lines in 2 colours. When the shift slider is changed the second set of data (red) will slide left or right depending on the shift.
Instead, I get the error message
55: stop
54: .getReactiveEnvironment()$currentContext
53: .subset2(x, "impl")$get
52: $.reactivevalues
47: server [/beavis/Documents/test/app.R#37]
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
Is anyone able to help me fix this code? Any help will be greatly appreciated. Having played around for an hour I believe the issue lies in the reactiveValues section, but nothing so far has worked.
Nice try. You're quite close. What you're missing is two things. You are creating a data object, which becomes reactive (I use reactive instead). This means that whenever you are calling data, you need to call it as data().
Second, your data returns only x. Output of this reactive environment should in your case be a list of x and d1.
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("shift",
"shift of 2nd set",
min = -1,
max = 1,
value = 0,
step = 0.1) # I added a step
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
# This reactive environment can be accessed using data().
data <- reactive({
d1 <- matrix(nrow=100, ncol=512)
for(i in 1:70){
d1[i,] <- density(rnorm(1000),from = -3, to = 3)$y
}
for(i in 71:100){
d1[i,] <- density(rnorm(1000, input$shift),from = -3, to = 3)$y
}
x <- density(rnorm(1000), from = -3, to = 3)$x
list(x = x, d1 = d1) # make sure that all objects are returned
})
output$distPlot <- renderPlot({
matplot(data()$x, t(data()$d1), type = "l", lty = 1, col = c(rep(1,70),rep(2,30)))
})
}
# Run the application
shinyApp(ui = ui, server = server)
Im creating shiny app. for calculating risk score where the user will upload input file and select the input such as ethnic groups, type of calculating score and diseases. After all of the input are selected and file is uploaded, my App. will be run when user click at action button and the output such as graph and dataframe will be shown
Im using observeEvent to control my App for triggering unnecessarily( mulitple handleExpr with one eventExpr), and this is my shorten version of code. Im sorry for my code that is not reproducible.
observeEvent(input$action,{
isolate(system2("bash_script/plink.sh",args = c(input$file$datapath,input$type,input$sum_stat,input$Disease,input$Ethnic,input$Ref)))
output$table_score <- renderDataTable({
percentile <- read.csv("../output/score_percentile.csv",header = T, sep = "\t")
}, selection = "single")
output$table_variant <- renderDataTable({
varaints_in_sample <- fread("../output/summary.csv", header = T, drop = 1)
})
#Plot Graph
output$plot <- renderPlot({
s <- input$table_score_cell_clicked
plot("../output/score_percentile_plot.csv",s,"analysis")
})
})
my problem is that when Im running app for the first time, everything is controllable. However, if I want to select new input. for example im changing input disease from heart disease to another disease. my App. will be triggered unnecessarily although I did NOT click at action button.
So, Is there any way to use observeEvent with one evenExpr for mulitple handleExpr
Thanks everyone for your help!
I think, this is simplified example of your problem. The solution is to put all your input$... inside isolate().
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
actionButton('action', 'Click')
),
mainPanel(
plotOutput("distPlot")
)
)
)
server <- function(input, output) {
output$distPlot <- renderPlot({
req(input$action)
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = isolate(input$bins) + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
shinyApp(ui = ui, server = server)