I\'m trying to use ggvis to create a NFL strength-of-schedule chart for the 2014 season. The data comes from FootballOutsiders.com, and later I\'ll make a Shiny app that aut
A solution I found to display a legend, making use of the scale_ordinal
function. I used a lot of the code written by @eipi10, thank you!
# Functions to create color ramps for the blue and orange color ranges,
# combined in a single palette with 10 colors of each ramp and gray for NAs
Blue <- colorRampPalette(c("darkblue","lightblue"))
Orange <- colorRampPalette(c("orange","darkorange3"))
palette <- c(Blue(10), "#E5E5E5", Orange(10))
# Negative values of defense get a blue color scale with 10 colors, indexes
# from 1 to 10
df2$def.label[!is.na(df2$defense) & df2$defense<0] <-
as.character(cut(df2$defense[!is.na(df2$defense) & df2$defense<0],
seq(min(df2$defense - 0.1, na.rm = TRUE), 0, length.out = 11),
labels = palette[1:10]))
# Positive values of defense get an orange color scale with 10 colors,
# indexes from 12 to 21
df2$def.label[!is.na(df2$defense) & df2$defense>=0] <-
as.character(cut(df2$defense[!is.na(df2$defense) & df2$defense>=0],
seq(0, max(df2$defense, na.rm = TRUE) + 0.1, length.out = 11),
labels = palette[12:21]))
# Set NA values in df2$defense to 11 in def.label, the label for gray color
df2$def.label[is.na(df2$defense)] <- palette[[11]]
# Define the values to be displayed on the legend
pos.cut.values <- seq(0, max(df2$defense, na.rm = TRUE) + 0.1, length.out = 11)
neg.cut.values <- seq(min(df2$defense - 0.1, na.rm = TRUE), 0, length.out = 11)
legend.values <- c(paste(neg.cut.values[1:10], '..', neg.cut.values[2:11]),
'NA', paste(pos.cut.values[1:10], '..', pos.cut.values[2:11]))
# Set NA values in df2$defense to blanks so that we won't get "NaN" in cells
# with missing data
df2$defense[is.na(df2$defense)] <- ""
df2 %>%
ggvis(~week, ~team, fill:=~def.label) %>%
scale_ordinal('fill', range = palette) %>%
add_legend(scales = 'fill', values = legend.values) %>%
layer_rects(width = band(), height = band()) %>%
scale_nominal("x", padding = 0, points = FALSE) %>%
scale_nominal("y", padding = 0, points = FALSE) %>%
layer_text(text := ~defense, stroke := "white", align := "left",
baseline := "top")
I set the colors for each cell by creating a new variable def.color
that maps each value of defense
to a specific color. In ggplot2
you can set the colors directly within the call to ggplot
using one line of code, such as scale_fill_manual()
, rather than adding a color variable to the data frame. I'm hoping there's a way to do that in ggvis
, but I haven't found it yet. So, for now, here we go:
# Create a new variable df2$def.color for mapping df2$defense values to colors
# Functions to create color ramps for the blue and orange color ranges
Blue = colorRampPalette(c("darkblue","lightblue"))
Orange = colorRampPalette(c("orange","darkorange3"))
# Negative values of defense get a blue color scale with 10 colors
df2$def.color[!is.na(df2$defense) & df2$defense<0] =
as.character(cut(df2$defense[!is.na(df2$defense) & df2$defense<0],
seq(min(df2$defense - 0.1, na.rm=TRUE), 0, length.out=11),
labels=Blue(10)))
# Positive values of defense get an orange color scale with 10 colors
df2$def.color[!is.na(df2$defense) & df2$defense>=0] =
as.character(cut(df2$defense[!is.na(df2$defense) & df2$defense>=0],
seq(0, max(df2$defense, na.rm=TRUE)+0.1, length.out=11),
labels=Orange(10)))
# Set NA values in df2$def.color to light gray in df2$def.color
df2$def.color[is.na(df2$defense)] = "#E5E5E5"
# Set NA values in df2$defense to blanks so that we won't get "NaN" in cells with
# missing data
df2$defense[is.na(df2$defense)] = ""
Now we create the plot. To get the colors, map def.color
to fill
using :=
to override the default colors. To add the values of defense
use layer_text
. I'm not happy with the text placement within each cell, but this is the best I've been able to come up with for now.
df2 %>%
ggvis(~week, ~team, fill:=~def.color) %>%
layer_rects(width = band(), height = band()) %>%
scale_nominal("x", padding = 0, points = FALSE) %>%
scale_nominal("y", padding = 0, points = FALSE) %>%
layer_text(text:=~defense, stroke:="white", align:="left", baseline:="top")