Visualizing data
ggplot2 Three common ways to generate graphics in R are via
base R lattice (little development in recent years though)ggplot2 We will skip base R graphics since ggplot2 will be the graphics package for this class.
Let us see how we use it, starting with a simple bar-chart
Remember the basic options...
one qualitative/categorical variables: bar-chart
one quantitative/continuous variables: histogram/box-plot/area-chart
two quantitative/continuous variables: scatter-plot/hex-bin
I will use two data-sets, the first being this IMDB data-set
The internet movie database, http://imdb.com/, is a website devoted to collecting movie data supplied by studios and fans. It claims to be the biggest movie database on the web and is run by amazon. More about information imdb.com can be found online, http://imdb.com/help/show_ leaf?about, including information about the data collection process, http://imdb.com/help/show_leaf?infosource.
library(ggplot2movies)
A data frame with 28819 rows and 24 variables
The second data-set is the Star Wars dataset, a tibble with 87 rows and 13 variables:
library(dplyr)data(starwars)
a tibble you say?
R's default is to store a data frame, as shown below with a small example and there is a tendency to convert characters into factors, change column names, etc.
data.frame( `Some Letters` = c("A", "B", "C"), `Some Numbers` = c(1, 2, 3) ) -> adfstr(adf)
## 'data.frame': 3 obs. of 2 variables:## $ Some.Letters: Factor w/ 3 levels "A","B","C": 1 2 3## $ Some.Numbers: num 1 2 3print(adf)
## Some.Letters Some.Numbers## 1 A 1## 2 B 2## 3 C 3tibbles is the brainchild of the team behind a bundle of packages (and RStudio) called the tidyverse that drop R's bad habits
tibble( `Some Letters` = c("A", "B", "C"), `Some Numbers` = c(1, 2, 3) ) -> atibglimpse(atib)
## Observations: 3## Variables: 2## $ `Some Letters` <chr> "A", "B", "C"## $ `Some Numbers` <dbl> 1, 2, 3print(atib)
## # A tibble: 3 x 2## `Some Letters` `Some Numbers`## <chr> <dbl>## 1 A 1## 2 B 2## 3 C 3Questions??

qplot will generate a quick plot but ggplot2 is the way to go so we build with it
ggplot(data = starwars)

Nothing results since we have not specified how we want the variable(s) to be mapped to the coordinate system ... what variable should go on what axis?
ggplot(data = starwars, mapping = aes(x = eye_color) )

Now we are getting somewhere. We see the canvas with the specific eye colors on the x-axis but nothing else has been drawn since we have not specified the geometry ... do you want a bar-chart? histogram? dot-plot? line-chart?
grammar of graphics ... not essential to understand ggplot2 but helpful if they want to specialize in visualizations With a categorical variable the bar-chart would be appropriate and so we ask for a geom_bar()
ggplot(data = starwars, mapping = aes(x = eye_color)) + geom_bar()
Other aesthetics can be added, such as
group color fill size alpha Two commands for adding a color scheme --
(a) color or colour
(b) fill
You can also change color palettes, roll your own, and more

ggplot(data = starwars, mapping = aes(x = eye_color, colour = eye_color)) + geom_bar() + labs(x = "Eye Color", y = "Frequency", title = "Bar-chart of Eye Color", subtitle = "(of Star Wars characters)")
Note what colour = generated for us
labs() is allowing us to customize the axis labels, add a title and subtitle.
If you wanted a caption, you could add a line of code, something like caption = "lorem ipsum"

This is not a very good plot of course. Why is that?
ggplot(data = starwars, mapping = aes(x = eye_color, fill = eye_color)) + geom_bar() + labs(x = "Eye Color", y = "Frequency", title = "Bar-chart of Eye Color", subtitle = "(of Star Wars characters)")
Note what fill = generated for us
Of course, it would be good to have the fill colors match the eye-color so let us do that next
We can also eliminate the legend. Why is that?

