I'm trying to create a histogram of distances between cells with slidebar that varies the range of the x-axis like this:
ui <- fluidPage(
# Application title
titlePanel("Distribution of distance between nucleus"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("x_range", "Range:",
min = min(histo$Dist_Closest_Cell),
max = max(histo$Dist_Closest_Cell),
value = c(min(histo$Dist_Closest_Cell),
max(histo$Dist_Closest_Cell)))
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
server <- function(input, output) {
output$distPlot <- renderPlot({
# draw the histogram with the specified range
hist(histo$Dist_Closest_Cell,
xlim = c(input$x_range[1], input$x_range[2]),
breaks = 100,
xlab = "Distance µm",
main = "Distribution of distance between nucleus")
})
}
# Run the application
shinyApp(ui = ui, server = server)
histo$Dist_Closest_Cell
I have a DataFrame called histo that has some columns and one of them is Dist_Closest_Cell that contains distance values.
Now, I want to save in a variable as DataFrame the info of histo but in the x-axis range selected with the slidebar. This Shiny App (the code above) is interjected in the middle of a bigger code, so after run the app and choosing the x-axis range I would like to stop the app and return the mencioned DataFrame variable.
I know that with runApp() and stopApp() I could continue with the rest of the code but I don´t know how to write it properly...
Maybe with something like:
...
# Previous code
df <- runApp(
# Above code
return(c(input$x_range[1], input$x_range[2]))
stopApp()
)
# Next code
...
I´m trying this with Shiny because it's the only way to plot a dinamic histogram with slidebar that I've found but if you know another alternative it's welcome.
Thank you in advance.
Related
My app that i built outputs the coordinates of the clicked point but my objective is to output the coordinates of the plotted point and that is by printing out the real correspendent coordinates existing on the x axis .This is the first part of the post i want to resolve, then if it is done then we will deal with the fact that my app deals with an x axis of a date nature then we will plot another plot, instaed of the actual, which in fact based on filtering the data based on that date .But now i want to get using the code below the abscisse which is written on the x axis and not that numerical delivered but R shiny:
library(ggplot2)
library(shiny)
library(shiny)
df<-data.frame("pr"=c("a","n","z","o"),"value"=c(5,1,13,9))
ui <- basicPage(
plotOutput("plot1", click = "plot_click"),
verbatimTextOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
plot(as,factor(df$pr ), df$value)
})
output$info <- renderText({
paste0("x=", input$plot_click$x, "\ny=", input$plot_click$y)
})
}
shinyApp(ui, server)
By the way who can disply the points in form of points and not in form of bars or bold lines like in my example so please do it .i will be thankful.
Hey Shiny and Plumber experts,
Relevant links :
https://abndistro.com/post/2019/07/06/deploying-a-plumber-api-on-aws-ec2-instance/
https://abndistro.com/post/2019/07/06/deploying-a-shiny-app-with-shiny-server-on-an-aws-ec2-instance/
Basically, we are trying to pass the output of shiny via Plumber to other programmers to integrate in an webpage.
From the documentation, running on local machine,
following works individually:
Plumber reprex
#* Plot a histogram
#* #png
#* #get /plot
function(){
random_num <- rnorm(10) * 5
hist(random_num)
}
saving the file as plumber.R
# Running the below in console
r <- plumb("plumber.R") # Where 'plumber.R' is the location of the file shown above
r$run(port=8000)
# Now, loading the browser: http://127.0.0.1:8000/__swagger__/
[![plumber output][1]][1]
Similarly shiny reprex :
library(shiny)
# Define UI for application that plots random distributions
ui = shinyUI(fluidPage(
# Application title
titlePanel("Hello Shiny!"),
# Sidebar with a slider input for number of observations
sidebarLayout(
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 1,
max = 1000,
value = 500)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
# Define server logic required to generate and plot a random distribution
server = shinyServer(function(input, output) {
# Expression that generates a plot of the distribution. The expression
# is wrapped in a call to renderPlot to indicate that:
#
# 1) It is "reactive" and therefore should be automatically
# re-executed when inputs change
# 2) Its output type is a plot
output$distPlot <- renderPlot({
# generate an rnorm distribution and plot it
dist <- rnorm(input$obs)
hist(dist)
})
})
# Run the app
shinyApp(ui, server)
How can we render shiny's output i.e histogram into plumber's swagger ?
i.e. How to display the user
Tried: Embedding the plumber function within Shiny's renderFunction
library(shiny)
# Define UI for application that plots random distributions
ui = shinyUI(fluidPage(
# Application title
titlePanel("Hello Shiny!"),
# Sidebar with a slider input for number of observations
sidebarLayout(
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 1,
max = 1000,
value = 500)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
# Define server logic required to generate and plot a random distribution
server = shinyServer(function(input, output) {
# Expression that generates a plot of the distribution. The expression
# is wrapped in a call to renderPlot to indicate that:
#
# 1) It is "reactive" and therefore should be automatically
# re-executed when inputs change
# 2) Its output type is a plot
#### Embedding inside the shiny
output$distPlot <- renderPlot({
#* Plot a histogram
#* #png
#* #get /plot
function(){
# generate an rnorm distribution and plot it
dist <- rnorm(input$obs)
hist(dist)
}
})
})
shinyApp(ui, server)
I'm trying to create a Shiny app that lets users
create a dataset by entering frequency counts for different values
plot a histogram of that dataset
A paired back example of the code is as follows:
library(shiny)
library(ggplot2)
# Define UI for application
ui <- fluidPage(
# Sidebar with inputs
sidebarLayout(
sidebarPanel(
numericInput("data1s",
"How many have a score of 1?",
value = 0,
min = 0
),
numericInput("data2s",
"How many have a score of 2?",
value = 0,
min = 0
),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 3,
value = 1)
),
# Show a plot of the data
mainPanel(
htmlOutput("mydatatable"),
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
#show the data
output$mydatatable <- renderTable({
#create the dataframe from the frequncies
mydata <- data.frame(our_data=c(rep(1,input$data1s),rep(2,input$data2s))
)
}
)
#show the histogram
output$distPlot <- renderPlot({
ggplot(mydata, aes(x=our_data)) +
geom_histogram(bins = input$bins)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I have achieved the creation of the dataset, but the code for displaying a histogram of the data returns an error: "object 'mydata' not found" instead of showing the histogram. The histogram should update whenever any of the inputs are changed.
Any help to resolve would be much appreciated.
The mydata that you define in the mydatatable reactive is not visible anywhere else. To understand why, I suggest you read about R's namespaces and environments; one good tutorial on it is Hadley's Advanced R -- Environments.
To fix it, I suggest you make the data itself a reactive block, and depend on it in your two other blocks (table and plot):
server <- function(input, output) {
mydata <- reactive({
req(input$data1s, input$data2s)
data.frame(our_data=c(rep(1,input$data1s),rep(2,input$data2s)))
})
#show the data
output$mydatatable <- renderTable({ req(mydata()); })
#show the histogram
output$distPlot <- renderPlot({
req(mydata())
ggplot(mydata(), aes(x=our_data)) +
geom_histogram(bins = input$bins)
})
}
(Untested.)
I added the use of req solely to prevent start-up jittering and warnings/errors in the app. When the shiny app is warming up, it's common to have input variables empty (NULL), and things that depend on it will temporarily produce errors until the inputs stabilize. (For an example of why things will stumble, input$data1s may initially show a NULL value, and try to see if data.frame(our_data=rep(1,NULL)) will work.)
req just looks for something that is "truthy", meaning: not NULL, not NA, not FALSE, length greater than 0, etc. See ?shiny::req for more details.
While req is not strictly required, it has its advantages. As you may infer from the table code, req(x) will return the "first value that was passed in" (from ?req), so it can be used in this shortcut mode for brevity.
And one last soap-box: in my limited experience with shiny reactivity, there are few times that I've generated data within a reactive block and used it solely within that reactive block. Given that, whenever you make a data.frame (or list or ... some important structure that is dependent on user input), it is often beneficial to make it its own reactive component (specifically, not an output component), and then depend on it as many times as necessary.
I cannot use functions from the Crosstalk package in a Shiny app. When running, I receive an error message saying my SharedData object is not found.
I would like to create a Shiny app where users can filter in various ways (selectInput, selecting rows in a data table, etc.) but all tables, charts and maps update simultaneously regardless of the filter method. I have heard that crosstalk is good for this and I have relied on the volcano example here as a template.
My issue is that when I attempt to run my app, I receive a warning saying that the SharedData object cannot be found. I've tried placing this in the server part, and tried placing within reactive, eventReactive, observe, observeEvent, etc. but these don't make any difference. I've also tried placing the code outside of both ui and server parts but the only difference is that my error is now "object of type 'environment' is not subsettable".
Below is not my original code; I have simplified the issue and made it reproducible by sharing the following:
*Created a new Shiny app from Rstudio (the template uses the faithful dataset)
*Modified the dataset from faithful to iris
*Added a call to the crosstalk library
*Included filter_select, SharedData calls
*Modified line 48 to refer to shared_df rather than iris
library(shiny)
library(crosstalk)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Crosstalk test"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
filter_select("rows", "Select rows:",
shared_df,
~Species,
multiple = TRUE)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
# Shared data available for use by the crosstalk package
shared_df <- SharedData$new(iris)
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- shared_df[, 2]
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)
My expected results should include a histogram chart with interactive slider to dynamically adjust bin widths (as per the "old faithful" template). In addition, I should be able to select Species of plant and the histogram should dynamically update to only display results for the selected Species.
* edit *
I've managed to recreate the volcano example linked to above for a Shiny app. The code below works:
library(shiny)
library(crosstalk)
library(leaflet)
library(DT)
# Wrap data frame in SharedData
# Use SharedData like a dataframe with Crosstalk-enabled widgets
sd <- SharedData$new(quakes[sample(nrow(quakes), 100),])
ui <- fluidPage(
# Create a filter input
filter_slider("mag", "Magnitude", sd, column=~mag, step=0.1, width=250),
bscols(leafletOutput("map"), DTOutput("table"))
)
server <- function(input,output) {
output$map <- renderLeaflet({ leaflet(sd) %>% addTiles() %>% addMarkers()})
output$table <- renderDT({
datatable(sd, extensions="Scroller", style="bootstrap", class="compact", width="100%",
options=list(deferRender=TRUE, scrollY=300, scroller=TRUE))
}, server = FALSE)
}
shinyApp(ui = ui, server = server)
The only difference between this volcano example and my iris example is (apart from moving the shared_df outside of ui and server) the usage of filter_select. When I move shared_df a different error is returned: "Warning: Error in [: object of type 'environment' is not subsettable"
I'm trying to make a simple shiny ap for creating kaplan-meier survival curves that are stratified by selection the user makes. When I code the KM calculation statically (with the column name thorTr) it works but the calculation and plot is static. When I replace with input$s I get ERROR:variable lengths differ (found for 'input$s')
I've tried looking at other code which use as.formula and paste, but I don't understand and couldn't get to work. But I am a new R and Shiny user so maybe I didn't get it right. Here is a similar shiny ap but I want to use survminer and the ggsurvplot for plotting
library(shiny)
library(ggplot2)
library(survival)
library(survminer)
#load data
data(GBSG2, package = "TH.data")
#Define UI for application that plots stratified km curves
ui <- fluidPage(
# Sidebar layout with a input and output definitions
sidebarLayout(
# Inputs
sidebarPanel(
# Select variable strat
selectInput(inputId = "s",
label = "Select Stratification Variable:",
choices = c("horTh","menostat","tgrade"),
selected = "horTh")
),
# Outputs
mainPanel(
plotOutput(outputId = "km")
)
)
)
# Define server function required to create the km plot
server <- function(input, output) {
# Create the km plot object the plotOutput function is expecting
output$km <- renderPlot({
#calc KM estimate with a hard coded variables - the following line works but obviously is not reactive
#km <- survfit(Surv(time,cens) ~ horTh,data=GBSG2)
#replaced hard coded horTh selection with the respnse from the selection and I get an error
km <- survfit(Surv(time,cens) ~ input$s ,data=GBSG2)
#plot km
ggsurvplot(km)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)
I expect to have a plot that updates the stratification variable with the users selection
Try using surv_fit() instead of survfit().
surv_fit() is a helper from survminer which does different scoping compared to survival:survit(), which is what you seem to need, as Byron suggests.
My snippet looks like:
output$plot <- renderPlot({
formula_text <- paste0("Surv(OS, OS_CENSOR) ~ ", input$covariate)
## for ggsurvplot, use survminer::surv_fit instead of survival:survfit
fit <- surv_fit(as.formula(formula_text), data=os_df)
ggsurvplot(fit = fit, data=os_df)
})
Two things:
The formula in the call to survfit() needs to be defined explicitly. The object being passed to survfit() in the original code uses a character value on the right hand side of the function. This throws an error, which we can address by translating the entire pasted value into a formula, i.e., as.formula(paste('Surv(time,cens) ~',input$s))
The formula needs to be defined in the call to ggsurvplot() to avoid scoping issues. This is a little more technical and has to do with the way that ggsurvplot() is programmed. Basically, ggsurvplot() can't access a formula that is defined outside of its own call.
Try replacing
km <- survfit(Surv(time,cens) ~ input$s ,data=GBSG2)
ggsurvplot(km)
with
ggsurvplot(survfit(as.formula(paste('Surv(time,cens) ~',input$s)),data=GBSG2))
Hi finally got this to work combinigng both solutions. I don't understand the fix but at least it now works the way I wanted it to :)
library(shiny)
library(ggplot2)
library(survival)
library(survminer)
data(GBSG2, package = "TH.data")
# Define UI for application that plots features of movies
ui <- fluidPage(
# Sidebar layout with a input and output definitions
sidebarLayout(
# Inputs
sidebarPanel(
# Select variable strat
selectInput(inputId = "s",
label = "Select Stratification Variable:",
choices = c("Hormone Therapy" = "horTh",
"Menopausal Status" = "menostat",
"Tumor Grade" = "tgrade"),
selected = "horTh")
),
# Outputs
mainPanel(
plotOutput(outputId = "km")
)
)
)
# Define server function required to create the scatterplot
server <- function(input, output) {
# Create the km plot object the plotOutput function is expecting
output$km <- renderPlot({
## calc survival curve and plot
kmdata <- surv_fit(as.formula(paste('Surv(time,cens) ~',input$s)),data=GBSG2)
ggsurvplot(kmdata)
})
}
# Create a Shiny app object
shinyApp(ui = ui, server = server)