I am trying to make the colors in a ggvis plot remain consistent whenever the data is re-plotted based on the factors (unfortunately I apparently lack enough reputation to include pictures to show you).
I could only find one other post about this controlling-color-of-factor-group-in-ggvis-r but none of his solutions or workarounds work in my situation.
my data looks like this:
month year date entity_name prefix module module_entry_key entity_table_name count
0 January 2011 2011.000 AbLibrary LIB Base BS AB_LIBRARY 0
1 February 2011 2011.083 AbLibrary LIB Base BS AB_LIBRARY 0
2 March 2011 2011.167 AbLibrary LIB Base BS AB_LIBRARY 0
3 April 2011 2011.250 AbLibrary LIB Base BS AB_LIBRARY 0
4 May 2011 2011.333 AbLibrary LIB Base BS AB_LIBRARY 0
5 June 2011 2011.417 AbLibrary LIB Base BS AB_LIBRARY 0
3000 January 2011 2011.000 Vector VEC Base BS VECTOR 0
3001 February 2011 2011.083 Vector VEC Base BS VECTOR 0
3002 March 2011 2011.167 Vector VEC Base BS VECTOR 0
3003 April 2011 2011.250 Vector VEC Base BS VECTOR 569
3004 May 2011 2011.333 Vector VEC Base BS VECTOR 664
3005 June 2011 2011.417 Vector VEC Base BS VECTOR 775
I'm using a shiny app to display the page in a browser, and the relevant code is:
# render the plot, filtering for entities within the module minus any entities selected from the exclude panel
plot <- reactive({
if (input$filter==1){
data <- dplyr::filter(.data=melted, module_entry_key %in% input$module)
}
else{
data <- dplyr::filter(.data=melted, entity_name == input$entity)
}
data <- dplyr::filter(.data=data, !entity_name %in% input$excluded)
data$entity_name <- factor(data$entity_name)
data %>%
ggvis(x = ~date, y = ~count, fill = ~entity_name, key := ~id, fillOpacity := 0.5, fillOpacity.hover := 0.9) %>%
add_legend("fill", title="Entities") %>%
layer_points() %>%
add_tooltip(tooltipText, "hover") %>%
add_axis("y", title = "Count", title_offset = 50) %>%
add_axis("x", title="Date", title_offset=50, subdivide=6, tick_size_minor=3, format=parseDate(~year, ~month))
})
the filter is creating the subset of "melted" as "data" based on the filters in the UI (see picture)
since as far as I can tell there is no way to associate a fill color to a factor (the entity name) explicitly and the color is chosen by alphabetical order of the factors, whenever I make a new subset of data the colors are changed.
Is there any way to work around this?
(full shiny code)
server.R
library(ggvis)
library(shiny)
library(dplyr)
shinyServer(function(input, output, session){
modules_list <- as.character(c("Base" = "BS",
"Screening" = "SC",
"Protein Engineering" = "EN",
"Protein Production" = "PP",
"CD",
"PT",
"PD"))
#melted <- read.table(file="~/dataOut.txt", sep="\t", strip.white=TRUE, row.names=1, header=TRUE);
modules <- as.character(as.vector(unique(melted$module_entry_key)))
modules <- modules[modules != "null"]
entities <- as.character(as.vector(unique(melted$entity_name)))
entities <- entities[entities != "null"]
for (i in entities){
melted <- rbind(melted, data.frame(month=NA, year=NA, date=NA, entity_name=i, prefix=NA, module=NA, module_entry_key=NA, entity_table_name=NA, count=NA))
}
melted$id <- 1:nrow(melted)
#create ui checkbox for modules in the data
output$module_list <- renderUI({
checkboxGroupInput(inputId = "module",
label = "Module",
choices = modules,
selected = "BS")
})
#create the ui list for entities
output$entity_list <- renderUI({
checkboxGroupInput(
inputId = "entity",
label = "Entity",
choices = entities,
selected = "Vector"
)
})
#ex <- entities
#create the checkboxGroupInput with entities to 'exclude'
output$exclusion_entities <- renderUI({
checkboxGroupInput(inputId = "excluded", label = "Exclude",
choices = entities)
})
#update the excluded entities list with entities within a particular module
observe({
if (input$filter==1)
ex1 <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=ex1, selected = input$excluded )
})
# render the plot, filtering for entities within the module minus any entities selected from the exclude panel
plot <- reactive({
if (input$filter==1){
data <- dplyr::filter(.data=melted, module_entry_key %in% input$module)
}
else{
data <- dplyr::filter(.data=melted, entity_name == input$entity)
}
data <- dplyr::filter(.data=data, !entity_name %in% input$excluded)
data$entity_name <- factor(data$entity_name)
data %>%
ggvis(x = ~date, y = ~count, fill = ~entity_name, key := ~id, fillOpacity := 0.5, fillOpacity.hover := 0.9) %>%
add_legend("fill", title="Entities") %>%
layer_points() %>%
add_tooltip(tooltipText, "hover") %>%
add_axis("y", title = "Count", title_offset = 50) %>%
add_axis("x", title="Date", title_offset=50, subdivide=6, tick_size_minor=3, format=parseDate(~year, ~month))
})
#function to add color and mouse-over effect to layer_points() (unused in this code)
points <- reactive({
layer_points(fillOpacity := 0.5, fillOpacity.hover := 1, fill.hover := "red")
})
#d3 date format for formatting x-axis text
parseDate <- function(year, month){
paste("d3.time.format(\"%Y\").parse(", year, ")", sep="")
}
#function for what to display in mouse-hover tooltip
tooltipText <- function(x) {
if(is.null(x)) return(NULL)
row <- melted[melted$id == x$id, ]
paste(row$entity_name, ": ", row$count, sep="")
}
#bind the plot to the UI
plot %>% #layer_points(fill = ~factor(entity_name)) %>%
bind_shiny("ggvis")
#select all button for modules
observe({
if (input$selectall ==0){
return(NULL)
}
else if ((input$selectall%%2)==0){
updateCheckboxGroupInput(session, inputId = "module", "Module", choices = modules)
}
else{
updateCheckboxGroupInput(session, inputId = "module", "Module", choices=modules, selected=modules)
}
})
#select all button for excluded entities
observe({
list <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
if (input$exclude_all ==0){
return(NULL)
}
else if ((input$exclude_all%%2)==0){
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=list )
}
else{
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=list, selected=list )
}
})
#---general output / debugging stuff ----#
output$table <- renderTable({dataInput()})
output$entity_selected = renderPrint({
list <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
entities[!entities %in% input$excluded & entities %in% list]
})
output$filter_value = renderPrint({input$filter})
output$modules = renderPrint({input$module})
output$link = renderPrint(input$selectall%%2)
#----------------------------------------#
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("DB Analysis"),
sidebarLayout(
sidebarPanel(
width=3,
radioButtons(inputId="filter",
label="Filter",
choices = list("By Module" = 1, "By Entity" = 2),
selected = 1),
conditionalPanel(condition = "input.filter == 1",
uiOutput("module_list"),
actionButton("selectall", "Select All"),
uiOutput("exclusion_entities"),
actionButton("exclude_all", "Select All")
),
conditionalPanel(condition = "input.filter == 2",
uiOutput("entity_list")
)
),
mainPanel(
h2("Cumulative Entity Counts over Time (years)", align="center"),
#verbatimTextOutput("value"),
#verbatimTextOutput("filter_value"),
#verbatimTextOutput("modules"),
#tableOutput("table"),
ggvisOutput("ggvis"),
verbatimTextOutput("link"),
verbatimTextOutput("entity_selected")
#textOutput("entities_plot")
)
)
)
)
This is probably the best way to do it. Try something like this:
df[which(df$entity_name == "AbLibrary"),]$color <- "FF0000"
df[which(df$entity_name == "Vector"),]$color <- "#FFB90F"
For each one in your data frame. Set your fill then to color each time. The only problem is trying to make a legend. (I have been trying to figure that out, so if I find it I will edit this post.