c("black", "blue", "slategray", "brown", "gray34", "gold", "greenyellow", "navajowhite1", "orange", "pink", "red", "magenta", "thistle3", "white", "yellow") -> mycolorsggplot(data = starwars, mapping = aes(x = eye_color)) + geom_bar(fill = mycolors) + labs(x = "Eye Color", y = "Frequency", title = "Bar-chart of Eye Color", subtitle = "(of Star Wars characters)", caption = "Much better!")
R Colors used from this source but see also this source

We can still do better. How can we improve this?
c("black", "blue", "slategray", "brown", "gray34", "gold", "greenyellow", "navajowhite1", "orange", "pink", "red", "magenta", "thistle3", "white", "yellow") -> mycolorsggplot(data = starwars, mapping = aes(x = eye_color)) + geom_bar(fill = mycolors) + labs(x = "Eye Color", y = "Frequency", title = "Bar-chart of Eye Color", subtitle = "(of Star Wars characters)", caption = "Much better!")
R Colors used from this source but see also this source

We can still do better. How can we improve this?
think in terms of the frequencies of eye-color

I'll switch to a different variable and show you how to use prebuilt color palettes
ggplot(data = starwars, mapping = aes(x = gender)) + geom_bar(aes(fill = gender)) + labs(x = "Gender", y = "Frequency", title = "Bar-chart of Gender", subtitle = "(of Star Wars characters)", caption = "(Source: The dplyr package)") + scale_fill_brewer(palette = "Pastel1")

library(wesanderson)ggplot(data = starwars, mapping = aes(x = gender)) + geom_bar(aes(fill = gender)) + labs(x = "Gender", y = "Frequency", title = "Bar-chart of Gender", subtitle = "(of Star Wars characters)", caption = "(Source: The dplyr package)") + scale_fill_manual(values = wes_palette("Darjeeling1"))

scale_fill_brewer in the plot on the left, calling on built-in color palettes. You can review them here scale_fill_manual in the plot on the right and a specific palette is being invoked from the wesanderson package caption = command to source the data scale_fill_brewer() to scale_fill_manual() One can also lean on various plotting themes as shown below
library(ggthemes)ggplot(data = starwars, aes(x = eye_color)) + geom_bar() + theme_tufte() + theme(axis.text.x = element_text(size = 6)) -> p1ggplot(data = starwars, aes(x = eye_color)) + geom_bar() + theme_solarized() + theme(axis.text.x = element_text(size = 6)) -> p2ggplot(data = starwars, aes(x = eye_color)) + geom_bar() + theme_economist() + theme(axis.text.x = element_text(size = 6)) -> p3ggplot(data = starwars, aes(x = eye_color)) + geom_bar() + theme_fivethirtyeight() + theme(axis.text.x = element_text(size = 6)) -> p4library(patchwork)p1 + p2 + p3 + p4 + plot_layout(ncol = 2)

Note: I am not using mapping = aes(...) any longer
Later on you will learn these & other ways to build advanced visualizations ...for now we get to work more with ggplot2
library(ggplot2)ggplot(data = movies, aes(x = mpaa)) + geom_bar() + theme_minimal()

library(ggplot2)ggplot(data = movies) + geom_bar(aes(x = mpaa)) + theme_minimal()

