source(here::here("r", "my_functions.R"))
Color scales and palettes
This page is a work in progress and may contain areas that need more detail or that required syntactical, grammatical, and typographical changes. If you find some part requiring some editing, please let me know so I can fix it for you.
Overview
Readings
Reading should take place in two parts:
- Prior to class, the goal should be to familiarize yourself and bring questions to class. The readings from TFDV are conceptual and should facilitate readings from EGDA for code implementation.
- After class, the goal of reading should be to understand and implement code functions as well as support your understanding and help your troubleshooting of problems.
Before Class: First, read to familiarize yourself with the concepts rather than master them. Understand why one would want to visualize data in a particular way and also understand some of the functionality of {ggplot2}. I will assume that you attend class with some level of basic understanding of concepts.
Class: In class, some functions and concepts will be introduced and we will practice implementing {ggplot2} code. On occasion, there will be an assessment involving code identification, correction, explanation, etc. of concepts addressed in previous modules and perhaps some conceptual elements from this week’s readings.
After Class: After having some hands-on experience with coding in class, homework assignments will involve writing your own code to address some problem. These problems will be more complex, will involving problem solving, and may be open ended. This is where the second pass at reading with come in for you to reference when writing your code. The module content presented below is designed to offer you some assistance working through various coding problems but may not always suffice as a replacement for the readings from Wickham, Navarro, & Pedersen (under revision). ggplot2: Elegant Graphics for Data Analysis (3e).
External Functions
Provided in class:
view_html()
: for viewing data frames in html format, from /r/my_functions.R
You can use this in your own workspace but I am having a challenge rendering this of the website, so I’ll default to print()
on occasion.
Libraries
- {colorblindr} 0.1.0: for simulations of color vision deficiencies to ggplot2 objects; post-hoc color editing
- {colorspace} 2.1.0: for manipulating and assessing colors and color palettes
- {cowplot} 1.1.1: for ggplot add-ons; object management
- {here}: 1.0.1: for path management
- {dplyr} 1.1.2: for selecting, filtering, and mutating
- {ggplot2} 3.4.3: for plotting
- {ggthemes} 4.2.4: for palettes and themes
- {magrittr} 2.0.3: for code clarity and piping data frame objects
- {patchwork} 1.1.3: for plotting on grids
- {RColorBrewer} 1.1.3: for color palettes
Load libraries
library(dplyr)
library(magrittr)
library(ggplot2)
library(colorspace)
library(cowplot)
library(ggthemes) # for scale_color_colorblind()
library(colorblindr)
library(khroma)
Loading Data
For this exercise, we will use some data from a 2023 CMS swim meet located at: “https://github.com/slicesofdata/dataviz23/raw/main/data/swim/cleaned-2023-CMS-Invite.csv”.
<- readr::read_csv("https://github.com/slicesofdata/dataviz23/raw/main/data/swim/cleaned-2023-CMS-Invite.csv", show_col_types = F) SWIM
Color Uses in Data Visualization
To distinguish categories (qualitative)
%>%
SWIM ggplot(., aes(x = School, fill = Event)) +
geom_bar()
To represent numeric values (sequential)
%>%
SWIM filter(., Distance < 1000) %>%
ggplot(., aes(x = Event, y = Time, col = Time)) +
geom_point(position = position_jitter()) + theme_classic()
When no fill scale is defined, default is scale_fill_gradient()
, which we can change to something else.
%>%
SWIM filter(., Distance < 1000) %>%
ggplot(., aes(x = Event, y = Time, col = Time)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_fill_viridis_c()
But the function won’t change anything if we don’t use the proper scale_*_()
function.
%>%
SWIM filter(., Distance < 1000) %>%
ggplot(., aes(x = Event, y = Time, col = Time)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_viridis_c()
Or:
%>%
SWIM filter(., Distance < 1000) %>%
ggplot(., aes(x = Event, y = Time, col = Time)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_viridis_c(option = "B", begin = 0.15)
To represent numeric values (diverging):
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = Diff)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_gradient2()
Or:
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = Diff)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_continuous_diverging()
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = Diff)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_distiller(type = "div")
There are other applications too but we cannot get into them all here.
What is a Color Palette?
First, just in base R, there are 657 colors, which you can check out using colors()
and demo("colors")
.
Well, let’s see:
?palette
starting httpd help server ... done
palette()
[1] "black" "#DF536B" "#61D04F" "#2297E6" "#28E2E5" "#CD0BBC" "#F5C710"
[8] "gray62"
We see palette()
returns a character vector of 8 color elements. We can plot these to see the colors.
ggplot(data = data.frame(x = 1:8,
y = rep(1, 8),
names = sort(palette())),
mapping = aes(names, y)) +
geom_tile(fill = palette(),
size = 6
+ coord_flip() + theme_classic() +
) xlab("") + ylab("") + theme(axis.text.x = element_blank())
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
You can also
palette.colors(n = 5,
palette = "Okabe-Ito",
alpha = .5,
recycle = FALSE
)
[1] "#00000080" "#E69F0080" "#56B4E980" "#009E7380" "#F0E44280"
<- function(n = 5,
get_palette palette = "Okabe-Ito",
alpha = 1,
plot = TRUE,
tile_size = 5) {
= palette.colors(n = n,
pal palette = palette,
alpha = alpha,
recycle = FALSE
)
if (plot) {
<- ggplot(data = data.frame(x = 1:n,
(p y = rep(1, n),
names = pal),
mapping = aes(x = names, y = y)
+
) geom_tile(aes(fill = pal, size = tile_size),
alpha = alpha, show.legend = FALSE) +
coord_flip() + theme_classic() +
xlab("") + ylab("") +
theme(axis.text.x = element_blank())
)
}#print(pal);
return(pal)
}
get_palette(n = 5, palette = "Okabe-Ito", alpha = .4, plot = F)
[1] "#00000066" "#E69F0066" "#56B4E966" "#009E7366" "#F0E44266"
The colors will change if you change the alpha.
get_palette(n = 8, palette = "Okabe-Ito", alpha = .5, plot = T)
[1] "#00000080" "#E69F0080" "#56B4E980" "#009E7380" "#F0E44280" "#0072B280"
[7] "#D55E0080" "#CC79A780"
get_palette(n = 8, palette = "Okabe-Ito", alpha = .2, plot = T)
[1] "#00000033" "#E69F0033" "#56B4E933" "#009E7333" "#F0E44233" "#0072B233"
[7] "#D55E0033" "#CC79A733"
Color Scales Built into {ggplot2}
There are colors built into {ggplot2}. The scale_*()
functions will also following the naming conventions scale_color_*()
or scale_fill_*()
. When you have bars, remember that you are changing fill
color and with solid circle points you are changing col
so your go-to functions should adhere to those naming conventions (e.g., scale_fill_*()
and scale_color_*()
). Some examples include: scale_color_brewer()
or scale_color_distiller()
for discrete or continuous scales, respectively.
{ggplot} functions:
scale_color_hue()
: color, data: discrete, palette: qualitativescale_fill_hue()
: fill, data: discrete, palette: qualitativescale_color_gradient()
: color, data: continuous, palette: sequentialscale_color_gradient2()
: color, data: continuous, palette: divergingscale_fill_viridis_c()
: color, data: continuous, palette: sequentialscale_fill_viridis_d()
: fill, data: discrete, palette: sequentialscale_color_brewer()
: color, data: discrete , palette: qualitative, diverging, sequentialscale_fill_brewer()
: fill, data: discrete, palette: qualitative, diverging, sequentialscale_color_distiller()
: color, data: continuous, palette: qualitative, diverging, sequential
{colorspace}
The {colorspace} library written by Claus Wilke, Reto Stauffer, and Achim Zeileis brings some really useful color functionality to {ggplot2} and creates some order to an otherwise messing set of functions.
Function naming convention: scale_<aesthetic>_<datatype>_<colorscale>()
<aesthetic>
: name of the aesthetic (fill, color, colour) <datatype>
: type of variable plotted (discrete, continuous, binned) <colorscale>
: type of the color scale (qualitative, sequential, diverging, divergingx)
Scale function Aesthetic Data type Palette type
scale_color_discrete_qualitative()
color, discrete, qualitativescale_fill_continuous_sequential()
fill, continuous, sequentialscale_colour_continous_divergingx()
color, continuous, diverging
{colorspace} Color Palettes
::hcl_palettes(type = "sequential", plot = TRUE) # all sequential palettes colorspace
::hcl_palettes(type = "diverging", plot = TRUE, n = 9) # all diverging palettes colorspace
::divergingx_palettes(plot = TRUE, n = 9) # all divergingx palettes colorspace
Example plots
We can then specify the function according to our goal using: scale_<aesthetic>_<datatype>_<colorscale>()
. We can see an example with fill
ing points.
Continuous:
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = Diff)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_continuous()
Continuous and Sequential:
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
# mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = Time)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_continuous_sequential()
Discrete and Sequential:
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = School)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_discrete_sequential()
A specific palette added: palette = "Inferno"
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
# mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = Time)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_continuous_sequential(palette = "Inferno")
Continuous and Diverging:
%>%
SWIM filter(., Distance < 1000, Time < 200) %>%
filter(., Event == "Freestyle") %>%
mutate(., Diff = (Time - mean(Time, na.rm = T))) %>%
ggplot(., aes(x = Event, y = Time, col = Diff)) +
geom_point(position = position_jitter()) + theme_classic() +
scale_color_continuous_diverging()
Exploring {colorspace}
For a dynamic exploration use colorspace::hcl_wizard()
, which is a {shiny} app . When you are done exploring, click the “Return to R” box.
Color Picker
{colorspace} also has a color picker function, colorspace::hclcolorpicker()
which will allow you to pick color and obtain the hexidecimal color codes. You can also obtain html color names and rgb codes for colors at websites like htmlcolorcodes.com. With recent updates to RStudio, color names written as character strings when typed in the console or in files will display the color. Hint: you must type the names in lowercase (e.g., “mediumseagreen. If the color is not known by its name, then you won’t see the background string color change.
Setting Colors Manually
Discrete, qualitative scales
Discrete, qualitative scales are sometimes best set manually.
An example using default color palette:
%>%
SWIM filter(., Distance < 1000) %>%
ggplot(., aes(x = Distance, y = Time, color = School)) +
geom_point(position = position_jitter()) +
scale_color_hue()
Now consider the following plot.
%>%
SWIM ggplot(., aes(x = School, y = Time, fill = Event)) +
geom_col()
To set the color, add a layer:
For the hue, scale_<datatype>_hue()
could be scale_colour_hue()
or scale_fill_hue()
. The two function are listed below.
scale_colour_hue(
...,
h = c(0, 360) + 15,
c = 100,
l = 65,
h.start = 0,
direction = 1,
na.value = "grey50",
aesthetics = "colour"
)
scale_fill_hue(
...,
h = c(0, 360) + 15,
c = 100,
l = 65,
h.start = 0,
direction = 1,
na.value = "grey50",
aesthetics = "fill"
)
When you are trying to customize a plot for a client or find issue with the color palettes out-of-the-box, scale_color_manual()
or scale_fill_manual()
are likely your best friends. As you see in the functions, you need to pass some color values
. This is a vector of color by name or hexidecimal code.
scale_colour_manual(
...,
values,
aesthetics = "colour",
breaks = waiver(),
na.value = "grey50"
)
scale_fill_manual(
...,
values,
aesthetics = "fill",
breaks = waiver(),
na.value = "grey50"
)
But you need to know how values are mapped to subgroups. How many subgroups are there and what are they?
glimpse(SWIM)
Rows: 201
Columns: 10
$ Year <dbl> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2…
$ School <chr> "Pomona-Pitzer-CA", "Claremont-Mudd-Scripps-CA", "Claremont-M…
$ Team <chr> "Mixed", "Mixed", "Mixed", "Mixed", "Mixed", "Mixed", "Mixed"…
$ Relay <chr> "Relay", "Relay", "Relay", "Relay", "Relay", "Relay", "Relay"…
$ Distance <dbl> 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 2…
$ Name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "…
$ Age <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 2…
$ Event <chr> "Medley", "Medley", "Medley", "Medley", "Medley", "Medley", "…
$ Time <dbl> 97.74, 101.34, 101.64, 102.21, 102.83, 102.93, 103.55, 103.63…
$ Split50 <dbl> 26.35, 24.40, 24.06, 24.99, 24.37, 27.46, 28.54, 26.75, 25.77…
unique(SWIM$Event)
[1] "Medley" "Freestyle" "IM" "Butterfly" "Breaststroke"
[6] "Backstroke"
Make note of the order.
The order of the colors in the vector passes to values
will map to the order of the levels in the data frame. We can demonstrate this by changing the data frame arrangement.
Sorting by ascending or descending order changes the data frame.
%>% select(., Event) %>% unique() SWIM
# A tibble: 6 × 1
Event
<chr>
1 Medley
2 Freestyle
3 IM
4 Butterfly
5 Breaststroke
6 Backstroke
%>% arrange(., desc(Event)) %>% select(., Event) %>% unique() SWIM
# A tibble: 6 × 1
Event
<chr>
1 Medley
2 IM
3 Freestyle
4 Butterfly
5 Breaststroke
6 Backstroke
So how you sort the data frame matters, right? No.
Is this vector a factor? Note, you can also see this using glimpse()
.
is.factor(SWIM$Event)
[1] FALSE
glimpse(SWIM)
Rows: 201
Columns: 10
$ Year <dbl> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2…
$ School <chr> "Pomona-Pitzer-CA", "Claremont-Mudd-Scripps-CA", "Claremont-M…
$ Team <chr> "Mixed", "Mixed", "Mixed", "Mixed", "Mixed", "Mixed", "Mixed"…
$ Relay <chr> "Relay", "Relay", "Relay", "Relay", "Relay", "Relay", "Relay"…
$ Distance <dbl> 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 2…
$ Name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "…
$ Age <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 2…
$ Event <chr> "Medley", "Medley", "Medley", "Medley", "Medley", "Medley", "…
$ Time <dbl> 97.74, 101.34, 101.64, 102.21, 102.83, 102.93, 103.55, 103.63…
$ Split50 <dbl> 26.35, 24.40, 24.06, 24.99, 24.37, 27.46, 28.54, 26.75, 25.77…
What are the levels?
levels(SWIM$Event)
NULL
The levels()
function will only return levels if the vector is a factor.
Let’s change the variable in the data frame:
<- SWIM %>% mutate(., Event = factor(Event))
SWIM
levels(SWIM$Event)
[1] "Backstroke" "Breaststroke" "Butterfly" "Freestyle" "IM"
[6] "Medley"
<- length(levels(SWIM$Event)) num_events
is.ordered(SWIM$Event)
[1] FALSE
So it is not an ordered factor but it does have an order and that order will affect the plot.
The colors in the vector passed to values
will map onto the order of the levels as displayed by levels()
.
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(
values = c("#E69F00", "#1E90FF", "#009E73",
"#FFD700", "maroon", "gray")
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
Reverse the using rev()
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = rev(Event))) +
geom_point() +
scale_color_manual(
values = c("#E69F00", "#1E90FF", "#009E73",
"#FFD700", "maroon", "gray")
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
Something is wrong. Double check your data and labels.
mutate()
to change the order of levels
%>%
SWIM filter(., Distance < 300) %>%
mutate(., Event = factor(Event,
levels = c("Freestyle", "Breaststroke",
"Butterfly", "Backstroke",
"IM", "Medley"
))%>%
) ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(
values = c("#E69F00", "#1E90FF", "#009E73",
"#FFD700", "maroon", "gray")
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
OK, so we see that the color changes because the order of the levels changed. They are reordered in the plot legend.
mutate()
to make it an ordered factor
The order of the labels does not make a factor ordered. We need to do something special to accomplish that, which we will do here. However, the example is arbitrary here as there is not order or ranking to how I arrange them.
%>%
SWIM filter(., Distance < 300) %>%
mutate(., Event = factor(Event,
levels = c("Freestyle", "Breaststroke",
"Butterfly", "Backstroke",
"IM", "Medley"
),ordered = T)
%>%
) ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(
values = c("#E69F00", "#1E90FF", "#009E73",
"#FFD700", "maroon", "gray")
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
Change the labels
for the levels
Pass a vector of equal length with label names.
%>%
SWIM filter(., Distance < 300) %>%
mutate(., Event = factor(Event,
levels = c("Freestyle", "Breaststroke",
"Butterfly", "Backstroke",
"IM", "Medley"
),labels = c("Free", "Breast", "Fly",
"Back", "IM", "Medley"))
%>%
) ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(
values = c("#E69F00", "#1E90FF", "#009E73",
"#FFD700", "maroon", "gray")
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
Colors didn’t change but labels did.
Pair a Color with a Level
I’m not going to get into why this approach is actually a vector but you can test it if you want.
is.vector(c(Freestyle = "#E69F00", Breaststroke = "#1E90FF",
Butterfly = "#009E73", Backstroke = "#FFD700",
IM = "maroon", Medley = "gray"))
[1] TRUE
Pass a vector of names and color values.
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(
values = c(Freestyle = "#E69F00", Breaststroke = "#1E90FF",
Butterfly = "#009E73", Backstroke = "#FFD700",
IM = "maroon", Medley = "gray")
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
Pass a vector of colors
Changing the colors inside the function can be annoying so you might just create a vector object to pass to values
.
<- c(Freestyle = "#E69F00", Breaststroke = "#1E90FF",
color_vector Butterfly = "#009E73", Backstroke = "#FFD700",
IM = "maroon", Medley = "gray")
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(values = color_vector)
Warning: Removed 15 rows containing missing values (`geom_point()`).
Vectors containing additional name elements
If that vector contains names that are not in the variable vector, then the function will not break. Rather, colors will show for level in the data only. We are going to save this plot object to use later.
<- c(Freestyle = "#E69F00", Breaststroke = "#1E90FF",
color_vector Butterfly = "#009E73", Backstroke = "#FFD700",
IM = "maroon", Medley = "gray",
SomethingNew = "blue"
)
<- SWIM %>%
(SWIM_plot filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(values = color_vector)
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
Vectors missing name elements
But when names in the data vector are not in the color vector, something interesting happens.
<- color_vector[1:3]) (color_vector
Freestyle Breaststroke Butterfly
"#E69F00" "#1E90FF" "#009E73"
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(values = color_vector)
Warning: Removed 15 rows containing missing values (`geom_point()`).
First, and most obviously, the missing pair is dropped from the legend. So the data points are stripped from the plot too, right? Look closer. No! They are in a there but plotting as "grey50"
. This happens because the default setting na.value = "grey50"
.
There is also no warning, so double check your plots!
More dramatically, show only the first color element.
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(values = color_vector[1])
Warning: Removed 15 rows containing missing values (`geom_point()`).
color_vector
Freestyle Breaststroke Butterfly
"#E69F00" "#1E90FF" "#009E73"
which(names(color_vector) == "Freestyle")
[1] 1
This approach can be useful if you want to color only certain events by their name. The goal would be to determine which color corresponds to the Freestyle and plot only that. But remember, there are names in the vector and color values.
color_vector
Freestyle Breaststroke Butterfly
"#E69F00" "#1E90FF" "#009E73"
names(color_vector)
[1] "Freestyle" "Breaststroke" "Butterfly"
We need to find out the color position corresponding to the name position Using which()
we can evaluate the names to determine which position is the Freestyle.
which(names(color_vector) == "Freestyle")
[1] 1
What we get returned is position 1. Of course, you knew that but something might change and if it moves position based on a reordering, then hard coding won’t work.
To obtain the color associated with element position 1, use []
notation after the vector.
1] # hard coded solution color_vector[
Freestyle
"#E69F00"
which(names(color_vector) == "Freestyle")] # flexible solution color_vector[
Freestyle
"#E69F00"
Putting it all together, pass that to values
:
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(values = color_vector[which(
names(color_vector) == "Freestyle")]
)
Warning: Removed 15 rows containing missing values (`geom_point()`).
And if you wanted more than one event, evaluate with %in%
rather than ==
. For example, names(color_vector) %in% c("Freestyle", "Butterfly")
.
%>%
SWIM filter(., Distance < 300) %>%
ggplot(., aes(x = Split50, y = Time, color = Event)) +
geom_point() +
scale_color_manual(values = color_vector[which(
names(color_vector) %in% c("Freestyle", "Butterfly"))]
)
Warning: Removed 15 rows containing missing values (`geom_point()`).