Reputation: 67
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)
Upvotes: 3
Views: 639
Reputation: 160437
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 aes
thetic 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.
Upvotes: 1
Reputation: 124083
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).
Upvotes: 2