Having trouble getting 2x2 table Mosaic Plot to display in R-shiny - r

raw data
I'm creating an Rshiny app that will allow a user to upload some clinical data, and view several different plots, based on the tabs they open. These include a line plot, pie chart, and mosaic plot. I'm able to view the line plot and pie chart, based on the uploaded data and user inputs, but having trouble getting the mosaic plot to appear. I get an error that says "object 'input' not found."
I tried to use the ggmosaic(geom_mosaic), and structable packages in R to display the plot. In my data table of interest, there are 5 columns: REF(reference method result for 2x2 contingency table, which is binary -- either POS or NEG clinical result), Result(4 diff values: True Positive, False negative, True negative, false positive), Value(number of patients for each result), SampleType(type of patient sample-- NS,NP, Overall are the 3 possible data values for this column) and Comparator(POS or NEG clinical result). In parenthesis, I have included the types of values one would expect for each column. Furthermore, For my R shiny mosaic app, I have several user inputs on the left hand side, which will allow the app to be constructed once the user has selected them: select input for REF column, select input for Sample type column, select input for comparator. I have code written inside the server function that uses these 3 inputs to construct the mosaic plot.
EDIT: I have attached my raw data in the link at the very top titled "raw data."
mosaic plot data table - takes data from pie chart, but displays it in a #different visual format
MosaicDF <- reactive({
#display mosaic
Mosaic_filtered <- select(PieData_extracted(),-c(3,5:7))
#data transformation
names(Mosaic_filtered)[1]<-"REF"
Mosaic_filtered$SampleType <- "NS"
Mosaic_filtered$Comparator <- c("POS","NEG","NEG","POS")
Mosaic_filtered$REF <- c("POS","POS","NEG","NEG")
Mosaic_filtered$F2 <- factor(as.character(Mosaic_filtered$Value))
MYRaw <- Mosaic_filtered[rep(rownames(Mosaic_filtered),as.numeric(as.character(Mosaic_filtered$F2))), ]
MYRaw <- as.data.frame(MYRaw)
#update select input for mosaic plot
updateSelectInput(session, inputId = 'REF', label = 'Select Reference column',
choices = names(MYRaw), selected = "")
updateSelectInput(session, inputId = 'SampleType', label = 'Select Sample Type column',
choices = names(MYRaw), selected = "")
updateSelectInput(session, inputId = 'Comparator', label = 'Select Comparator column',
choices = names(MYRaw), selected = "")
return(MYRaw)
})
#display mosaic plot
output$mosaic <- renderPlot({
ggplot(data=MosaicDF())+geom_mosaic(aes(x=product(input$REF,input$Comparator),fill=input$REF))+labs(x="Comparator",y="REF")
})
}
I'm getting the data table(from which the mosaic plot is constructed) to appear as an output, but the mosaic plot itself won't show up. It says:
"Error: object input not found".
The pie chart data table and pie chart itself do appear on the tab for this plot. (There are 3 tabs for each of the different plots within the R shiny app, of which the user can select any of these, choose some inputs from a dropdown menu, and allow an app to be automatically built based on the inputs).
I'm wondering if there's a way to modify the code for either my reactive data table or the plot itself-- should I change my code for ggplot, or use a different mosaic package for the Rshiny format?

Without providing an example consisting of both data and code that folks can copy and run to reliably reproduce your error, it is difficult to say what thing(s) is(are) going wrong.
However, here is an example shiny app based on the titanic example in the help page for geom_mosaic().
library(ggmosaic)
library(rlang)
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("REF", "REF", "Survived"),
selectInput("Comparator", "Comparator", c("Class", "Sex", "Age"))
),
mainPanel(
plotOutput("old_mosaic"),
plotOutput("new_mosaic")
)
)
)
server <- function(input, output) {
titanic_data <- reactive({
data(Titanic)
titanic <- as.data.frame(Titanic)
titanic$Survived <- factor(titanic$Survived, levels=c("Yes", "No"))
titanic
})
output$old_mosaic <- renderPlot({
ggplot(data = titanic_data()) +
geom_mosaic(aes(weight = Freq, x = product(input$REF, input$Comparator), fill = input$REF)) +
labs(title = "Old Way")
})
output$new_mosaic <- renderPlot({
ggplot(data=titanic_data()) +
geom_mosaic(aes(weight = Freq, x = product(!!sym(input$REF), !!sym(input$Comparator)), fill = !!sym(input$REF))) +
labs(title = "New Way")
})
}
shinyApp(ui, server)
The code that produces the first plot is similar to your ggplot code which attempts to use the input$id(s) as is. On my machine, this first plot produces the error you describe, and in other cases it seems this approach produces the same error.
The solution at the time of that post was to substitute aes_string() in place of aes(). However, here we should not do that because aes_string() is soft-deprecated; and more importantly, we cannot just use aes_string() because we still need to contend with the product() element.
Returning to the example app, notice the second plot is rendered without issue. In this code, I have employed the new idiomatic way which converts the input string to a symbol and then unquotes it.
Therefore, if I am correct, and this is the source of your error, then you should wrap each input$id with a !!sym() in your ggplot code.

