Hi I have a shiny app that helps a user visualize electropherograms (essentially spectra) that come from automated DNA sequencers. I would like the user to be able to hover over a peak and find out the time the peak came off the instrument. I also would like to be able to compare multiple electropherograms by plotting the spectra one above the other.
If I plot a single spectrum, I can recover the mouse x-position with the 'hover' option provided to plotOutput() in the ui. If I stack plots using base graphics and the par(mfrow=c(n,1)) where n is the number of spectra, the results are unpredictable. Basically the x-position is recoverable in part of the plot region but not throughout.
As a final piece of information, I wrote this app several years ago and it's been working as expected until I updated R and the shiny package to fairly recent versions: (R 3.4.4; shiny 1.2.0).
I've included an app.R file that reproduces this issue on a simple case using histograms and the old-faithful data and shows the approach I have been taking. I get the same behavior whether I set 'clip' in hoverOpts to TRUE or FALSE.
Thanks for any help
allan
library(shiny)
ui = fluidPage(
titlePanel("Mulitpanel hover: Old Faithful Geyser Data"),
sidebarLayout(
sidebarPanel(
sliderInput("bins","Number of bins:",min = 1,max = 50,value = 30)
),
mainPanel(
textOutput("xpos"),
plotOutput("distPlot",hover=hoverOpts(id="plot_hover",clip=TRUE))
)
)
)
server = function(input, output) {
output$xpos = renderText({paste("x coord:",input$plot_hover$x)})
output$distPlot = renderPlot({
x = faithful[, 2]
bins = seq(min(x), max(x), length.out = input$bins + 1)
par(mfrow=c(2,1))
hist(x, breaks = bins, col = 'darkgray', border = 'white')
hist(x, breaks = bins, col = 'orange', border = 'white')
})
}
shinyApp(ui = ui, server = server)
Related
I have a shiny app where I am using a shinyWidgets::sliderTextInput() slider to select a numeric value, but the scale is a bunch of consecutive numbers, then one quite far away. (In my case, it's select a year out of 2000-2010, or 2050).
Is there a way to use css to add visual space between two specific ticks on a shiny slider? In the reprex below, I use the default histogram shiny to select number of bins out of c(1:30,50). Here, I'd like the slider bar to show ticks 1:30 evenly spaced, then some sort of visual gap between the last two ticks (30 and 50) just to visually make it clear those are not consecutive. That space doesn't have to be 20 units long (the actual numerical difference), just an extra bit to help the user notice the difference.
I don't want to add in a "NA" to my selection vector because I don't want the space between those ticks to be selectable.
Based on Chrome web inspector, I know it has to do with object class irs-grid and irs-grid-pol, but I can't figure out how to change the spacing of those.
Thanks in advance!
reprex:
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(
shinyWidgets::sliderTextInput(
inputId = "bins",
label = "Number of bins:",
selected = 20,
choices = c(1:30, 50),
grid = TRUE
),
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 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)
I have an output that takes user input to select which of a number of calculations to use and results in 5 numbers. That output pushes out the results of this and other calculations as an HTML table. The individual calculations are not particularly complicated, but user selections choose which of many approaches they are using, so I don't really want to replicate all that code in other outputs that are going to use just those 5 numbers.
My thought was to use the double-arrow to make those numbers available to the other outputs (in my case some plots). My goal is to generate graphs from numbers already generated in a different output, however that gets accomplished. I am not attached to the approach below, it is just where I am right now.
I ran into a number of problems just using <<- and tried a lot of things to get it to work. I won't complicate this further with all the things I tried and the problems they created.
The MRE below replicates this by calculating a number in one output that is then to be used in another output. If you enter different numbers of bins, the second output is never triggered to update to the new number. For this MRE I could of course directly use the user input to calculate that number but that is what I am trying to avoid in the real app. I also don't want to use a "Go!" button if I can avoid it since part of the fun is watching how things change in response to your various selections.
# 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(
numericInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot"),
textOutput("binnum")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
a_number<-0
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
a_number<<-bins[2]/5}
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
output$binnum<-renderText({
a_number
})
}
# Run the application
shinyApp(ui = ui, server = server)
Could you just treat bins and a_number as reactive?
# 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(
numericInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot"),
textOutput("binnum")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
# a_number<-0
# generate bins based on input$bins from ui.R
data(faithful)
x <- faithful[, 2]
bins <- reactive({
seq(min(x), max(x), length.out = input$bins + 1)
})
a_number <- reactive({
req(bins())
-bins()[2]/5
})
output$distPlot <- renderPlot({
# draw the histogram with the specified number of bins
hist(x, breaks = bins(), col = 'darkgray', border = 'white', xlab = paste0("a = ", -bins()[2]/5))
})
output$binnum<-renderText({
a_number()
})
}
# Run the application
shinyApp(ui = ui, server = server)
I am trying to run the example shiny app (I added the options(encoding = 'UTF-8')):
options(encoding = 'UTF-8')
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("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 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)
and the image has not encoded the names (titles).
UPDATE
I tried to use par(family ="Ubuntu Mono") in the R script and it works. But, it doesn't work in the shiny app (tried it inside render plot).
This looks like a font conflict.
You could circumvent it by setting a custom font available on your system that does get rendered correctly.
For base graphics, use par(family = "serif") or
renderPlot(..., family = "serif") in Shiny.
For ggplot2 graphics, set theme(text = element_text(family = "serif"))
for an individual plot, or use base_family in supported themes, e.g.
theme_gray(base_family = "serif").
In all of the above, replace "serif"
with the font you want to use. For example, you specifically mentioned
"Ubuntu Mono" rendering correctly in your case.
As an exercise, I have modified the default Old Faithful Geyser Data app to incorporate asynchronous programming. However it's behaviour doesn't satisfy my expectations based on my understanding of asynchronous programming I suspect there is a fundamental misunderstanding on my part.
Here, the app creates 2 plot outputs that are identical. One takes longer than the other but set up to work asynchronously, the other is fast.
server.R
library(future)
library(promises)
library(shiny)
plan(multisession)
function(input, output) {
bins = reactive({
future({
print("I'm slow")
Sys.sleep(10)
faithful[, 2]
}) %...>%
{seq(min(.), max(.), length.out = input$slow_bins + 1)}
})
output$slow_dist_plot <- renderPlot({
bins() %...>%
{hist(faithful[, 2], breaks = ., col = 'darkgray', border = 'white')}
})
output$fast_dist_plot = renderPlot({
print("I'm fast")
x <-faithful[, 2]
bins = seq(min(x), max(x), length.out = input$fast_bins + 1)
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
ui.R
library(shiny)
fluidPage(
titlePanel("Old Faithful Geyser Data"),
sidebarLayout(
sidebarPanel(
sliderInput("slow_bins",
"Number of slow bins:",
min = 1,
max = 50,
value = 30),
sliderInput('fast_bins',
'fast bins',
min = 1,
max = 50,
value = 30)
),
mainPanel(
plotOutput("slow_dist_plot"),
plotOutput("fast_dist_plot")
)
)
)
Based on my understanding of asynchronous programming mainly derived from this Rstudio post, if two users are running this code at the same time, after the initial plotting of the two plots, if one of the users change the slow bins the other user should be free to play around with the fast bins and get instant plots as the other users request is processed by a new process.
However when I actually try this with two windows, I see that whenever I make a change in the slow bin, the other windows have to wait for slow bins to complete. What is going wrong here? Are my expectations wrong or did I set this up wrongly?
Expected behaviour in the question is correct. However, on a single core machine, the number of workers is set to 1 by default when using multisession plan. Doing
plan(multisession,workers = 2)
will have the expected behaviour. Raising the number is probably necessary for an app in live use.
so I wrote a shiny app for importing data and plotting it using ggplot2. If I use cairo for plotting
options(shiny.usecairo=T)
(should be active by default) plots are prettier but y axis label "Oxygen consumption" miss some parts.
Plot without cairo:
Plot with cairo:
Can someone point me towards a solution or have ideas what the mistake is?
Edit: here is a minimal example:
library(shiny)
library(ggplot2)
options(shiny.usecairo=T)
# 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("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
sliderInput("size",
"size:",
min = 0.1,
max = 40,
value = 15)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
res<- reactive({input$resolution})
output$distPlot <- renderPlot({
#refresh on
print(input$resolution)
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
qplot(x, breaks = bins, col = 'darkgray', ylab = "Some long string to test for errors and see what is affected")+theme_classic(base_size=input$size)
})
}
# Run the application
shinyApp(ui = ui, server = server)
So, for me it looks like some characters get cut on the right.
Edit: I narrowed this down to my windows machine, can't see it on shinyapps.io and local linux server anymore. Probably not so relevant then, since the error is only happening during development.