- Notifications
You must be signed in to change notification settings - Fork12
Description
First, thank you for building this great package!
I'm running into an issue trying to set the band argument in mark_point() and mark_errorbar() in a Dockerized Shiny app. When just in R (not using R Docker/Shiny), I am able to use bands to create an offset between points that have the same y-value, as in the chart below:
However, when I use the same syntax in my Dockerized Shiny app, the band argument does not work, resulting in the following chart:

(Please ignore that the charts use different data.)
From what I can tell, the issue traces to an issue when going from the VegaLite to Vega. Attached are the VegaLite Source and the Compiled Vega from the plot in Shiny. If you do a CTRL-F for the word "band", you see that in the VegaLite, the band argument is maintained (some points have band value of 0.3, and some of 0.7). In the Vega, however, the band is uniformly set to 0.5.
Am I correct in assuming that there's some sort of compilation error when going from VegaLite to Vega that resets the band to the default? Is there a fix for this?
Here's a simplified example of the Shiny app with the desired band argument behavior. I haven't been able to replicate the issue outside of Docker, so I expect the band argument here will work when running the app locally. If it would help, I can construct a Docker example to try replicate the problematic behavior.
Thank you for any help or insight you may have!
library(shiny)library(dplyr)library(doParallel)library(vegawidget)library(altair)ui <- fluidPage( selectInput("week_a","Week A",c("Week 1","Week 2","Week 3","Week 4","Week 5")), selectInput("week_b","Week B",c("Week 1","Week 2","Week 3","Week 4","Week 5")), vegawidgetOutput("chart"))server <- function(input, output, session) { # Get dataset data("airquality") colnames(airquality)[2] <- "Solar_R" ## Reformat to match my dataset's formatting # Use month names airquality$Month <- month.name[airquality$Month] # Assign weeks airquality$Week <- case_when(airquality$Day >= 1 & airquality$Day < 7 ~ "Week 1", airquality$Day >= 7 & airquality$Day < 14 ~ "Week 2", airquality$Day >= 14 & airquality$Day < 21 ~ "Week 3", airquality$Day >= 21 & airquality$Day < 28 ~ "Week 4", airquality$Day >= 28 & airquality$Day <= 31 ~ "Week 5") # Mean, pretend confidence interval of each column per week/month list_dfs <- list() for(i in 1:4){ dat <- aggregate(airquality[,i] ~ airquality$Month + airquality$Week, FUN=mean) dat$attribute_text <- colnames(airquality)[i] colnames(dat) <- c("Month","Week","Mean","attribute_text") stdev <- aggregate(airquality[,i] ~ airquality$Month + airquality$Week, FUN=sd) dat$lower_bound <- dat$Mean - stdev[,3] dat$upper_bound <- dat$Mean + stdev[,3] list_dfs[[i]] <- dat } chartdata <- as.data.frame(data.table::rbindlist(list_dfs)) # Function to create chart chart_code <- function (x) { # Get selected traits and remove apostrophes from them as well trait_1_value <- input[["week_a"]] trait_2_value <- input[["week_b"]] chartdata <- chartdata %>% filter(Week %in% c(trait_1_value, trait_2_value)) ## Elements for graph length_element <- round(3 * max(nchar(as.character(chartdata$Month))) - 132) # Shapes for highest and lowest value chartdata$importance_text <- "" subsets <- unique(chartdata[,c("attribute_text","Week")]) for(i in subsets$attribute_text){ for(j in subsets$Week){ dat <- subset(chartdata,chartdata$attribute_text==i & chartdata$Week == j) maximum <- which.max(dat$Mean) minimum <- which.min(dat$Mean) dat[maximum,"importance_text"] <- "Highest" dat[minimum,"importance_text"] <- "Lowest" chartdata[chartdata$attribute_text==i & chartdata$Week==j,] <- dat } } # Create expression to subset data by traits in graph filter_call_1 <- paste0("datum.Week == '", trait_1_value,"'") filter_call_2 <- paste0("datum.Week == '", trait_2_value,"'") ## Make plot base <- alt$Chart()$encode( x = alt$X("Mean", title = "", axis = alt$Axis(labelAlign = "center") ), y = alt$Y("Month", title = "" ), color = alt$Color("Week"), detail = alt$Detail("Mean:Q") ) # Add points for the first trait p_1 <- base$mark_point(filled = F, size = 80, opacity = 0.6)$encode( y = alt$Y("Month:N", title = "", sort = alt$EncodingSortField(field = "row"), axis = alt$Axis(labelLimit = 1000), band = 0.3 ), x = alt$X("Mean:Q", title = "Mean", axis = alt$Axis( labelAlign = "center", format = ".2f", tickCount = 5 )), shape = alt$Shape( "importance_text:N", title = "", scale = alt$Scale( domain = c("Highest", "Lowest"), range = c("triangle-up", "triangle-down") ), legend = NULL ) )$transform_filter(filter_call_1) # Add second trait points p_2 <- base$mark_point(filled = F, size = 80, opacity = 0.6)$encode( y = alt$Y("Month:N", title = "", sort = alt$EncodingSortField(field = "row"), axis = alt$Axis(labelLimit = 1000), band = 0.7 ), x = alt$X("Mean:Q", title = "Mean", axis = alt$Axis( labelAlign = "center", format = ".2f", tickCount = 5 )), shape = alt$Shape( "importance_text:N", title = "", scale = alt$Scale( domain = c("Highest", "Lowest"), range = c("triangle-up", "triangle-down") ), legend = NULL ) )$transform_filter(filter_call_2) # Add error bars (one layer for trait 1, another layer for trait 2) error_bars_1 <- base$mark_rule(opacity = 0.6, strokeDash = c(1,2), strokeWidth = 2)$encode( x = alt$X("lower_bound:Q", title = ""), x2 = alt$X2("upper_bound:Q"), y = alt$Y("Month:N", title = "", sort = alt$EncodingSortField("row"), band = 0.3) )$transform_filter(filter_call_1) error_bars_2 <- base$mark_rule(opacity = 0.6, strokeDash = c(1,2), strokeWidth = 2)$encode( x = alt$X("lower_bound:Q", title = ""), x2 = alt$X2("upper_bound:Q"), y = alt$Y("Month:N", title = "", sort = alt$EncodingSortField("row"), band = 0.7) )$transform_filter(filter_call_2) plot <- (p_1 + p_2 + error_bars_1 + error_bars_2)$facet(row = alt$Row("attribute_text", header = alt$Header( labelPadding = 5, labelOrient = "top", labelAlign = "center", labelAnchor = "middle", labelFontWeight = "bold", labelFontSize = 15 ) ), data = chartdata)$resolve_scale(y = "independent")$configure_facet(spacing = 20)$properties( title = alt$TitleParams( "Air Quality", #subtitle = list(fullsubtitle," ","▲ Most Preferred ▼ Least Preferred ● Neutral"," "), subtitle = list("▲ Highest ▼ Lowest"," "), baseline = "top", orient = "top", anchor = "middle", fontWeight = "bold", fontSize = 18, subtitlePadding = 15, subtitleFontSize = 13 ) )$configure_view( width = 300 )$configure_legend( orient = "right" ) return(plot) } output$chart <- vegawidget::renderVegawidget({ vegawidget::vegawidget(chart_code(1)) }) }shinyApp(ui, server)[traits_featureLevelEffectSize_VegaJSONSource.txt](https://github.com/user-attachments/files/19325487/traits_featureLevelEffectSize_VegaJSONSource.txt)[traits_featureLevelEffectSize_Vega-LiteJSONSource.txt](https://github.com/user-attachments/files/19325488/traits_featureLevelEffectSize_Vega-LiteJSONSource.txt)