Related

How to remove NA value from the ggplot in shiny app?

library(shiny)
library(palmerpenguins)
library(ggplot2)
library(dplyr)
penguin <- penguins
penguin$year <- as.factor(penguin$year)
ui <- fluidPage(
titlePanel("Data Visualisation of Penguins Data"),
sidebarPanel(
selectInput("yaxis",
label = "Choose a y-axis variable to display",
choices = list("bill_length_mm",
"bill_depth_mm",
"flipper_length_mm",
"body_mass_g"),
selected = "bill_length_mm"),
selectInput("xaxis",
label = "Choose a x-axis variable to display",
choices = c("species",
"sex",
"year"),
selected = "sex"),
checkboxGroupInput("islandlevels",
label = "Check to display different island levels",
choices = c("island"),
selected = NULL),
br(), br(),
selectInput("species",
label = "Choose species to view separate plot",
choices = list("Adelie",
"Chinstrap",
"Gentoo"),
selected = NULL)),
mainPanel(
plotOutput("plot1"),
br(), br(),
plotOutput("plot2")
)
)
server <- function(input, output){
output$plot1 <- renderPlot({
if(is.null(penguin))
return(NULL)
ggplot(penguin, aes(x = penguin[[input$xaxis]], y = penguin[[input$yaxis]])) +
geom_boxplot()
})
}
shinyApp(ui = ui, server = server)
This is my shiny code, but I'd like to remove NA value when x-axis variable is sex.
I can't just remove row with NA values because I have to use variable (that is not missing value but the row has missing value such as row 9 in image 2) when I change x-axis variable or/and y-axis variable.
I wanted to find the solution but I wonder what function should I use. Do I have to use if statement, reactive function, or else?
Thank you for help in advance.
sex variable with NA value(want to delete NA on my plot)
You can prevent the NA values of showing up as categories by making use of scale_x_discrete(na.translate = FALSE):
library(ggplot2)
library(palmerpenguins)
ggplot(penguins, aes(x = sex, y = bill_length_mm)) +
geom_boxplot() +
scale_x_discrete(na.translate = FALSE)
#> Warning: Removed 11 rows containing missing values (stat_boxplot).
Conditionally filter your data, perhaps something like this:
dat <- reactive({
if (input$xaxis == "sex") penguin[ !is.na(penguin$sex), ] else penguin
})
output$plot1 <- renderPlot({
req(penguin, input$xaxis, input$yaxis)
ggplot(dat(), aes_string(x = isolate(input$xaxis), y = input$yaxis)) +
geom_boxplot()
})
Several critical changes here:
In case you want to do more than a single plot with the filtered data, I make a reactive data component named dat with the filtered data. In this way, if you ever add (say) a table or another plot or something, you don't need to handle selective filtering in each of them, you just need to use dat() everywhere and everything benefits from it.
Reactive can be volatile, and having both the data and the plot reacting to input$xaxis will cause the plot to be rendered twice for each change to xaxis. Because of this, I isolate(input$xaxis) in the plot reactive. When the user changes xaxis, the dat will change which will trigger (once!) the plot to change. (No need to isolate yaxis, as that's correct in this case.)
In general, you should not use ggplot2(x, aes(x$a, x$b)). More specifically, using $ and/or [[ in aesthetic definitions is poor practice, and will fail given certain situations. It is much better to use aes with symbols (e.g., cyl from mtcars) or aes_string with strings ("cyl"). Since you're defining the aesthetics programmatically, it is better to use aes_string.
I changed your if (is.null(penguin)) to shiny's more canonical req, and added checks in the inputs as well. While most simpler shiny apps don't always need this, I've found that more complex apps can cause just enough delay in input instantiation that an output reactive block may trigger before all inputs have been assigned, meaning in this example it might be possible for input$xaxis to be null. While unlikely in simpler shiny apps like this, I still think it's safe.
There may be reasons to use individual req lines, one for each input. The results in this case will be the same, but there are times when it makes sense to break them out.
The use of req prohibits the rest of the plot rendering from occurring, but it also does it in a way that shiny components recognize, not causing errors or rendering issues. (I prefer it to manual if (is.null(.)) return(NULL) logic.)
Note: I think #stefan's answer may be the more canonical way in ggplot2 to omit NA values from the axis, so perhaps that is the best way to go for that side of things. However, I still believe that points 3 and 4 are still (also) relevant to your app even with stefan's change.

Creating if functions with checkboxes in R-shiny

I am currently doins a personal project to get used to using R-shiny. I am using the penguins dataset in R. This project is creating several different boxplots. I have been able to create the main code for the boxplots to show and now I am trying to use the checkbox input to allow the user to select if it wants the boxplots to be divided by the Islands ivestigated or rather just see the data as it.
My code is the following.
library("palmerpenguins")
library("shiny")
library("ggplot2")
penguins.data<- penguins
sum(is.na(penguins))
#As their are a few penguins with missing values (19 out of 2752) we decide to carry out the data visualization with
#Only the complete cases of the data
penguins.data<-na.omit(penguins.data)
#Making sure the categorical variables are factors
str(penguins.data)
penguins.data$species<-as.factor(penguins.data$species)
penguins.data$sex<-as.factor(penguins.data$sex)
penguins.data$year<-as.factor(penguins.data$year)
penguins.data$island<-as.factor(penguins.data$island)
#Defining the UI for the App.
ui <- fluidPage(
#Adding a suitable title
titlePanel("Penguin exploration"),
#Getting the layout
sidebarLayout(
#Setting the panel for the used to select the inputs they want
sidebarPanel(
#Selecting the variable for the X-axis
selectInput("horiz", "Select x-axis variable:",
c("Sex" = "sex",
"Species" = "species",
"Year" = "year"),
selected = "sex" ),
#Selecting the variable in the Y-axis
selectInput("vert", "Select y-axis variable:",
c("Bill Length" = "bill_length_mm",
"Bill Depth" = "bill_depth_mm",
"Flipper length" = "flipper_length_mm",
"Body mass" = "body_mass_g"),
selected = "flipper_length_mm" ),
#We create the checkbox input for the user to select if they want to see the data in
checkboxInput("Divide", "check to look at how data is divided by Island Level", value = F)),
mainPanel(
#Setting a title for the output
h3("plot"),
#We decide how to name the plot to use it in the output
plotOutput("PengPlot")
),
)
)
server <- function(input, output) {
horizontal<-reactive(input$horiz)
vertical<-reactive(input$vert)
output$PengPlot <- renderPlot({
if(output$Divide){
ggplot(data = penguins.data, aes_string(horizontal(), vertical()))+
geom_boxplot(aes(fill= island))+
facet_wrap(~horizontal())
}else{
ggplot(data = penguins.data, aes_string(horizontal(), vertical()))+
geom_boxplot()
}
})
}
shinyApp(ui = ui, server = server)
I am currently getting the error Reading from shinyoutput object is not allowed. I am lost on what specifically to do. I am considering if maybe creating both boxplots as reactive objects and then use the if functions but I have seen in other posts that doing that may overcomplicate the code.
Any advice or help will be great. Thank in advance

R Shiny: "Reactive" data analysis based on user input, followed by ggplot figure output

I have a basic R code where, within the code, a user can enter a country name "Argentina". Using that value/name, the code will run an analysis for the "Argentina" subset of the pre-loaded data. Finally, the code will produce a simple ggplot showing results.
I have tried to make this code into a Shiny App, however I cannot get it to work properly. My main issue is that I cannot seem to get the data analysis in the Server section to work, which should subsequently feed into the plotting code. More importantly, I cannot seem to get the user inputted country name to feed into my data analysis.
Without going into the detail of the code, could someone kindly point me in the right direction of how one would do this in Shiny? e.g.
Field for user input;
Use that user input as an object used in the code;
subsequently run the analysis (whatever it might be); and
use the final analysis data frame in ggplot for a figure output to be displayed in the shiny app.
Please see my shiny code currently used, with reproducible data using MTcars
library(shiny)
# Some Sample data to run app using mtcars
mtcars$Primary<- rownames(mtcars)
mtcars$Area <- "Argentina"
mtcars$Y2016<- mtcars$mpg
mtcars$Element <- "Gross Production Value (constant 2004-2006 million US$)"
# Defining UI ----
ui <- pageWithSidebar(
# App title ----
headerPanel("Subsector Selection Tool"),
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Country name
textInput("country", "Please enter country name", "")#,
),
# Main panel for displaying outputs ----
mainPanel("")
)
# Define server logic to plot various variables against mpg ----
server <- function(input, output) {
#Trying to make user inputed country name into an object to be used in
"reactive" code below, which in turn is be used to make dataset for graphing
country_interest <- reactive({
paste(input$country)
})
#Here I am trying to make the data analysis code run and create desired
dataset for graphing, and subsetting for country selected by user
Value_c_e_PRIM_x <- reactive({
Value_c <- Value[which(Value$Area==country_interest),]
Value_c_e <- Value_c[which(Value_c$Element=="Gross Production Value (constant 2004-2006 million US$)"),]
Value_c_e_PRIM$Primary <- Value_c_e_PRIM[,120]
Value_c_e_PRIM[,120] <- NULL
Value_c_e_PRIM <- Value_c_e_PRIM %>% group_by(Primary,Element) %>% summarise_at(vars(Y2016), sum)
Value_c_e_PRIM$Category <- "Value of Production"
Value_c_e_PRIM$Value <- Value_c_e_PRIM$Y2016
Value_c_e_PRIM <- Value_c_e_PRIM %>% group_by(Category,Primary) %>% summarise_at(vars(Value), mean)
})
#Graphing section, if Ihave the dataset "Value_c_e_PRIM_x" pre-loaded (e.g. not derived in code above), the figure is successfully shown in the output.
output$plot <- renderPlot({
Graph_data <- Value_c_e_PRIM_x
Graph_data$Score_type <- "Competitiveness Score"
Graph_data$`Competitiveness Score` <- round(Graph_data$Value, 2)
title1 <-paste("Competitiveness\nby",paste0(country_interest),"Subsector")
mycol <-c("red", "yellow", "#006600")
ggplot(data = Graph_data, aes(x = Score_type, y = reorder(Primary,Value), fill=Value)) +
geom_tile(aes(fill = Value), colour= "white")+
geom_text(data=Graph_data,aes(y=Primary, x= Score_type, label=Value))+
labs(title =(paste0(title1)),y = "", x = "")+
scale_fill_gradientn(colours = mycol)+
theme(legend.title=element_blank())+
theme(legend.position="bottom")
})
}
shinyApp(ui, server)

How can I use conditions to add data to a ggplot making it interactive?

This is my first question on stackoverflow, so please forgive me if my problem is not perfectly described.
I am working on an interactive plot using R shiny. The aim is to compare air quality data for different cities. This should be done in a ggplot where the user can select a pollutant (y-axis) and a possible correlation factor (e.g. air temperature, x-axis). The user should then be able to select all the cities (as CheckboxGroupInput) of which the data should be plotted. Selecting the two variables (x-/y-axis) works out fine, however I struggle to plot several cities at once.
I already created the inputs, that seem to work out fine. I can also plot one city at a time. I also managed to plot several selected cities, however they are not plotted in the same ggplot, but only the topmost plot is visible (see simplified code below).
UI:
library(shiny)
library(ggplot2)
berlin_d <- read.csv("berlin_d.csv")
london_d <- read.csv("London_d.csv")
warsaw_d <- read.csv("Warsaw_d.csv")
checkboxGroupInput(
inputId = "city",
label = "select a city/multiple cities",
choices = c(
"Berlin" = "Berlin",
"London" = "London",
"Warsaw" = "Warsaw"
)
),
selectInput(
inputId = "box1",
label = "select a variable to plot (x-axis)",
choices = c("temperature" = "temp",
"month" = "month",
"weekday" = "weekday"
),
selected = "temp"
),
selectInput(
inputId = "box2",
label = "select a pollutant to plot (y-axis)",
choices = c("Ozone" = "O3",
"NO2" = "NO2",
"PM10" = "PM10"
),
)
Server:
output$plot <- renderPlot(ggplot()+
geom_point(if (input$city=="Berlin") {aes(berlin_d[[input$box1]], berlin_d[[input$box2]])})+
geom_point(if (input$city=="London") {aes(london_d[[input$box1]], london_d[[input$box2]])})+
geom_point(if (input$city=="Warsaw") {aes(warsaw_d[[input$box1]], warsaw_d[[input$box2]])})
)
I don't understand why the data isn't displayed in the same plot. Is there a way to plot the data in one ggplot and still have the options to select the cities?
Any help is appreciated!
To answer your question a small change in your code should be enough to create the functionality you are looking for.
You have to look at the output of input$city. If you check more than one box the vector length changes and then only the first element will be used when checking the if-clause. To avoid this, you can rewrite the if-clause as follows
if ("Berlin" %in% input$city)
The whole plot would look like this.
ggplot() +
geom_point(if ("Berlin" %in% input$city) {aes(berlin_d[[input$box1]], berlin_d[[input$box2]])}) +
geom_point(if ("London" %in% input$city) {aes(london_d[[input$box1]], london_d[[input$box2]])}) +
geom_point(if ("Warsaw" %in% input$city) {aes(warsaw_d[[input$box1]], warsaw_d[[input$box2]])})
However, a much better approach would be to create one data set containing all the data, where city is just a grouping variable. Then create a reactive Expression subsetting the data in shiny according to the input filter (input$city). Then you can create a plot with one call to ggplot and setting city as a factor variable for colour, for example.

R shiny, cannot set column names with Shiny reactive variable for ggplot

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.

Resources