So the problem is that I am using xray package called to plot distributions from my data into Shiny dashboard.
Here is an example of the distributions function usage with my data:
ui <- fluidPage(
plotOutput("Distribute")
)
server <- function(input, output, session) {
#For Distribution
distribute <- reactive({
distrLongley=longley
distrLongley$testCategorical=c(rep('One',7), rep('Two', 9))
xray::distributions(distrLongley, charts = T)
})
output$Distribute <- renderPlot({
#distribute()
xray::distributions(longley, charts = T)
})
}
shinyApp(ui, server)
It shows from 3 to 4 distributions but actually it should show more distributions. When running in the console mode, I can see all the plots in plots screen. But when I run it in Shiny, it only shows few charts, which is not the desired output.
I don't know why the function shows all the plots when executing from the RStudio console, but not when executing in Shiny. Unlike in the RStudio plot viewer, there is not an option to move to next page option in Shiny.
The problem is that longley dataset contains 7 columns and xray package creates two 2 x 2 grids of graphs. And on the first graph it shows 4 graph and the second one it shows 3 graphs. The last graph overdraw the first one.
To cope with the problem you can temporarily save two graphs into two PNG file then load them into imageOutput. Please see the code below:
library(xray)
library(shiny)
ui <- fluidPage(
imageOutput("Distribute1"),
imageOutput("Distribute2")
)
server <- function(input, output, session) {
png("x%03d.png")
xray::distributions(longley, charts = T)
dev.off()
output$Distribute1 <- renderImage({
list(src = "x001.png")
}, deleteFile = FALSE)
output$Distribute2 <- renderImage({
list(src = "x002.png")
}, deleteFile = FALSE)
}
shinyApp(ui, server)
Output:
Related
Here's a long-shot question. The below code allows the user to build and alter a scaled-logarithmic curve by altering its 4 parameters, via slider inputs. I'd like to reverse the process, so the user clicks/drags the plot line and a new "exponential" curve parameter is backed into. How to do this in R Shiny?
Later, after figuring out how to derive the exponential parameter, I'll try backing into some of the other curve parameters too.
This image illustrates what I'm trying to do:
Code:
library(shiny)
ui <- fluidPage(
sliderInput('periods','Nbr of periods:',min=0,max=36,value=24),
sliderInput('start','Start value:',min=0,max=1,value=0.15),
sliderInput('end','End value:',min=0,max=1,value=0.70),
sliderInput('exponential','Exponential:',min=-100,max=100,value=10),
plotOutput('plot')
)
server <- function(input, output, session) {
data <- reactive({
data.frame(
Periods = c(0:input$periods),
ScaledLog = c(
(input$start-input$end) *
(exp(-input$exponential/100*(0:input$periods))-
exp(-input$exponential/100*input$periods)*(0:input$periods)/input$periods)) +
input$end
)
})
output$plot <- renderPlot(plot(data(),type='l',col='blue',lwd=5))
}
shinyApp(ui,server)
My Shiny app is getting a little long, as I'm plotting a variety of graphs in a number of panels. Accordingly, to help with some of the organization, I was wondering if it was possible to move the code for the graphs into a separate r-script, and call those graphs from the original r script.
Adding some further complication, the graphs that I'd like to display all require user input from the Shiny app.
Is it possible to use code from another script in R to plot graphs, and, if so, how? Additionally, as there will be multiple graphs, is it possible to specify which graph from the new r-script will go in the designated location, or will I need to create a separate r-script for each graph (which would defeat the purpose of increased organizational oversight)?
I've written some simplified, reproducible code (see below) that I hope will give you an idea of what I'm looking for. Essentially, I'd like any code that produces a graph within renderPlot() to come from a separate r-script.
Many thanks for any help!
library(shiny)
ui <- fluidPage(
mainPanel(
selectInput("input1","Select an option",choices = c("First","Second")),
plotOutput("plot1"),
plotOutput("plot2")
)
)
server <- function(input, output, session) {
output$plot1 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot(1,main = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot(2,main = input$input1)
}
})
output$plot2 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot(1*rnorm(1,10,2),main = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot(2*rnorm(1,50,2),main = input$input1)
}
})
}
shinyApp(ui, server)
You can make a function that takes arguments for the plot that you make like the data and plot title and then passes these arguments to your code that creates the plot. For example, say the only thing that changes is x and the plot title, you can define a function that takes those arguments and then uses them in the code to make the plot. Then you save this in a separate script and call the script using source() in your shiny app.
plots.R
plot_data <- function(x, y=NULL, plot.title){
if(is.null(y)) {
y <- seq(from = 1, by = 1, length.out = length(x))
}
plot(x, y, main = plot.title)
}
Load the function into your global environment using source('plots.R'), make sure plots.R is saved in the same location as your shiny app.
library(shiny)
source("plots.R")
ui <- fluidPage(
mainPanel(
selectInput("input1","Select an option",choices = c("First","Second")),
plotOutput("plot1"),
plotOutput("plot2")
)
)
server <- function(input, output, session) {
output$plot1 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot_data(1, plot.title = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot_data(2, plot.title = input$input1)
}
})
output$plot2 = renderPlot({
if(input$input1=="First"){
##This is where I'd like to call the code for the graph from another sheet.
plot_data(1*rnorm(1,10,2),plot.title = input$input1)
}
if(input$input1=="Second"){
##Again, this is where I'd like to code for the graph from another sheet.
plot_data(2*rnorm(1,50,2),plot.title = input$input1)
}
})
}
shinyApp(ui, server)
Of course this doesn't look like much of a difference, but with complex plots that span multiple lines, turning your plot code into a function will turn multiple lines into just one.
I built a simple app using FactorMineR package to do MCA analysis and clustering depending on selected variables.
The app works fine on my local device, however it does not show any plots (either base plots and ggplots) on shinyapps.io server. I checked the packages and locally and remotley they are the same. I also checked if the MCA() function from FactoMineR pcg even works by extracking some results and rendering them as a table what gave positive results. So there is only the problem with plots drawing. I have been trying to solve it for two days but nothing helps so I am asking you for any advice.
Here is how it looks locally:
Here is the link to the app: https://mikolajm.shinyapps.io/MCA_test/
And a reproducible example
library(shiny)
library(FactoMineR)
library(cluster)
library(ggplot2)
data(tea)
ui <- fluidPage(
# Application title
titlePanel("MCA"),
textOutput("packages"),br(),
tableOutput("table"),br(),
fluidRow(
column(4, checkboxGroupInput("Variables", "Select variables:",
names(tea), selected=c("breakfast", "tea.time"))),
column(4, plotOutput("plot")), column(4, plotOutput("plot1"))),
fluidRow(column(12, plotOutput("dendro", height = "700px", width="1200px"))
)
)
server <- function(input, output) {
## packages checking
output$packages <- renderText({.packages()})
tea_selected <- reactive({
tea[, input$Variables]
})
## table with some results from MCA() fun
output$table <- renderTable({
tea.mca <- MCA(tea_selected(), ncp=9)
tea.mca$eig[1:5,]
})
## mca1
output$plot <- renderPlot({
library(FactoMineR)
par(mfrow=c(2,2))
tea.mca <- MCA(tea_selected(), ncp=9)
})
## mca with ggplot
output$plot1 <- renderPlot({
tea.mca <- MCA(tea_selected(), ncp=9)
tea_vars_df <- data.frame(tea.mca$var$eta2, Variable =names(tea_selected()))
library(ggplot2)
pp <- ggplot(data=tea_vars_df, aes(x=Dim.1, y=Dim.2, label=Variable))+
geom_hline(yintercept = 0, colour = "gray70") +
geom_vline(xintercept = 0, colour = "gray70") +
geom_point()+
geom_text() +
ggtitle("MCA plot of variables ")+
theme_bw()
pp
})
### dendro
output$dendro <- renderPlot({
library(FactoMineR)
library(cluster)
tea.mca <- MCA(tea_selected(), ncp=9)
classif <- agnes(tea.mca$ind$coord,method="ward")
plot(classif,main="Dendrogram",ask=F,which.plots=2)
})
}
# Run the application
shinyApp(ui = ui, server = server)
EDIT: You can see plots obviously, but
ORIGINAL
I could not see plots in your shiny app when I ran your code.
After some digging, my guess is only that:
You use a lot of functions that come with the FactoMineR package. For instance, you use the function MCA in output$plot1 code block. Type MCA in your R command line, and it should print the function. You can see MCA does a lot of stuff and eventually calls plot.MCA. Now type plot.MCA in your R command line. You can see that plot.MCA has a lot of plot commands, and I'm pretty sure this executes all the plotting when you call MCA. I think your problem is that plot in the function plot.MCA is sent to the graphic device, and these plots are not saved, ie they are not return() to the parent environment. This is only speculation.
I'm trying to make a shiny app with a scatterplot and I am getting the error"
Uncaught DefinitionError: Bad specification
polychart2.standalone.js:263
I've read that using renderchart2 will fix this but I still get the same error, I am using the latest dev version of rcharts, and this is my code
UI.R
# A bunch of user input
mainPanel(showOutput("data","polycharts"))
server.R
# combined matrix is declared here
shinyServer(function(input, output)
{
output$data <- renderChart2({
# x and y are the column headers to be plotted
plot <- rPlot(x=x,y=y, data=combined_matrix,
color = "Categories", facet = "Categories",
type='point')
plot$set(dom= 'data')
return(plot)
})
Thanks for your help
Is there any way I can dynamically create a number of renderPlot functions, based on the number of plots I have in a list of ggplots?
I have a Shiny app where instead of having a stable UI, and instead of using renderUI, I am relying on a user-supplied config file to tell Shiny how many plots to show. The config file also supplies data and pretty much helps do most of the heavy lifting.
After much battling, I'm mostly there. With the handy-dandy config file, I can build the correct UI, and generate the correct number of ggplots. The ggplots live in a list, creatively named list_of_ggplots.
But now, I'm at a point where I have a list of ggplots, and I need to allow them to be plotted by using them like this:
output$plot1 <- renderPlot({
print(list_of_ggplots[[1]])
})
But now I have an existentialist crisis -- I can't do it like this, since the user-supplied config file tells me how many plots I have. I can no longer hard code the renderPlot call like is usually done in Shiny, since the number of these functions needed is defined in the config file.
Given my list of ggplots, I need some way to generate the renderPlot calls.
Has anyone done this or have any ideas? Much appreciated.
Here's my code:
SERVER.R:
library(shiny)
library(ggplot2)
# 3 simple plots of different colors -- used here instead of all the complicated stuff
# where someone uses the config file that specified 3 plots, with data, etc.
ggplot_names <- c("p1", "p2", "p3")
ggplot_colors <- c("red", "blue", "green")
list_of_ggplots <- list()
j = 1
for (i in ggplot_names){
i <- ggplot(data.frame(x = c(-3, 3)))
i <- i + aes(x)
i <- i + stat_function(fun = dnorm, colour=ggplot_colors[[j]])
list_of_ggplots[[j]] <- i
j <- j+ 1
}
## here's the problem -- the user specified 3 plots.
## I can't hardcode the following shinyServer functions!!!
## What if tomorrow, the user specifies 2 plots instead?
shinyServer(function(input, output) {
output$plot1 <- renderPlot({
print(list_of_ggplots[[1]])
})
output$plot2 <- renderPlot({
print(list_of_ggplots[[2]])
})
output$plot3 <- renderPlot({
print(list_of_ggplots[[3]])
})
})
UI.R
## this top part is actually sourced from the config file
## since Shiny needs to know how many tabPages to use,
## names for the tabs, etc
number_of_tabPages <- 3
tab_names <- c("", "Tab1", "Tab2", "Tab3")
tabs<-list()
tabs[[1]]=""
for (i in 2:(number_of_tabPages+1)){
tabs[[i]]=tabPanel(tab_names[i],plotOutput(paste0("plot",i-1)))}
## Here's the familiar UI part
shinyUI(fluidRow(
column(12,
"",
do.call(navbarPage,tabs)
)
)
)
You can use this solution (I modified only the shinyServer part of your scripts, so I don't list the repeating code here):
shinyServer(function(input, output) {
observe(
lapply(seq(3),function(i) output[[paste0("plot",i)]] <- renderPlot(list_of_ggplots[[i]]))
)
})
Of course, you can replace 3 by a variable.