I use a function to plot in R, because this is pretty large code for the plot (hexagonals etc). For the sake of neat code I put this in a function.
It is about a SOM algorithm , that does not really matter for now, but I create the data I need, then I normally plot it with the following code:
mydata <- som_model$codes
var <- 1
title <- names(som_model$data)[var]
dataplot <- matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source('plotHexMap.R')
plotHexMap(dataplot,title,gridsize)
So now I want to do this in Shiny:
observe({
if(input$plottrained>0){
var <- 1
title <- names(som_model$data)[var]
dataplot<-matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source("plotHexMap.R")
output$plot1 <-renderPlot({plotHexMap(dataplot,title,gridsize)})
}
})
Ok so this does not work, but when I just write the plot to a global variable (with <<-) it does exist and I can see it in the plots, so by doing this:
observe({
if(input$plottrained>0){
var <- 1
title <- names(som_model$data)[var]
dataplot<-matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source("plotHexMap.R")
plot1 <<-renderPlot({plotHexMap(dataplot,title,gridsize)})
}
})
What am I missing here? what does shiny need that normal R environment does not to plot this from function?
would really appreciate any help with this! Thanks in advance,
Pieter
Instead of observe, try renderPlot in server:
output$myplot <- renderPlot({
if(input$plottrained>0){
var <- 1
title <- names(som_model$data)[var]
dataplot<- matrix(mydata[,var],nrow=gridsize,ncol=gridsize,byrow=TRUE)
source("plotHexMap.R", local = TRUE) #assuming this file is actually local for you
plot1 <- plotHexMap(dataplot,title,gridsize)
}
else{return(NULL)}
})
And then plotOutput in the ui:
plotOutput('myplot')
Related
I want to create a subset dataframe in shiny to output various filtered options in my ploy. In the UI, my variable PLAN_DIM_CK are my different choices, and each PLAN_DIM_CK number is the what I want to subset by. When I run the code, I get the error "Operation not allowed without an active reactive context (You tried to do something that can only be done inside a reactive expression or observer.)
Can anyone help me with where this issue lies?
# Filter by plan in UI
selectInput(inputId = "PlanID",
label = "Select a Plan",
choices = unique(vbc2$PLAN_DIM_CK)
In the server
#within server
subsetTest <- reactive ({
subset(vbc2, PLAN_DIM_CK == input$planID)})
y <- subsetTest()$RISK_ADJUSTED_HBR
x <- subsetTest()$PANEL_SIZE
output$distPlot <- renderPlot({
ggplot(data = subsetTest(), aes(x=y,y=x))
My best guess would be that you need to use observe. The x and y variables should be inside observe, something similar to this:
observe({
y <- subsetTest()$RISK_ADJUSTED_HBR
x <- subsetTest()$PANEL_SIZE
})
Using global variables like this is not a good option. I would suggest you put this x and y variables inside your renderPlot or create reactive variables from it.
Putting it inside the renderPlot could be something like this:
output$distPlot <- renderPlot({
y <- subsetTest()$RISK_ADJUSTED_HBR
x <- subsetTest()$PANEL_SIZE
ggplot(data = subsetTest(), aes(x=y,y=x))
)}
Using reactive you could do something like this:
subsetTest <- reactive ({
subset(vbc2, PLAN_DIM_CK == input$planID)})
y <- reactive({subsetTest()$RISK_ADJUSTED_HBR})
x <- reactive({subsetTest()$PANEL_SIZE})
output$distPlot <- renderPlot({
ggplot(data = subsetTest(), aes(x=y(),y=x()))
Also, it would be better that you provide a minimal reproducible example from next time so that it would be easy to help you.
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 want to use the functionality of nearPoints() to print out summary statistics for a specific point without printing the x, y associated with that point. I have been able to use this function printing the data frame and variations of the data frame. Is there anyway to suppress those columns
to customize the output? nearPoints comes from the latest version of shiny 0.12.1 but I believe may have been introduced a little earlier.
I know the documentation says this:
Note that these functions are only appropriate if the x and y variables are present in the data frame, without any transformation. If, for example, you have a plot where a the x position is calculated from a column of data, then these functions won’t work. In such a case, it may be useful to first calculate a new column and store it in the data frame.
but wanted to know if there was any kind of work around.
Here is the app that illustrates this problem, note that I'm using all of those libraries in my bigger app:
library(shiny)
library(ggplot2)
library(Cairo)
library(plyr)
library(dplyr)
library(shinydashboard)
library(grid)
library(gridExtra) # also loads grid
library(grDevices)
library(ggmap)
library(sqldf)
cars <- mtcars
ui <- basicPage(
plotOutput("plot1", click = "plot_click"),
dataTableOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
ggplot(cars, aes(x=cyl, y=carb)) + geom_point()
})
output$info <- renderDataTable({
summary_cars <- ddply(cars, .(gear, cyl, carb),
function(dd){as.data.frame(cbind(Mean_hp = mean(dd$hp),
Mean_wt = mean(dd$wt))
)
})
#This works-------------------------------------------------------
# nearPoints(summary_cars, input$plot_click, threshold = 10,
# addDist = TRUE)
#Removing the columns does not work ---------
nearPoints(select(summary_cars,-cyl,-carb), input$plot_click, threshold = 10,
addDist = F)
})
}
shinyApp(ui, server)
I recently start building shiny app but I got stuck. Please help me.Thank you in advance
I am trying to create a bar chart to show the count for different type of cash and different term. This part, the code went well.
And I also want to create the box plot to show the numeric summary for different variables selected by the user. I created a selectInput called "metric" and then create a reactive called "metric1" in server.R. and then use "metric1" as the variables I selected to create box plot in server.R.
But it keep saying "cannot find the function "metric1". I don't know why it regards "metric1" as a function? it should be a vector-name of the variable selected by the user.
And if I use input$metric in ggplot to create box plot directly, it still say Error: " object 'input' not found". Why cannot find input? I have paste the code below. It is not a long code. And please help me!
library(shiny)
library(ggplot2)
cash <- read.csv("cash 042014-032015.csv")
cash$TERM <- as.numeric(cash$TERM)
shinyServer(function(input, output) {
dataset <- reactive({cash[cash$mapped_name %in% (input$model),]})
metric1 <- reactive({input$metric})
output$caption <- renderText({
input$model
})
output$countPlot <- renderPlot({
p <- ggplot(dataset(), aes(Incentive.Type, fill=factor(Incentive.Type))) + geom_bar()+ facet_grid(~TERM, margins=TRUE)+theme(axis.text.x = element_blank(),axis.ticks=element_blank(),legend.text = element_text(size=20))+guides(fill=guide_legend(title="Incentive Type"),title.theme=element_text(size=30))+scale_x_discrete(limits=c("Standard","Standard+Captive","Standard+Customer","Standard+Captive+Customer","Special","Special+Captive","Special+Customer","Special+Captive+Customer"))
print(p)
})
output$summaryPlot <- renderPlot({
p <- ggplot(dataset(),aes(factor(Incentive.Type), metric1()))+geom_boxplot()
print(p)
})
})
Here is the ui.R
library(shiny)
library(ggplot2)
dataset <- cash
shinyUI(
fluidPage(
# Give the page a title
titlePanel("Incentives by Model"),
# Generate a row with a sidebar
sidebarPanel(
checkboxGroupInput("model", "Select Models:",
choices=c("370Z","Altima","Armada","Crew","Cube","Frontier","GTR","Juke","Leaf",
"Maxima","Murano","NV","Other","Pathfinder","Quest","Rogue","Sentra","Titan","Versa","Xterra"),selected="Altima"),
selectInput("metric","Please select an option below:", choices=c("Dealer Commission Amount"="DLR_COMM_AMT", "Total Monthly Payment"="TOT_MO_PMT","Original Loan Amount"="ORIG_LN_AMT", "Rate"="RATE"),
selected="DLR_COMM_AMT"),
width=2
),
mainPanel(
h3(textOutput("caption", container=span)),
plotOutput("countPlot"),
plotOutput("summaryPlot")
)
))
Try changing metric1() in the second ggplot call to metric1. As in:
p <- ggplot(dataset(),aes(factor(Incentive.Type), metric1))+geom_boxplot()
Actually I think you will have to use something like:
p <- ggplot(dataset(),aes_string(factor("Incentive.Type"), "metric1"))+geom_boxplot()
In order to get it to see the value of your variable metric1 and properly interpret the use of string variables inside of ggplot.
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.