Notice how the aes(x = mpaa) is placed differently in the two commands and yet yields identical plots
MPAA ratings are missing for a lot of movies so we eliminate these from the plot via subset(mpa != "")
str(movies$mpaa)
## chr [1:58788] "" "" "" "" "" "" "R" "" "" "" "" "" "" "" "PG-13" "PG-13" "" "" "" "" ...ggplot(subset(movies, mpaa != ""), aes(x = mpaa)) + geom_bar() + theme_minimal()
The order of the bars is fortuitous in that it goes from the smallest frequency to the highest frequency.
I said fortuitous because ggplot2's default is to order the bars in an ascending alphabetic/alphanumeric ssequence if the variable is a character. See below for an example.
df = tibble(x = c(rep("A", 2), rep("B", 4), rep("C", 1)))ggplot(data = df, aes(x = x)) + geom_bar() + theme_minimal()
Later on we'll learn how to order the bars with ascending/descending frequencies or by some other logic
What about plotting the relative frequencies on the y-axis rather than the frequencies?
ggplot(data = subset(movies, mpaa != ""), aes(x = mpaa, y = (..count..)/sum(..count..))) + geom_bar() + scale_y_continuous(labels = scales::percent) + labs(x = "MPAA Rating", y = "Relative Frequency (%)") + theme_minimal()
Note: I used
y = (..count..)/sum(..count..) scale_y_continuous(labels = scales::percent) 
We could also add a second or even a third/fourth categorical variable. Let us see this with our hsb2 data-set
library(here)load("data/hsb2.RData")ggplot(data = hsb2, aes(x = ses, group = female)) + geom_bar(aes(fill = female)) + theme_minimal()
This is not very useful since the viewer has to estimate the relative sizes of the two colors within any given bar.
ggplot(data = hsb2, aes(x = ses, group = female)) + geom_bar(aes(fill = female), position = "dodge") + theme_minimal()
position = "dodge" will juxtapose the bars, and this is much better.
This is fine if you want to know what percent of the 200 students are low SES males, low SES females, etc. What if you wanted to calculate percentages within each sex?
ggplot(data = hsb2, aes(x = ses, y = female)) + geom_bar(aes(group = female, fill = female, y = ..prop..), position = "dodge") + scale_y_continuous(labels = scales::percent) + labs(y = "Relative Frequency (%)", x = "Socioeconomic Status Groups") + theme_minimal()
What about within each ses?
ggplot(data = hsb2, aes(x = female, y = ses)) + geom_bar(aes(group = ses, fill = ses, y = ..prop..), position = "dodge") + scale_y_continuous(labels = scales::percent) + labs(y = "Relative Frequency (%)", x = "Socioeconomic Status Groups") + theme_minimal()
geom_histogram() does the trick but note that the default number of bins is not very useful and can be tweaked, along with other embellishments
ggplot(data = hsb2, aes(x = read)) + geom_histogram(fill = "cornflowerblue", color = "white") + ggtitle("Histogram of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + theme_minimal()
See bins = 5 and also experiment with binwidth =
ggplot(data = hsb2, aes(x = read)) + geom_histogram(fill = "cornflowerblue", color = "white", bins = 5) + ggtitle("Histogram of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + theme_minimal()
If we wanted to break out the histogram by one or more categorical variables, we could do so
ggplot(hsb2, aes(x = read)) + geom_histogram(fill = "cornflowerblue", bins = 5, color = "white") + ggtitle("Histogram of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + facet_wrap(~ female) + theme_minimal()
Or better yet,
ggplot(hsb2, aes(x = read)) + geom_histogram(fill="cornflowerblue", bins = 10, color = "white") + ggtitle("Histogram of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + facet_wrap(~ female, ncol = 1) + theme_minimal()
Why? ... the distributions are stacked above each other, making for an easier comparison

One useful design element with breakouts is placing in relief the consolidated data (i.e., the distribution without break-outs)
ggplot(data = hsb2, aes(x = read, fill = female)) + geom_histogram(bins = 10, color = "white") + ggtitle("Histogram of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + facet_wrap(~ female, ncol = 1) + geom_histogram(data = hsb2[, -2], bins = 10, fill = "grey", alpha = .5) + theme_minimal()

Here it is obvious that the distribution of readings scores of any one sex are similar to the overall distribution so perhaps the groups are not really that different in terms of reading scores
For breakouts with two categorical variables we could do
ggplot(data = hsb2, aes(x = read)) + geom_histogram(fill="cornflowerblue", bins = 10, color = "white") + ggtitle("Histogramx of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + facet_wrap(~ female + schtyp, ncol = 2) + theme_minimal()
Note that ~ female + schtyp renders the panels for the first category of female by all categories of schtyp and then repeats for the other category of female

ggplot(data = hsb2, aes(x = read)) + geom_histogram(fill="cornflowerblue", bins = 10, color = "white") + ggtitle("Histogramx of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + facet_wrap(schtyp ~ female, ncol = 2) + theme_minimal()
Note that schtyp ~ female renders the panels for the first category of schtype for all categories of female and then repeats for the other category of schtyp

... which is the same as ...
ggplot(data = hsb2, aes(x = read)) + geom_histogram(fill = "cornflowerblue", bins = 10, color = "white") + ggtitle("Histogramx of Reading Scores") + labs(x = "Reading Score", y = "Frequency") + facet_wrap(~ schtyp + female, ncol = 2) + theme_minimal()
These were all the rage in the summer of 2017, and initially named joy plots but the unfortunate connection with the source of the plots led the name to be revised to ridge-plots. If you are curious, see why not joy?. You need to have installed the ggridges package but other than that, they are easy to craft.
library(viridis)library(ggridges)library(ggthemes)ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = `Month`)) + geom_density_ridges(scale = 3, alpha = 0.3, aes(fill = Month)) + labs(x = "Mean Temperature", y = "Month", title = 'Temperatures in Lincoln NE', subtitle = 'Mean temperatures (Fahrenheit) by month for 2016', caption = "Data: The Weather Underground") + theme_ridges() + theme(axis.title.y = element_blank(), legend.position = "none")

Here is another one, mapping the distribution of hemoglobin in four populations (the US being the reference group) as part of a study looking at the impacy of altitude on hemoglobin concentration (courtesy Whitlock and Schluter).
hemo <- read.csv(url("http://whitlockschluter.zoology.ubc.ca/wp-content/data/chapter02/chap02e3cHumanHemoglobinElevation.csv"))ggplot(hemo, aes(x = hemoglobin, y = population)) + geom_density_ridges(scale = 3, alpha = 0.3, aes(fill = population)) + labs(title = 'Hemoglobin Concentration Levels', subtitle = 'in Four populations') + theme_ridges() + theme(axis.title.y = element_blank(), legend.position = "none")

As should be evident, they are visually appealing when comparing a large number of groups on a single continuous variable and using simple facet-wrap or other options would be suboptimal
These can be useful to look at the distribution of a continuous variable
ggplot(hemo, aes(y = hemoglobin, x = "")) + geom_boxplot(fill = "cornflowerblue") + coord_flip() + labs(x = "", y = "Hemoglobin Concentration") + theme_minimal()
Note
x = "" in aes() because otherwise with a single group the box-plot will not build up coord_flip() is flipping the x-axis and y-axis 
ggplot(hemo, aes(y = hemoglobin, x = population, fill = population)) + geom_boxplot() + coord_flip() + labs(x = "", y = "Hemoglobin Concentration") + theme(axis.title.y = element_blank(), legend.position = "none") + theme_minimal()
Notice the need for no legend with fill = population

Ideal use: time series data
library(plotly)data(economics)# names(economics)ggplot(economics, aes(x = date, y = uempmed)) + geom_line() + labs(x = "Date", y = "Unemployment Rate") + theme_minimal()

load("data/gap.df.RData")ggplot(gap.df, aes(x = year, y = LifeExp, group = continent, color = continent)) + geom_line() + geom_point() + labs(x = "Year", y = "Median Life Expectancy (in years)", color = "") + theme_minimal() + theme(legend.position = "bottom")
Note: I switched off the legend label via color = ""

Pretty ugly!!
but we can dress these up by using plotly
library(plotly)myplot <- plot_ly(economics, x = ~date) %>% add_trace(y = ~uempmed, line = list(color = 'black'), mode = "lines", name = "Unemployment Rate") %>% add_trace(y = ~psavert, line = list(color = 'red'), mode = "lines", name = "Personal Savings Rate") %>% layout(autosize = F, width = 600, height = 300)library(shiny)div(myplot, align = "center")
scatter-plots ...
load("data/hsb2.RData")ggplot(hsb2, aes(x = write, y = science)) + geom_point() + labs(x = "Writing Scores", y = "Science Scores") + theme_minimal()
color by ses
ggplot(hsb2, aes(x = write, y = science)) + geom_point(aes(color = ses)) + labs(x = "Writing Scores", y = "Science Scores") + theme_minimal() + theme(legend.position = "bottom")
breakout ses for ease of interpretation
ggplot(hsb2, aes(x = write, y = science)) + geom_point() + labs(x = "Writing Scores", y = "Science Scores") + facet_wrap(~ ses) + theme_minimal()
count plots: see the frequency of given pairs of values by varying sizes of the points. The more the frequency of a pair the greater the size of these points.
data(mpg, package = "ggplot2")ggplot(mpg, aes(x = cty, y = hwy)) + geom_count(col = "firebrick", show.legend = FALSE) + labs(subtitle = "City vs Highway mileage", y = "Highway mileage", x = "City mileage") + theme_minimal()
Boston Marathon data
boston = read.csv("./data/BostonMarathon.csv")boston2 = boston[sample(nrow(boston), 200), ]ggplot(boston2, aes(x = Age, y = finishtime, group = M.F)) + geom_count(aes(color = M.F), show.legend = FALSE) + labs(subtitle = "", y = "Finishing Times (in seconds)", x = "Age (in years)") + facet_wrap(~ M.F, ncol = 1) + theme_minimal()
ggplot(data = diamonds, aes(y = price, x = carat)) + geom_hex() + labs(x = "Weight in Carats", y = "Price") + theme_minimal()
ggplot(data = diamonds, aes(y = price, x = carat)) + geom_hex() + labs(x = "Weight in Carats", y = "Price") + facet_wrap(~ color) + theme_minimal()
ggplot2ggplot(data, aes()) + geom_(aes()) + ...
aes() will take x =, y =, fill =, color =, group =, size =, radius =, size = and more
each geom has its own components
plenty of themes available; see for e.g., ggthemes here
don't forget to stay in touch with development of ggplot2 extensions
of course, the plotly site and Carson Sievert's plotly book
join stackoverflow but if you ask a question, post with a MWE
MWE = minimum working example
The Data Visualization Catalogue developed by Severino Ribecca to create a library of different information visualisation types
The R Graph Catalog maintained by Joanna Zhao and Jenny Bryan is always useful to see code-and-resulting-figure
Ferdio's Data Visualization Project, a website trying to present all relevant data visualizations, so you can find the right visualization and get inspired how to make them
The Chartmaker Directory will offer an answer to one of the most common questions in data visualisation: which tool do you need to make that chart?
Emery's Essentials focusing on the charts that give you the best bang for your buck
The Data Visualization Checklist by Ann K. Emery & Stephanie Evergreen
Data Visualization: A Practical Introduction by Kieran Healy
🔁 start with pencil and paper, sketch prototypes of desired visualization(s)
😄 graphics are relatively easy to generate with base R & with ggplot2
👏 common-sense: number & type of variable(s) guide plotting
🎇 stay color conscious: sensible colors & sensitive to color blindness
🔰 experiment, experiment, experiment until you are happy
use the 🆓 learning resources available online
📒 if you learn something new in R, write it down
Check out Data Camp and the blogosphere for plenty of examples
Visualizing data
ggplot2 Keyboard shortcuts
| ↑, ←, Pg Up, k | Go to previous slide |
| ↓, →, Pg Dn, Space, j | Go to next slide |
| Home | Go to first slide |
| End | Go to last slide |
| Number + Return | Go to specific slide |
| b / m / f | Toggle blackout / mirrored / fullscreen mode |
| c | Clone slideshow |
| p | Toggle presenter mode |
| t | Restart the presentation timer |
| ?, h | Toggle this help |
| Esc | Back to slideshow |