Data Science Workflow in the Tidyverse

Data Science Workflow

Data Science Workflow

Data Science: Statistics, Machine Learning, Big Data

The data science tent is very large with many diverse researchers. Today the enlighted approach is summarized as “evidence-based decision making” as opposed to more theoretical or idealogical approaches. For example, I am concerned about wide open unregulated commericalization of drugs such as marijuana and so I was pleased to hear our Prime Minister say the government approach would be evidence-based. Evidence-based decision making and evidence based-based are largely based on statistical models. In machine learning and big data the focus is on using data for prediction.

evidence based medicine

evidence based management

Algorithms vs Models

Algorithmic Prediction

Algorithmic Prediction

Leo Breiman, Stanford Statistics Professorm developed many of the modern algorithms in Machine Learning such as CART, Bagging, Random Forest and Gradient Boosting. There is major cultural divide between the statistical and machine learning communities. Breiman’s article is one of the most cited papers in Statistics.

American Statistical Association provides an concise insightful statement of the role of statistics in data science Link HTML or Link PDF

Comparing python, R and Excel

Many data scientists have backgrounds in engineering and computer science and as part of their education they have learned python. Python is widely used by these researchers. My eldest son works for a large medical company in Silicon Valley and his background is in biomedical engineering. In this field, engineers have developed convenient easy to use python interfaces to many advanced medical instruments such as robots and medical imaging devices. Many of these devices produce XML output, so R could also be used. R is also extensively used by companies such as Google especially for advanced statistical analysis. At the lowest level of management, for example a Walmart or MacDonal’s Manager, excel spreadsheets are sufficient. Whatever software you are using many of the basic principles of how to approach the analysis of data that are covered in this course are useful.

In data science, XML is a widely used format - some call it the new ASCII!

Brief Overview of R

The grammar or syntax which are used in the R language was orginally developed in its essentials in the S statistical software system in the 1970’s at Bell Labs. The S software only ran on unix computer systems but it was provided for free to universities and government research organizations. By 1990, more than 10,000 organizations were using S. I learned S on a four month visit to the Institute for Statistical Mathematics (Tokyo) in 1990. The team leader for the S project was John Chambers and in 1998 he received the ACM Software System Prize for is role in the development of S. Computing facilities have hugely improved since the 1970’s and tidyverse has been developed to better utilize the modern computing environments.

Robert Gentleman and Ross Ihaka initially developed because with the dissolution of Bell Labs, S was marked by a private owned company as S-Plus and it was very expensive. At the time Gentleman and Ihaka were teaching professors at The University of Auckland and it was very important that put R in the public domain - officially it is a GNU product which means that it will forever be freely available. Today there is a core development team for R and it is used world-wide.

