Remove blank categories from a dynamic bar plot

I've written a function to create a plot with data that changes based on a filter input, below is a simplified reprex:

            library(tidyverse)                                               
               library(plotly)
one<- as.numeric(NA)
two<- 25
three<- 35
four<- 40
five<- 0
dat<- data.frame(one, two, three, four, five)

  get_plot <- function(x, a){
    data<- x[, a]                       
    p<- data %>%  
        pivot_longer(everything(), names_to="variable", values_to="value") %>%
        ggplot(aes(x = reorder(variable, value), y = value, fill = variable, text = paste0(value*100, "%"))) +
        geom_bar(stat = "identity",position = "dodge")+
        theme(axis.title.x=element_blank(),
              axis.text.x=element_blank(),
              axis.ticks.x=element_blank(),
              axis.title.y=element_blank(),
              legend.position = "none")+
              coord_flip()
    ggplotly(p, tooltip = c("text")) %>% config(displaylogo = FALSE,
                                                modeBarButtons = list(list("toImage")))
  }
  
get_plot(dat, a= c(1:5))

Depending on the filter sometimes I end up with a chart with categories that don't have values in them because the filtered data frame I feed the function ends up looking like dat from my reprex. How do I exclude categories from appearing on the plot when the value is 0 or NA?

Welcome to the community!

I don't see a filter step in your code. So just based on general assumptions, you can use droplevels function.

See this example:

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

iris %>%
    filter(Species != "setosa") %>%
    str()
#> 'data.frame':    100 obs. of  5 variables:
#>  $ Sepal.Length: num  7 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 ...
#>  $ Sepal.Width : num  3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 ...
#>  $ Petal.Length: num  4.7 4.5 4.9 4 4.6 4.5 4.7 3.3 4.6 3.9 ...
#>  $ Petal.Width : num  1.4 1.5 1.5 1.3 1.5 1.3 1.6 1 1.3 1.4 ...
#>  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 2 2 2 2 2 2 2 2 2 2 ...

iris %>%
    filter(Species != "setosa") %>%
    droplevels() %>%
    str()
#> 'data.frame':    100 obs. of  5 variables:
#>  $ Sepal.Length: num  7 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 ...
#>  $ Sepal.Width : num  3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 ...
#>  $ Petal.Length: num  4.7 4.5 4.9 4 4.6 4.5 4.7 3.3 4.6 3.9 ...
#>  $ Petal.Width : num  1.4 1.5 1.5 1.3 1.5 1.3 1.6 1 1.3 1.4 ...
#>  $ Species     : Factor w/ 2 levels "versicolor","virginica": 1 1 1 1 1 1 1 1 1 1 ...

Created on 2021-04-01 by the reprex package (v1.0.0)

Hope this helps.

1 Like

Thank you for the welcome. First post! long time reader. I didn't include the filter step to make the reprex more simplified because the whole thing is actually part of a bigger shiny renderPlotly function. The filter happens before the function and gets me the data frame I'm calling "dat" in the reprex. Then if you run the function like I have at the end of the reprex, get_plot(dat, a= c(1:5)) it results in a bar plot with 5 categories but the "one" category and the "five" category are empty. How do output the plot but not show the empty categories? Keeping in mind that I can't just drop category one and five because sometimes, depending on how the data that creates dat are filtered, there are values in those categories.

update, after thinking about it more this morning and doing more googling and trying things I figure out a solution. I inserted these select statements into the function and it gets me what I wanted!
p<- data %>%
select(where(~!any(is.na(.)))) %>%
select(where(~!any(.== 0))) %>%

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.