A brief summary of the R language is given in the Wikipeda article R (programming language). If you have a background in another computing language such as MatLab you can easily learn R from documentation “Introduction to R” provided in HTML, PDF and ePub format at the CRAN website (https://cran.r-project.org/manuals.html). RMetrics has provided another book “Basic R for Finance” which I have made available on the OWL website for this course. There are many other fine introductory books about using R. I especially recommend “Hands-On Programming with R” by Grolemund who also co-authored R4DS with Wickham.

Strengths of R:

R Graphics

W.S. Cleveland was involved in the development of S graphics that form the basis of what is often called “traditional R graphics”. Such graphic functions include plot() as all the plotting functions included in base R. Cleveland’s 1993 book, The Elements of Graphing Data, describes the underlying philosophy and presents scientific evidence about human perception which he published in leading peer-reviewed journals. This book describes many interesting actual examples. The 1993 book provides guidance in creating effective graphs.

Cleveland’s 1994 book Visualizing Data describes basic visualization principles used by the lattice package in R. Here is an example of a lattice graphic produced by one of my former students Esam Mahdi. This visualization is comprised of a coordinated multi-panel display. The point in each panel (blue o) shows the empirical p-value for a nominal 5% test based on 1000 simulations. The nominal level is based on asymptotic theory and our purpose is to show that for finite samples (n = 50, 100, 200) the empirical observed size of the test agrees with asymptotic theory. Each panel is for different model/test parameters (x bivariate correlation; m number of lags). The vertical line shows the 95% confidence for the true finite sample test size.

Both the traditional R graphics as well as lattice graphics use a low-level implementation based on Paul Murrel’s grid graphics system described in his book R Graphics.

ggplot2 provides a comprehensive and powerful method for generating almost every imaginable data visualization. Hadley Wickham’s 2008 Ph.D. Thesis at the University Iowa, Practical Tools for Exploring Data and Models developed ggplot based on an abstract method for visualing data termed ‘the grammar of graphics’.

Wickham mentions in the preface to the 2nd edition of the ggplot2 book (2016) that in the year prior to the publication of the 2nd edition, there were over 1,000,000 downloads from CRAN of this package. Stack Overflow is a Q&A website for programmers and it provides answers to tens of thousandsquestions user’s of ggplot have raised, so it is a rich and useful resource when you want to do minor tweaks to your graph. To use the resource simply enter a suitable question in a google search. For example, try “omit tick marks on axis in ggplot2” and you should get several links to Stack Overflow. The 2nd Edition of the ggplot2 book is available online from Western Libraries, http://alpha.lib.uwo.ca/record=b6962637.

Minard’s Famous Graph and ggplot

In 1869 Charles Minard created a fascinating display depicting Napoleon’s 1812 invasion of Russia, Minard’s Chart. Expert opinion on data visualization is that Minard’s display is an outstanding example of the power of statistical visualization. To demonstrate the power of ggplot, Hadley Wickham produced a rendering of this graph using ggplot another improved version of this ggplot is given by Andrew Weiss.

The current version of ggplot is implemented in the R package ggplot2 and is described in Wichham’s 2015 book ggplot2: Elegant Graphics for Data Analysis (2nd Ed.). The complete source code for this book is also available of github.

The following graphic from The Economist combines mulitple graphic elements in a similar way to Minard’s famous display.

The Economist, Sept. 9-15, 2017

The Economist, Sept. 9-15, 2017

RStudio

I will give a classroom demonstration using RStudio of some basic plots in ggplot2.

You can obtain also obtain useful tips from many ‘cheatsheets’ available using the RStudio Help Menu:

Grammar of Graphics

The seven main constituents of the grammar of graphics are:

Most geom’s have defaults for aes, stat, position

Either str() or args() are useful to get a quick look at the arguments of a function. Both are base R functions.

geom_point()
str(geom_point)
## function (mapping = NULL, data = NULL, stat = "identity", position = "identity", 
##     ..., na.rm = FALSE, show.legend = NA, inherit.aes = TRUE)
geom_boxplot()
args(geom_boxplot)
## function (mapping = NULL, data = NULL, stat = "boxplot", position = "dodge", 
##     ..., outlier.colour = NULL, outlier.color = NULL, outlier.fill = NULL, 
##     outlier.shape = 19, outlier.size = 1.5, outlier.stroke = 0.5, 
##     outlier.alpha = NULL, notch = FALSE, notchwidth = 0.5, varwidth = FALSE, 
##     na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) 
## NULL
Other geom’s included in ggplot2

I found using the R command search() that ggplot2 was in position 2 on my search path. So the following command generated all the geom’s in this package.

> objects(7, pattern="^geom*")
 [1] "geom_abline"     "geom_area"       "geom_bar"        "geom_bin2d"     
 [5] "geom_blank"      "geom_boxplot"    "geom_col"        "geom_contour"   
 [9] "geom_count"      "geom_crossbar"   "geom_curve"      "geom_density"   
[13] "geom_density_2d" "geom_density2d"  "geom_dotplot"    "geom_errorbar"  
[17] "geom_errorbarh"  "geom_freqpoly"   "geom_hex"        "geom_histogram" 
[21] "geom_hline"      "geom_jitter"     "geom_label"      "geom_line"      
[25] "geom_linerange"  "geom_map"        "geom_path"       "geom_point"     
[29] "geom_pointrange" "geom_polygon"    "geom_qq"         "geom_quantile"  
[33] "geom_raster"     "geom_rect"       "geom_ribbon"     "geom_rug"       
[37] "geom_segment"    "geom_smooth"     "geom_spoke"      "geom_step"      
[41] "geom_text"       "geom_tile"       "geom_violin"     "geom_vline"  ```

Many more geom’s are available - see http://www.ggplot2-exts.org.

For spatial data visualization Kable and Wicham provide the CRAN package ggmap, https://cran.r-project.org/web/packages/ggmap/index.html among others. See “CRAN Task View: Analysis of Spatial Data” for others.

Syntax of ggplot()

 ggplot(data = <DATA>) + 
   <GEOM_FUNCTION>(
      mapping = aes(<MAPPINGS>),
      stat = <STAT>, 
      position = <POSITION>
   ) +
   <COORDINATE_FUNCTION> +
   <FACET_FUNCTION>

Note: the use of “+”. An advanced technique in R allows one to overload built-in functions with alternative definitions. In the context of ggplot2 “+” means continuation, so, for example I would read

ggplot(...) +
  geom_point(...)

as “ggplot … then geom_point …”.

Since ggplot was developed, Wicham discovered “pipes”. This is widely used since the 1980’s for unix scripts and Wickham elegantly included this in the tidyverse.

Simple examples of basic plots

Let’s start with the mpg dataset in ggplot. Our purpose is to investigate the effect of engine size and other automobile parameters on gas mileage.

We begin by display the dataframe mpg included ggplot2. Actually this is a specialized type of data frame known in the tidyverse as a tibble.

mpg
## # A tibble: 234 x 11
##    manufacturer      model displ  year   cyl      trans   drv   cty   hwy
##           <chr>      <chr> <dbl> <int> <int>      <chr> <chr> <int> <int>
##  1         audi         a4   1.8  1999     4   auto(l5)     f    18    29
##  2         audi         a4   1.8  1999     4 manual(m5)     f    21    29
##  3         audi         a4   2.0  2008     4 manual(m6)     f    20    31
##  4         audi         a4   2.0  2008     4   auto(av)     f    21    30
##  5         audi         a4   2.8  1999     6   auto(l5)     f    16    26
##  6         audi         a4   2.8  1999     6 manual(m5)     f    18    26
##  7         audi         a4   3.1  2008     6   auto(av)     f    18    27
##  8         audi a4 quattro   1.8  1999     4 manual(m5)     4    18    26
##  9         audi a4 quattro   1.8  1999     4   auto(l5)     4    16    25
## 10         audi a4 quattro   2.0  2008     4 manual(m6)     4    20    28
## # ... with 224 more rows, and 2 more variables: fl <chr>, class <chr>

For more information we can use str() or in the tidyverse the preferred function is glimpse().

str(mpg)
## Classes 'tbl_df', 'tbl' and 'data.frame':    234 obs. of  11 variables:
##  $ manufacturer: chr  "audi" "audi" "audi" "audi" ...
##  $ model       : chr  "a4" "a4" "a4" "a4" ...
##  $ displ       : num  1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ...
##  $ year        : int  1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ...
##  $ cyl         : int  4 4 4 4 6 6 6 4 4 4 ...
##  $ trans       : chr  "auto(l5)" "manual(m5)" "manual(m6)" "auto(av)" ...
##  $ drv         : chr  "f" "f" "f" "f" ...
##  $ cty         : int  18 21 20 21 16 18 18 18 16 20 ...
##  $ hwy         : int  29 29 31 30 26 26 27 26 25 28 ...
##  $ fl          : chr  "p" "p" "p" "p" ...
##  $ class       : chr  "compact" "compact" "compact" "compact" ...
glimpse(mpg)
## Observations: 234
## Variables: 11
## $ manufacturer <chr> "audi", "audi", "audi", "audi", "audi", "audi", "...
## $ model        <chr> "a4", "a4", "a4", "a4", "a4", "a4", "a4", "a4 qua...
## $ displ        <dbl> 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 1.8, 1.8, 2.0,...
## $ year         <int> 1999, 1999, 2008, 2008, 1999, 1999, 2008, 1999, 1...
## $ cyl          <int> 4, 4, 4, 4, 6, 6, 6, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6...
## $ trans        <chr> "auto(l5)", "manual(m5)", "manual(m6)", "auto(av)...
## $ drv          <chr> "f", "f", "f", "f", "f", "f", "f", "4", "4", "4",...
## $ cty          <int> 18, 21, 20, 21, 16, 18, 18, 18, 16, 20, 19, 15, 1...
## $ hwy          <int> 29, 29, 31, 30, 26, 26, 27, 26, 25, 28, 27, 25, 2...
## $ fl           <chr> "p", "p", "p", "p", "p", "p", "p", "p", "p", "p",...
## $ class        <chr> "compact", "compact", "compact", "compact", "comp...

Also we should read the documentation,

?mpg

Here is a brief summary of the variables:

  • manufacturer
  • model:name
  • displ:engine displacement, in litres
  • year:year of manufacture
  • cyl:number of cylinders
  • trans:type of transmission
  • drv:f = front-wheel drive, r = rear wheel drive, 4 = 4wd
  • cty:city miles per gallon
  • hwy:highway miles per gallon
  • fl:fuel type
  • class: “type” of car

We start with a simple scatterplot using ggplot.

ggplot(data=mpg) +
  geom_point(mapping=aes(x=displ, y=hwy))

A version of the scatterplot similar to that rendered by the traditional R plot().

ggplot(data=mpg) +
 geom_point(mapping=aes(x=displ, y=hwy), shape=1, size=2, stroke=1) +
 theme_bw()

Here is a simple barchart showing the number of cars with various types of Fuel Types.

ggplot(mpg, mapping=aes(x=fl)) +
 geom_bar(fill="red") +
 ggtitle("Barchart for Fuel Types") +
 xlab("Fuel type")

Boxplots are frequently used to compare distributions. For example, let’s compare the distributions of highway mileage, hwy with cars of different fuel types, fl. We use a specialized geom for this geom_boxplot(). Options are used to use a notched boxplot with width proportional to the square-root of the number of observations. There are many other similar geom functions for comparing and the distribution of the data including geom_histogram(), geom_freqpoly(), geom_density(), geom_dotplot() and geom_qq().

ggplot(data=mpg, mapping=aes(x=fl, y=hwy)) +
 geom_boxplot(notch=TRUE, varwidth=TRUE)
## notch went outside hinges. Try setting notch=FALSE.
## notch went outside hinges. Try setting notch=FALSE.

Notice the odd looking boxplot for Fuel Type “e”. Let’s drill down to understand. We use the functions filter(), select() and %> from the dplyr package. The function %> is called a pipe and read as “then”. So the following code reads ‘mpg then filter(fl==“e”) then select hwy’.

mpg %>%
 filter(fl=="e") %>%
 select(hwy)
## # A tibble: 8 x 1
##     hwy
##   <int>
## 1    15
## 2    14
## 3    17
## 4    12
## 5    12
## 6    12
## 7    12
## 8    12

Ok it is clear. The median, lower quartile and minimum are all equal! It is not hard obtain a similar result using regular R but using the data pliers package, dplyr, provides a more straightforward approach after you have learned how to use it.

In general for many data science problems tidyverse methods using the dplyr package provides simpler methods for [data wrangling (Wikipedia)]https://en.wikipedia.org/wiki/Data_wrangling and exploratory investigation including {EDA}https://en.wikipedia.org/wiki/Exploratory_data_analysis.

Primitive geom functions

The functions geom_point() and geom_bar() are two examples of primitive geom functions. Some more primitive geom functions that we will use frequently are geom_curve, geom_polygon(), geom_rect() and geom_abline(). The primitive geom functions can be used to create other more complicated graphs. Some more primitive geom functions are given on the ggplot cheatsheet

Exercises

  1. Run ggplot(data = mpg). What do you see?

  2. How many rows are in mpg? How many columns?

  3. What does the drv variable describe? Read the help for ?mpg to find out.

  4. Make a scatterplot of hwy vs cyl.

  5. What happens if you make a scatterplot of class vs drv? Why is the plot not useful? ggplot(mpg) + mapping=aes=(mapping=x=drv, y=class))

Solutions

Aesthetic Mappings

“The greatest value of a picture is when it forces us to notice what we never expected to see.” — John Tukey

Aesthetics are assigned to each individual observation and determine the colour, size or shape of each data point that is plotted. Some examples are shown in the Figure below.

Figure 1.

Figure 1.

In the plot below, one group of points (highlighted in red) seems to fall outside of the linear trend. These cars have a higher mileage than you might expect. How can you explain these cars?

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
  geom_point() + 
  geom_point(data = dplyr::filter(mpg, displ > 5, hwy > 20), colour = "red", size = 2.2)

BONUS PROBLEM FOR CLASS PRESENTATION: See code above. I discovered empirically that ggplot works by first producing a plot with all black points and then the 2nd call to geom_point() overplots the selected points in red. I had thought that maybe ggplot waited until all input was complete then produced the correct plot. How did I discover this in just a few seconds without spending many hours deciphering the inner working the underling code?

The solution I am looking for will test your hacking skills! See Drew Conway’s famous [Data Science Venn Diagram] (http://drewconway.com/zia/2013/3/26/the-data-science-venn-diagram)

Let’s hypothesize that the cars are hybrids. One way to test this hypothesis is to look at the class value for each car. The class variable of the mpg dataset classifies cars into groups such as compact, midsize, and SUV. If the outlying points are hybrids, they should be classified as compact cars or, perhaps, subcompact cars (keep in mind that this data was collected before hybrid trucks and SUVs became popular).

You can add a third variable, like class, to a two dimensional scatterplot by mapping it to an aesthetic. An aesthetic is a visual property of the objects in your plot. Aesthetics include things like the size, the shape, or the color of your points. You can display a point (like the one below) in different ways by changing the values of its aesthetic properties. Since we already use the word “value” to describe data, let’s use the word “level” to describe aesthetic properties.

You can convey information about your data by mapping the aesthetics in your plot to the variables in your dataset. For example, you can map the colors of your points to the class variable to reveal the class of each car.

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, color = class))

To map an aesthetic to a variable, associate the name of the aesthetic to the name of the variable inside aes(). ggplot2 will automatically assign a unique level of the aesthetic (here a unique color) to each unique value of the variable, a process known as scaling. ggplot2 will also add a legend that explains which levels correspond to which values.

The colors reveal that many of the unusual points are two-seater cars. These cars don’t seem like hybrids, and are, in fact, sports cars! Sports cars have large engines like SUVs and pickup trucks, but small bodies like midsize and compact cars, which improves their gas mileage. In hindsight, these cars were unlikely to be hybrids since they have large engines.

In the above example, we mapped class to the color aesthetic, but we could have mapped class to the size aesthetic in the same way. In this case, the exact size of each point would reveal its class affiliation. We get a warning here, because mapping an unordered variable (class) to an ordered aesthetic (size) is not a good idea.

REMARK: It is interesting to use color inside aes() with a discrete value such as class. We see that a legend is produced. This graph is also shown in R4DS and at first I was worried because of an issue with cognitive load. Both Cleveland and Tufte has stressed that too much colour can be distracting. But in this situation, I have come think Wicham’s graph is OK. Cleveland and Tufte’s concerns is more relevant when colour is used to distinguish different levels of a continuous variable as when a rainbow scheme is used.


ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, size = class))
## Warning: Using size for a discrete variable is not advised.

Or we could have mapped class to the alpha aesthetic, which controls the transparency of the points, or the shape of the points.

# Left
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, alpha = class))

# Right
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, shape = class))

What happened to the SUVs? ggplot2 will only use six shapes at a time. By default, additional groups will go unplotted when you use the shape aesthetic.

For each aesthetic, you use aes() to associate the name of the aesthetic with a variable to display. The aes() function gathers together each of the aesthetic mappings used by a layer and passes them to the layer’s mapping argument. The syntax highlights a useful insight about x and y: the x and y locations of a point are themselves aesthetics, visual properties that you can map to variables to display information about the data.

Once you map an aesthetic, ggplot2 takes care of the rest. It selects a reasonable scale to use with the aesthetic, and it constructs a legend that explains the mapping between levels and values. For x and y aesthetics, ggplot2 does not create a legend, but it creates an axis line with tick marks and a label. The axis line acts as a legend; it explains the mapping between locations and values.

You can also set the aesthetic properties of your geom manually to make a global change. For example, we can make all of the points in our plot blue:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy), color = "blue")

Here, the color doesn’t convey information about a variable, but only changes the appearance of the plot. To set an aesthetic manually, set the aesthetic by name as an argument of your geom function; i.e. it goes outside of aes(). You’ll need to pick a value that makes sense for that aesthetic:

  • The name of a color as a character string.
  • The size of a point in mm.
  • The shape of a point as a number, as shown in the Figure below.
R has 25 built in shapes that are identified by numbers. There are some seeming duplicates: for example, 0, 15, and 22 are all squares. The difference comes from the interaction of the `colour` and `fill` aesthetics. The hollow shapes (0--14) have a border determined by `colour`; the solid shapes (15--18) are filled with `colour`; the filled shapes (21--24) have a border of `colour` and are filled with `fill`.

R has 25 built in shapes that are identified by numbers. There are some seeming duplicates: for example, 0, 15, and 22 are all squares. The difference comes from the interaction of the colour and fill aesthetics. The hollow shapes (0–14) have a border determined by colour; the solid shapes (15–18) are filled with colour; the filled shapes (21–24) have a border of colour and are filled with fill.

R4DS Exercises, p. 11

  1. What’s gone wrong with this code? Why are the points not blue?

    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy, color = "blue"))

  2. Which variables in mpg are categorical? Which variables are continuous? (Hint: type ?mpg to read the documentation for the dataset). How can you see this information when you run mpg?

  3. Map a continuous variable to color, size, and shape. How do these aesthetics behave differently for categorical vs. continuous variables?

  4. What happens if you map the same variable to multiple aesthetics?

  5. What does the stroke aesthetic do? What shapes does it work with? (Hint: use ?geom_point)

  6. What happens if you map an aesthetic to something other than a variable name, like aes(colour = displ < 5)?

Solutions

Common problems

As you start to run R code, you’re likely to run into problems. Don’t worry — it happens to everyone. I have been writing R code for years, and every day I still write code that doesn’t work!

Start by carefully comparing the code that you’re running to the code in the book. R is extremely picky, and a misplaced character can make all the difference. Make sure that every ( is matched with a ) and every " is paired with another ". Sometimes you’ll run the code and nothing happens. Check the left-hand of your console: if it’s a +, it means that R doesn’t think you’ve typed a complete expression and it’s waiting for you to finish it. In this case, it’s usually easy to start from scratch again by pressing ESCAPE to abort processing the current command.

One common problem when creating ggplot2 graphics is to put the + in the wrong place: it has to come at the end of the line, not the start. In other words, make sure you haven’t accidentally written code like this:

ggplot(data = mpg) 
+ geom_point(mapping = aes(x = displ, y = hwy))

If you’re still stuck, try the help. You can get help about any R function by running ?function_name in the console, or selecting the function name and pressing F1 in RStudio. Don’t worry if the help doesn’t seem that helpful - instead skip down to the examples and look for code that matches what you’re trying to do.

If that doesn’t help, carefully read the error message. Sometimes the answer will be buried there! But when you’re new to R, the answer might be in the error message but you don’t yet know how to understand it. Another great tool is Google: try googling the error message, as it’s likely someone else has had the same problem, and has gotten help online.

Facets

Flatling

Flatling

One way to add additional variables is with aesthetics. Another way, particularly useful for categorical variables, is to split your plot into facets, subplots that each display one subset of the data.

To facet your plot by a single variable, use facet_wrap(). The first argument of facet_wrap() should be a formula, which you create with ~ followed by a variable name (here “formula” is the name of a data structure in R, not a synonym for “equation”). The variable that you pass to facet_wrap() should be discrete.

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) + 
  facet_wrap(~ class, nrow = 2)

To facet your plot on the combination of two variables, add facet_grid() to your plot call. The first argument of facet_grid() is also a formula. This time the formula should contain two variable names separated by a ~.

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) + 
  facet_grid(drv ~ cyl)

If you prefer to not facet in the rows or columns dimension, use a . instead of a variable name, e.g. + facet_grid(. ~ cyl).

R4DS Exercises, p.14

  1. What happens if you facet on a continuous variable?

  2. What do the empty cells in plot with facet_grid(drv ~ cyl) mean? How do they relate to this plot?

    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = drv, y = cyl))
  3. What plots does the following code make? What does . do?

    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy)) +
      facet_grid(drv ~ .)
    
    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy)) +
      facet_grid(. ~ cyl)
  4. Take the first faceted plot in this section:

    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy)) + 
      facet_wrap(~ class, nrow = 2)

    What are the advantages to using faceting instead of the colour aesthetic? What are the disadvantages? How might the balance change if you had a larger dataset?

  5. Read ?facet_wrap. What does nrow do? What does ncol do? What other options control the layout of the individual panels? Why doesn’t facet_grid() have nrow and ncol argument?

  6. When using facet_grid() you should usually put the variable with more unique levels in the columns. Why?

Solutions

Superposition or Juxtaposition

Sometimes small graphic multiples provide a better visualization of data than superposition of on the same plot. The following plot of the change in bone density over one-year for female and male children is shown in the plot below which uses superposition.

#install.packages("ElemStatLearn", message=FALSE)
library(ElemStatLearn) #data: bone
ggplot(data=bone, aes(x=age, y=spnbmd, color=gender)) +
 geom_point() +
 geom_smooth() +
 ylab("change in bone density")
## `geom_smooth()` using method = 'loess'

Remark: We use message=FALSE to suppress the message from geom_smooth() that is used the loess smoother!

With the advent of high-resolution colour displays, superposition usually produces an effective display when there are only two or very few classes and there are not too many data values.

The following plot uses the ggplots::facet() juxtaposition.

ggplot(data=bone, aes(x=age, y=spnbmd)) +
 geom_point() +
 geom_smooth() +
 facet_wrap(~gender, ncol=1, nrow=2) +
 ylab("change in bone density")

In this case, I used a column or vertical juxtaposition since I thought if was more effective in comparing the effect on age in the females and males than row/horizontal juxtaposition. But the square aspect-ratio in the superimposed plot is better for visualizating the interesting part of the curves. In general, a judicious choice of aspect-ratio play an important role when comparing curves or underlying trends in data. In the plot below we use a square aspect-ratio.

ggplot(data=bone, aes(x=age, y=spnbmd)) +
 geom_point() +
 geom_smooth() +
 facet_wrap(~gender, ncol=1, nrow=2) +
 ylab("change in bone density") +
 theme(aspect.ratio=1)

Figure from research paper with Yuanhao

Empirical MSE for Three Estimators

Empirical MSE for Three Estimators

Note this use plotmath for the Greek math symbols. The source code and data to produce this figure are available here

Remark: It is important to note that ggplot by default uses the same scaling in each graphic multiple. In many situations this is an essential feature. In base R, the layout() function does not do this and it is very tedious to make small graphic multiples with the correct scaling.

Geometric objects

How are these two plots similar?

See Rmd-file for details on how to create juxtaposed plots using markdown. Listing of ggplot call is given below.

ggplot(data = mpg) + 
 geom_point(mapping = aes(x = displ, y = hwy))

ggplot(data = mpg) + 
 geom_smooth(mapping = aes(x = displ, y = hwy))

Both plots contain the same x variable, the same y variable, and both describe the same data. But the plots are not identical. Each plot uses a different visual object to represent the data. In ggplot2 syntax, we say that they use different geoms.

A geom is the geometrical object that a plot uses to represent data. People often describe plots by the type of geom that the plot uses. For example, bar charts use bar geoms, line charts use line geoms, boxplots use boxplot geoms, and so on. Scatterplots break the trend; they use the point geom. As we see above, you can use different geoms to plot the same data. The plot on the left uses the point geom, and the plot on the right uses the smooth geom, a smooth line fitted to the data.

Every geom function in ggplot2 takes a mapping argument. However, not every aesthetic works with every geom. You could set the shape of a point, but you couldn’t set the “shape” of a line. On the other hand, you could set the linetype of a line. geom_smooth() will draw a different line, with a different linetype, for each unique value of the variable that you map to linetype.

ggplot(data = mpg) + 
geom_smooth(mapping = aes(x = displ, y = hwy, linetype = drv))

Here geom_smooth() separates the cars into three lines based on their drv value, which describes a car’s drivetrain. One line describes all of the points with a 4 value, one line describes all of the points with an f value, and one line describes all of the points with an r value. Here, 4 stands for four-wheel drive, f for front-wheel drive, and r for rear-wheel drive.

If this sounds strange, we can make it more clear by overlaying the lines on top of the raw data and then coloring everything according to drv.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + 
 geom_point() +
 geom_smooth(mapping = aes(linetype = drv))

Notice that this plot contains two geoms in the same graph! If this makes you excited, buckle up. In the next section, we will learn how to place multiple geoms in the same plot.

ggplot2 provides over 30 geoms, and extension packages provide even more (see https://www.ggplot2-exts.org for a sampling). The best way to get a comprehensive overview is the ggplot2 cheatsheet, which you can find at http://rstudio.com/cheatsheets. To learn more about any single geom, use help: ?geom_smooth.

Many geoms, like geom_smooth(), use a single geometric object to display multiple rows of data. For these geoms, you can set the group aesthetic to a categorical variable to draw multiple objects. ggplot2 will draw a separate object for each unique value of the grouping variable. In practice, ggplot2 will automatically group the data for these geoms whenever you map an aesthetic to a discrete variable (as in the linetype example). It is convenient to rely on this feature because the group aesthetic by itself does not add a legend or distinguishing features to the geoms.

To create juxtaposed plots in markdown as in the above plot we use option outwidth. It is also important to specify also echo=FALSE. The argument fig.asp=1/2 sets the aspect-ratio to 1/2. Note this method of juxtaposition does not automatically enforce same scaling so it is like using the layout() function in base R. Here is the listing.

markdown arguments: echo=FALSE, out.width = "33%", fig.asp = 1/2, 
                    fig.align = 'default',message = FALSE}
ggplot(data = mpg) +
 geom_smooth(mapping = aes(x = displ, y = hwy))
ggplot(data = mpg) +
 geom_smooth(mapping = aes(x = displ, y = hwy, group = drv))
ggplot(data = mpg) +
 geom_smooth(
  mapping = aes(x = displ, y = hwy, color = drv),
  show.legend = FALSE
 )

To display multiple geoms in the same plot, add multiple geom functions to ggplot():

r ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + geom_smooth(mapping = aes(x = displ, y = hwy))

This, however, introduces some duplication in our code. Imagine if you wanted to change the y-axis to display cty instead of hwy. You’d need to change the variable in two places, and you might forget to update one. You can avoid this type of repetition by passing a set of mappings to ggplot(). ggplot2 will treat these mappings as global mappings that apply to each geom in the graph. In other words, this code will produce the same plot as the previous code:

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
geom_point() + 
geom_smooth()

If you place mappings in a geom function, ggplot2 will treat them as local mappings for the layer. It will use these mappings to extend or overwrite the global mappings for that layer only. This makes it possible to display different aesthetics in different layers.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
geom_point(mapping = aes(color = class)) + 
geom_smooth()

You can use the same idea to specify different data for each layer. Here, our smooth line displays just a subset of the mpg dataset, the subcompact cars. The local data argument in geom_smooth() overrides the global data argument in ggplot() for that layer only.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
geom_point(mapping = aes(color = class)) + 
geom_smooth(data = filter(mpg, class == "subcompact"), se = FALSE)

(You’ll learn how filter() works in the next chapter: for now, just know that this command selects only the subcompact cars.)

Exercises, p.20

  1. What geom would you use to draw a line chart? A boxplot? A histogram? An area chart?

  2. Run this code in your head and predict what the output will look like. Then, run the code in R and check your predictions.

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + 
 geom_point() + 
 geom_smooth(se = FALSE)
  1. What does show.legend = FALSE do? What happens if you remove it?
    Why do you think I used it earlier in the chapter?

  2. What does the se argument to geom_smooth() do?

  3. Will these two graphs look different? Why/why not?

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 
 geom_point() + 
 geom_smooth()

ggplot() + 
 geom_point(data = mpg, mapping = aes(x = displ, y = hwy)) + 
 geom_smooth(data = mpg, mapping = aes(x = displ, y = hwy))
  1. Recreate the R code necessary to generate the following graphs.

Statistical transformations

diamonds dataset

The diamonds dataset comes in ggplot2 and contains information about ~54,000 diamonds, including the price, carat, color, clarity, and cut of each diamond. Using glimpse() we see that cut, color and clarity are ordinal (ordered factor in R).

glimpse(diamonds)
## Observations: 53,940
## Variables: 10
## $ carat   <dbl> 0.23, 0.21, 0.23, 0.29, 0.31, 0.24, 0.24, 0.26, 0.22, ...
## $ cut     <ord> Ideal, Premium, Good, Premium, Good, Very Good, Very G...
## $ color   <ord> E, E, E, I, J, J, I, H, E, H, J, J, F, J, E, E, I, J, ...
## $ clarity <ord> SI2, SI1, VS1, VS2, SI2, VVS2, VVS1, SI1, VS2, VS1, SI...
## $ depth   <dbl> 61.5, 59.8, 56.9, 62.4, 63.3, 62.8, 62.3, 61.9, 65.1, ...
## $ table   <dbl> 55, 61, 65, 58, 58, 57, 57, 55, 61, 61, 55, 56, 61, 54...
## $ price   <int> 326, 326, 327, 334, 335, 336, 336, 337, 337, 338, 339,...
## $ x       <dbl> 3.95, 3.89, 4.05, 4.20, 4.34, 3.94, 3.95, 4.07, 3.87, ...
## $ y       <dbl> 3.98, 3.84, 4.07, 4.23, 4.35, 3.96, 3.98, 4.11, 3.78, ...
## $ z       <dbl> 2.43, 2.31, 2.31, 2.63, 2.75, 2.48, 2.47, 2.53, 2.49, ...
  • carat: weight of the diamond (0.2-5.01)
  • cut: quality of the cut (Fair, Good, Very Good, Premium, Ideal)
  • color: diamond colour, from J (worst) to D (best)
  • clarity: a measurement of how clear the diamond is (I1 (worst), SI1, SI2, VS1, VS2, VVS1, VVS2, IF (best))
  • depth: total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43-79)
  • table: width of top of diamond relative to widest point (43-95)
  • price: price in US dollars ($326-$18,823)
  • x: length in mm (0-10.74)
  • y: width in mm (0-58.9)
  • z: depth in mm (0-31.8)

Barcharts

Next, let’s take a look at a bar chart. Bar charts seem simple, but they are interesting because they reveal something subtle about plots. Consider a basic bar chart, as drawn with geom_bar().

The following chart displays the total number of diamonds in the diamonds dataset, grouped by cut.

The chart shows that more diamonds are available with high quality cuts than with low quality cuts.

ggplot(data = diamonds) + 
geom_bar(mapping = aes(x = cut))

On the x-axis, the chart displays cut, a variable from diamonds. On the y-axis, it displays count, but count is not a variable in diamonds! Where does count come from? Many graphs, like scatterplots, plot the raw values of your dataset. Other graphs, like bar charts, calculate new values to plot:

  • bar charts, histograms, and frequency polygons bin your data and then plot bin counts, the number of points that fall in each bin.

  • smoothers fit a model to your data and then plot predictions from the model.

  • boxplots compute a robust summary of the distribution and then display a specially formatted box.

The algorithm used to calculate new values for a graph is called a stat, short for statistical transformation. The figure below describes how this process works with geom_bar().

Schematic showing how stat with geom_bar() works

Schematic showing how stat with geom_bar() works

You can learn which stat a geom uses by inspecting the default value for the stat argument. For example, ?geom_bar shows that the default value for stat is “count”, which means that geom_bar() uses stat_count(). stat_count() is documented on the same page as geom_bar(), and if you scroll down you can find a section called “Computed variables”. That describes how it computes two new variables: count and prop.

You can generally use geoms and stats interchangeably. For example, you can recreate the previous plot using stat_count() instead of geom_bar():

ggplot(data = diamonds) + 
stat_count(mapping = aes(x = cut))

This works because every geom has a default stat; and every stat has a default geom. This means that you can typically use geoms without worrying about the underlying statistical transformation. There are three reasons you might need to use a stat explicitly:

  1. You might want to override the default stat. In the code below, I change the stat of geom_bar() from count (the default) to identity. This lets me map the height of the bars to the raw values of a \(y\) variable. Unfortunately when people talk about bar charts casually, they might be referring to this type of bar chart, where the height of the bar is already present in the data, or the previous bar chart where the height of the bar is generated by counting rows.
demo <- tribble(
~cut,         ~freq,
"Fair",       1610,
"Good",       4906,
"Very Good",  12082,
"Premium",    13791,
"Ideal",      21551
)
ggplot(data = demo) +
geom_bar(mapping = aes(x = cut, y = freq), stat = "identity")

Override default mapping from transformed variables

You might want to override the default mapping from transformed variables to aesthetics. For example, you might want to display a bar chart of proportion, rather than count:

r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, y = ..prop.., group = 1))

To find the variables, such as prop, computed by the stat, look for the help section titled “computed variables”.

Specify the statistical transformation for emphasis

You might want to draw greater attention to the statistical transformation in your code. For example, you might use stat_summary(), which summarises the y values for each unique x value, to draw attention to the summary that you’re computing:

ggplot(data = diamonds) + 
stat_summary(
mapping = aes(x = cut, y = depth),
fun.ymin = min,
fun.ymax = max,
fun.y = median
)

args(stat_summary)
## function (mapping = NULL, data = NULL, geom = "pointrange", position = "identity", 
##     ..., fun.data = NULL, fun.y = NULL, fun.ymax = NULL, fun.ymin = NULL, 
##     fun.args = list(), na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) 
## NULL

ggplot2 provides over 20 stats for you to use. Each stat is a function, so you can get help in the usual way, e.g. ?stat_bin. To see a complete list of stats, try the ggplot2 cheatsheet.

Exercises

  1. What is the default geom associated with stat_summary()? How could you rewrite the previous plot to use that geom function instead of the stat function?

  2. What does geom_col() do? How is it different to geom_bar()?

  3. Most geoms and stats come in pairs that are almost always used in concert. Read through the documentation and make a list of all the pairs. What do they have in common?

  4. What variables does stat_smooth() compute? What parameters control its behaviour?

  5. In our proportion bar chart, we need to set group = 1. Why? In other words what is the problem with these two graphs?

ggplot(data = diamonds) + 
geom_bar(mapping = aes(x = cut, y = ..prop..))
ggplot(data = diamonds) + 
geom_bar(mapping = aes(x = cut, fill = color, y = ..prop..))

Solutions

Position adjustments

There’s one more piece of magic associated with bar charts. You can colour a bar chart using either the colour aesthetic, or, more usefully, fill:

r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, colour = cut))

r ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = cut))

Note what happens if you map the fill aesthetic to another variable, like clarity: the bars are automatically stacked. Each colored rectangle represents a combination of cut and clarity.

ggplot(data = diamonds) + 
 geom_bar(mapping = aes(x = cut, fill = clarity)) +
 ggtitle("Example of a stacked barchart")

Bonus Problem Cleveland in his book “Elements of Graphing Data” presents a convincing argument that the grouped dotchart performs better than the stacked barchart. Compare the above plot with the base R dotchart(). Can you use ggplot2 for a grouped dotchart?

The stacking is performed automatically by the position adjustment specified by the position argument. If you don’t want a stacked bar chart, you can use one of three other options: "identity", "dodge" or "fill".

ggplot(data = diamonds, mapping = aes(x = cut, fill = clarity)) + 
geom_bar(alpha = 1/5, position = "identity")

ggplot(data = diamonds, mapping = aes(x = cut, colour = clarity)) + 
geom_bar(fill = NA, position = "identity")

The identity position adjustment is more useful for 2d geoms, like points, where it is the default.

ggplot(data = diamonds) + 
geom_bar(mapping = aes(x = cut, fill = clarity), position = "fill") +
ggtitle("Example Spline Plot")

The Economist, Sept. 9-15, 2017

The Economist, Sept. 9-15, 2017

ggplot(data = diamonds) + 
geom_bar(mapping = aes(x = cut, fill = clarity), position = "dodge")

There’s one other type of adjustment that’s not useful for bar charts, but it can be very useful for scatterplots. Recall our first scatterplot. Did you notice that the plot displays only 126 points, even though there are 234 observations in the dataset?

The values of hwy and displ are rounded so the points appear on a grid and many points overlap each other. This problem is known as overplotting. This arrangement makes it hard to see where the mass of the data is. Are the data points spread equally throughout the graph, or is there one special combination of hwy and displ that contains 109 values?

You can avoid this gridding by setting the position adjustment to “jitter”. position = "jitter" adds a small amount of random noise to each point. This spreads the points out because no two points are likely to receive the same amount of random noise.

ggplot(data = mpg) + 
geom_point(mapping = aes(x = displ, y = hwy), position = "jitter")

Adding randomness seems like a strange way to improve your plot, but while it makes your graph less accurate at small scales, it makes your graph more revealing at large scales. Because this is such a useful operation, ggplot2 comes with a shorthand for geom_point(position = "jitter"): geom_jitter().

To learn more about a position adjustment, look up the help page associated with each adjustment: ?position_dodge, ?position_fill, ?position_identity, ?position_jitter, and ?position_stack.

Exercises

  1. What is the problem with this plot? How could you improve it?
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) + 
geom_point()

  1. What parameters to geom_jitter() control the amount of jittering?

  2. Compare and contrast geom_jitter() with geom_count().

  3. What’s the default position adjustment for geom_boxplot()? Create a visualisation of the mpg dataset that demonstrates it.

Solutions

Coordinate systems

Coordinate systems are probably the most complicated part of ggplot2. The default coordinate system is the Cartesian coordinate system where the x and y positions act independently to determine the location of each point. There are a number of other coordinate systems that are occasionally helpful.

ggplot(data = mpg, mapping = aes(x = class, y = hwy)) + 
 geom_boxplot()

ggplot(data = mpg, mapping = aes(x = class, y = hwy)) + 
 geom_boxplot() +
 coord_flip()

nz <- map_data("nz")

ggplot(nz, aes(long, lat, group = group)) +
 geom_polygon(fill = "white", colour = "black")

ggplot(nz, aes(long, lat, group = group)) +
 geom_polygon(fill = "white", colour = "black") +
 coord_quickmap()

Barchart and Coxcomb chart

  • coord_polar() uses polar coordinates. Polar coordinates reveal an interesting connection between a bar chart and a Coxcomb chart.
bar <- ggplot(data = diamonds) + 
 geom_bar(
  mapping = aes(x = cut, fill = cut), 
  show.legend = FALSE,
  width = 1
 ) + 
 theme(aspect.ratio = 1) +
 labs(x = NULL, y = NULL)

bar + coord_flip()

bar + coord_polar()

Exercises

  1. Turn a stacked bar chart into a pie chart using coord_polar().

  2. What does labs() do? Read the documentation.

  3. What’s the difference between coord_quickmap() and coord_map()?

  4. What does the plot below tell you about the relationship between city and highway mpg? Why is coord_fixed() important? What does geom_abline() do?

ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
geom_point() + 
geom_abline() +
coord_fixed()

Solutions

The layered grammar of graphics

In the previous sections, you learned much more than how to make scatterplots, bar charts, and boxplots. You learned a foundation that you can use to make any type of plot with ggplot2. To see this, let’s add position adjustments, stats, coordinate systems, and faceting to our code template:

 ggplot(data = <DATA>) + 
   <GEOM_FUNCTION>(
      mapping = aes(<MAPPINGS>),
      stat = <STAT>, 
      position = <POSITION>
   ) +
   <COORDINATE_FUNCTION> +
   <FACET_FUNCTION>

Our new template takes seven parameters, the bracketed words that appear in the template. In practice, you rarely need to supply all seven parameters to make a graph because ggplot2 will provide useful defaults for everything except the data, the mappings, and the geom function.

The seven parameters in the template compose the grammar of graphics, a formal system for building plots. The grammar of graphics is based on the insight that you can uniquely describe any plot as a combination of a dataset, a geom, a set of mappings, a stat, a position adjustment, a coordinate system, and a faceting scheme.

To see how this works, consider how you could build a basic plot from scratch: you could start with a dataset and then transform it into the information that you want to display (with a stat).

select data, compute counts

select data, compute counts

Next, you could choose a geometric object to represent each observation in the transformed data. You could then use the aesthetic properties of the geoms to represent variables in the data. You would map the values of each variable to the levels of an aesthetic.

geom for bars

geom for bars

You’d then select a coordinate system to place the geoms into. You’d use the location of the objects (which is itself an aesthetic property) to display the values of the x and y variables. At that point, you would have a complete graph, but you could further adjust the positions of the geoms within the coordinate system (a position adjustment) or split the graph into subplots (faceting). You could also extend the plot by adding one or more additional layers, where each additional layer uses a dataset, a geom, a set of mappings, a stat, and a position adjustment.

Set geom, coordinates, x and y

Set geom, coordinates, x and y

You could use this method to build any plot that you imagine. In other words, you can use the code template that you’ve learned in this chapter to build hundreds of thousands of unique plots.

Workflow: basics

Frustration is natural when you start programming in R, because it is such a stickler for punctuation, and even one character out of place will cause it to complain. But while you should expect to be a little frustrated, take comfort in that it’s both typical and temporary: it happens to everyone, and the only way to get over it is to keep trying.

Before we go any further, let’s make sure you’ve got a solid foundation in running R code, and that you know about some of the most helpful RStudio features.

Coding basics

Let’s review some basics we’ve so far omitted in the interests of getting you plotting as quickly as possible. You can use R as a calculator:

1 / 200 * 30
## [1] 0.15
(59 + 73 + 2) / 3
## [1] 44.66667
sin(pi / 2)
## [1] 1

You can create new objects with <-:

x <- 3 * 4

All R statements where you create objects, assignment statements, have the same form:

object_name <- value

When reading that code say “object name gets value” in your head.

You will make lots of assignments and <- is a pain to type. Don’t be lazy and use =: it will work, but it will cause confusion later. Instead, use RStudio’s keyboard shortcut: Alt + - (the minus sign). Notice that RStudio automagically surrounds <- with spaces, which is a good code formatting practice. Code is miserable to read on a good day, so giveyoureyesabreak and use spaces.

What’s in a name?

Object names must start with a letter, and can only contain letters, numbers, _ and .. You want your object names to be descriptive, so you’ll need a convention for multiple words. I recommend snake_case where you separate lowercase words with _.

i_use_snake_case
otherPeopleUseCamelCase
some.people.use.periods
And_aFew.People_RENOUNCEconvention

We’ll come back to code style later, in [functions].

You can inspect an object by typing its name:

x
## [1] 12

Make another assignment:

this_is_a_really_long_name <- 2.5

To inspect this object, try out RStudio’s completion facility: type “this”, press TAB, add characters until you have a unique prefix, then press return.

Ooops, you made a mistake! this_is_a_really_long_name should have value 3.5 not 2.5. Use another keyboard shortcut to help you fix it. Type “this” then press Cmd/Ctrl + â???’. That will list all the commands you’ve typed that start those letters. Use the arrow keys to navigate, then press enter to retype the command. Change 2.5 to 3.5 and rerun.

Make yet another assignment:

r_rocks <- 2 ^ 3

Let’s try to inspect it:

r_rock
#> Error: object 'r_rock' not found
R_rocks
#> Error: object 'R_rocks' not found

There’s an implied contract between you and R: it will do the tedious computation for you, but in return, you must be completely precise in your instructions. Typos matter. Case matters.

Calling functions

R has a large collection of built-in functions that are called like this:

function_name(arg1 = val1, arg2 = val2, ...)

Let’s try using seq() which makes regular sequences of numbers and, while we’re at it, learn more helpful features of RStudio. Type se and hit TAB. A popup shows you possible completions. Specify seq() by typing more (a “q”) to disambiguate, or by using â???’/â???" arrows to select. Notice the floating tooltip that pops up, reminding you of the function’s arguments and purpose. If you want more help, press F1 to get all the details in the help tab in the lower right pane.

Press TAB once more when you’ve selected the function you want. RStudio will add matching opening (() and closing ()) parentheses for you. Type the arguments 1, 10 and hit return.

seq(1, 10)
##  [1]  1  2  3  4  5  6  7  8  9 10

Type this code and notice you get similar assistance with the paired quotation marks:

x <- "hello world"

Quotation marks and parentheses must always come in a pair. RStudio does its best to help you, but it’s still possible to mess up and end up with a mismatch. If this happens, R will show you the continuation character “+”:

> x <- "hello
+

The + tells you that R is waiting for more input; it doesn’t think you’re done yet. Usually that means you’ve forgotten either a " or a ). Either add the missing pair, or press ESCAPE to abort the expression and try again.

If you make an assignment, you don’t get to see the value. You’re then tempted to immediately double-check the result:

y <- seq(1, 10, length.out = 5)
y
## [1]  1.00  3.25  5.50  7.75 10.00

This common action can be shortened by surrounding the assignment with parentheses, which causes assignment and “print to screen” to happen.

(y <- seq(1, 10, length.out = 5))
## [1]  1.00  3.25  5.50  7.75 10.00

Now look at your environment in the upper right pane:

RStudio Basic

RStudio Basic

Here you can see all of the objects that you’ve created.

Practice

  1. Why does this code not work?

    my_variable <- 10
    my_varıable
    ## Error: <text>:2:8: unexpected input
    ## 1: my_variable <- 10
    ## 2: my_varı
    ##           ^

    Look carefully! (This may seem like an exercise in pointlessness, but training your brain to notice even the tiniest difference will pay off when programming.)

  2. Tweak each of the following R commands so that they run correctly:

    library(tidyverse)
    
    ggplot(dota = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy))
    
    fliter(mpg, cyl = 8)
    filter(diamond, carat > 3)
  3. Press Alt + Shift + K. What happens? How can you get to the same place using the menus?

Solutions to All Exercises in R4DS

(https://jrnold.github.io/e4qf/visualize.html)