Excercise created by Ben Finkel, adapted with permission by Mika LaVaque-Manty and Ben Goehring
Welcome to POLSCI 381 R World! You will learn to work with it by reading, using, and editing this R markdown file.
First, make sure you have oriented yourself to R and R studio with the introductory materials provided.
Quickly notice that this window/panel displays your .Rmd file. You also should see a ‘Console’ window/panel where the code is actually run. This is the environment in which commands get executed. You can always issue commands and code in it by typing at the > prompt.
As you read through this document, you’ll find areas where we have asked you to write in a comment or edit code. Read carefully, or you may miss something.
For instance, write your name next to “author” above at the document header.
Just like in Code Academy, unless text is in a code chunk, it does not run. Here is what an empty code chunk looks like
#This code chunk is empty, other than this comment
When pound signs (hashtags) are outside of code blogs, they indicate headers. # Largest Header. ## Smaller header. ### Even Smaller Header. You can see these when this file is knit (more on that later)
Optional: find the “explore document outline” option to see how headers automatically sort into an interactive document outline in Rmarkdown.
We have divided this into sections. Some sections you will need to do only once; some more frequently. So just read on!
If at any point you want help, try using R Studio’s help (in the menu bar in the bottom-right quadrant) or just Google it: for example, try “r change chr to factor” for the heck of it.
First, you will install some packages that will allow you to complete this assignemnt. Note that this is only done once: once the packages are installed, they remain on your computer. So, if you return to this assignemnt tomorrow, the packages should still be there and you will not have to re-run this code.
There are well over 10,000 packages people have created that allow you to do different things with R – and in different ways. (R generally has many different ways of doing the same thing.)
1. Run the code below. To install, note that you must have internet access.
To run code inside of a code chunk you can either: a) Click the right pointing arrow on top of the code chunk to run it’s entire contents b) Highlight the code you want to run, then hit Cmd + Return (Mac) or Ctrl + Return (PC) to send that line over to the console to run. c) Copy/paste thee code you want to run from the code chunk into the Console (the most ‘low-tech’ method).
Now that the packages are installed, you can view them in the R Studio’s “Packages” menu, in the right-bottom quadrant by default.
You can ignore any warnings. Throughout the activity you may get more warnings, but they don’t always mean something bad or that the code hasn’t worked.
Again, you only have to complete this step once as the packages will remain on your computer.
This step you must complete each time you start a new work session, because it tells R to load or use each of those packages.
Each time you begin work sessions (and your scripts), you start by loading the packages you’ll likely need.
1b. Run the following code
#Load necessary packages. Again, highlight, and select "Run Lines" in the Code menu above or hit the right arrow.
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.0 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
In order to get data into R from a csv or other type of file, you have to tell R where to look for it. Your computer’s file system can be thought of as a sort of root system with different folders branching out from a single folder (the trunk, to keep the analogy alive). If you are not explicit about the folder in which your data lives, R will not be able to read it in and will return an error. There are multiple ways to tell R where to look for your data, which is often referred to as “setting your working directory.” (Directory and folder are synonymous terms.) For this assignment we are going to use R Projects.
Look at the top right-hand corner of Rstudio and click on “Project: (None)” and “New Project.” If prompted, save any changes to the Rmarkdown file. A screen should pop up asking you if you would like to create a new directory or use an existing directory. Select existing directory and then, in the next screen, select whichever folder your Rmakrdown file is currently in. Then click “Create Project” in the bottom right-hand corner.
Now, when you look at the top right-hand corner of RStudio it should provide the name of the folder that your Rmarkdown file is in (rather than “Project: (None)). If so, great! Now when you tell R to read in a data file, R will automatically begin searching for the file in your current folder.
(As an aside, some of you may have used the setwd() function to set your working directory in other classes. That is fine. I much prefer R Projects to setwd() for reproducibility reasons, but either will get the job done. If you want a hotter take on this: https://www.tidyverse.org/blog/2017/12/workflow-vs-script/.)
Note: this section includes extra review of R language basics to familiarize you with working inside of Rstudio.
At the command prompt, type “3 + 2” (without the quotes) and hit return.
2a. What happened? > [1] 5
(Note: by keeping your text to the right of the >, your answer will be formatted as a quote in the final knitted document.)
Now, run the code below
# Variables:
x <- 2
y <- 5
z <- x * y
print(z)
## [1] 10
2b. What did print(z) produce and why? > [1] 10. Because ‘x <- 2” assigned 2 to the variable x, and ’y <-5’ assigned 5 to the variable y. Then, ‘z <- x * y’ assigned the multiplication of x and y to the variable z. So, by printing z, it must have ran ‘x * y’ which is the same as 2 * 5– so the answer is 10.
Above, the values of X and Y and Z were saved into the enviornment. You can see the list of saved values by going to the ‘Environment panel’ in the top-right corner of RStudio. Try to find that now. You can always see all of your stored “objects”(variables, data frames, etc.) in the console by running:
ls()
## [1] "x" "y" "z"
2c. How many objects were listed? > Three objects were listed– x, y, and z.
OK, let’s continue with variables. Instead of single values, we will make them “vectors,” with multiple values.
Run the code below one line at a time and consider what action each line performs.
x <- c(1,2,3,4) # overwrites our earlier variable x
x
## [1] 1 2 3 4
sum(x) # This adds up the values of x
## [1] 10
min(x)
## [1] 1
max(x)
## [1] 4
mean(x)
## [1] 2.5
2d. If “sd” is the command for standard deviation, write one line of code below that returns the standard deviation of vector x as defined above. (The standard deviation is a measure of variation. For instance, the vector (10, 1, -5) has a higher standard deviation than the vector (1, 2, 3).
sd(x)
## [1] 1.290994
OK, let’s continue with variables
y <- c(5,6,7)
z <- c(x,y)
print(z)
## [1] 1 2 3 4 5 6 7
Using the c() combine function, it added the new vector y the end of vector x and called it z.
Data usually comes in more complex arrangements than single values or vectors. Data frames are objects where we store that complexity.
Data comes in the form of “observations,” which are represented as rows in data frames, and “variables,” which are in columns.
The following process creates a data frame for us. Our variables are “students,” “scores,” and “grades”, our observations are individual students, the score, and the grade each got.
#We create the variables first as vectors:
students <- c("Harry", "Hermione", "Neville", "Ron", "Draco")
scores <- c(3.3, 4, 1.7, 2.7, 0)
grades <- c("B+", "A", "C-", "B-", "F")
# ...and then combine them into the data frame itself:
dark.arts.exam <- data.frame(students, scores, grades)
In R Studio, you will notice that in the Environment window on the top-right, you now have an object called dark.arts.exam. Click on it and you will be able to take a closer look at what you created. You can get back to this window simply by clicking the “381_r_assignment.Rmd” tab after looking at your data frame.
This allowed you to open and view your data frame manually. We have much better tools to do this using R, especially when working with large datasets that cant’ fit in a single frame.
Here are some basic, and often more useful ways of looking at your data. Issue the following commands one at a time:
summary(dark.arts.exam) # summarizes the data
## students scores grades
## Length:5 Min. :0.00 Length:5
## Class :character 1st Qu.:1.70 Class :character
## Mode :character Median :2.70 Mode :character
## Mean :2.34
## 3rd Qu.:3.30
## Max. :4.00
names(dark.arts.exam) # lists your variable names
## [1] "students" "scores" "grades"
str(dark.arts.exam) # lists your variable names and types
## 'data.frame': 5 obs. of 3 variables:
## $ students: chr "Harry" "Hermione" "Neville" "Ron" ...
## $ scores : num 3.3 4 1.7 2.7 0
## $ grades : chr "B+" "A" "C-" "B-" ...
2e. What is the mean score of all students in the dark.arts.exam dataframe? > The mean of all students in the dark.arts.exam dataframe is 2.34.
We’ll create a second data frame and then merge it with the first.
first.name <- c("Harry", "Hermione", "Neville", "Ron", "Draco")
last.name <- c("Potter", "Granger", "Longbottom", "Weasley", "Malfoy")
house <- c("Gryffindor", "Gryffindor", "Gryffindor", "Gryffindor", "Slytherin")
houses <- data.frame(first.name, last.name, house)
exam.with.houses <- merge(dark.arts.exam, houses, by.x = "students", by.y = "first.name")
2f. In your own words, what did the merge() function do above? > The merge() combined the new house data frame with the previous dark.arts.exam data frame to create one data frame that includes all the data from both data frames.
Now run this.
only.the.good.guys <- filter(exam.with.houses, house == "Gryffindor")
2g. In one sentence, what did the filter() function do above? You may want to examine the only.the.good.guys. object to confirm your guess. > It removed anyone who was assigned to the Gryffindor house.
(Important technical note: “filter” in the above example is part of the “tidyr” package. If you haven’t installed and loaded tidyr, the command will produce a mistaken result because “filter” is then a different function.)
challenge2 <- filter(exam.with.houses, house != "Gryffindor")
2h. In one sentence, what did the filter() function do above? > It filtered out everyone who was not assigned to the Gryffindor house.
2i. Next, write your own code that selects all students who scored above average (you’ll probably want to cut and paste the above code and then modify it)
#your code here
challenge3 <- filter(exam.with.houses, scores > "2.34")
R is very powerful for producing excellent graphical plots. Base R (the default) has it’s own graphics, but we will use the package ggplot2 as an alternative graphics engine.
( You can find its documentation and details at http://docs.ggplot2.org/current/index.html)
In the following, we’ll create a basic boxplot with the exam data. Notice how adding a plus-sign at the end of a line lets you add further operations.
ggplot(exam.with.houses, aes(x = house, y = scores)) +
geom_boxplot(aes(fill=house)) +
ylab("Score") +
ggtitle("Proof of Slytherin lameness")
2j. Reproduce the code above with two changes: with the title as “Exam results,” and with a blank x-axis label.
#new plot here
ggplot(exam.with.houses, aes(x = , y = scores)) +
geom_boxplot(aes(fill=house)) +
ylab("Score") +
ggtitle("Exam results")
Great job! You’ve learned the basics, and you can start playing with real data.
For the rest of the exercise, we’re going to use data on Trump’s votes in every US county in the 2016 election paired with county-level data on median income. The vote data is from the MIT Election Lab and the income data is from the Census ACS survey.
The data is stored in the trump_income.csv file on Canvas. Download it and place it in whichever folder you set as your working directory when you created an R Project.
#Note: This will only work if trump_income.csv is located in your working directory
d <- read_csv("trump_income.csv") # naming your dataframe d or df is a common shorthand
## Rows: 3114 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): state, county, name
## dbl (5): fips, median_income, trump_votes, total_votes, vote_share
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Let’s take a look at our new data frame, d
nrow(d) # nrow and ncol return the number of rows or columns present in x. NCOL and NROW do the same treating a vector as 1-column matrix, even a 0-length vector, compatibly with as.matrix() or cbind(), see the example.
## [1] 3114
ncol(d)
## [1] 8
dim(d) #Retrieve or set the dimension of an object
## [1] 3114 8
Note: you can ask R for the definition of a function by typing ?function() e.g. ?nrow. The description will appear in the Help window.
3a. Briefly summarize what the above three functions each did. > The nrow() function returns with the number of rows in the trump_income.csv. The ncol() function returns with the number of rows in the trump_income.csv. The dim(d) function returns with the dimension aka number of rows and columns in the trum_income.csv.
names(d)
## [1] "state" "county" "name" "fips"
## [5] "median_income" "trump_votes" "total_votes" "vote_share"
Our data has 7 variables. Read carefully!
Let’s look at the first row of data
d[1,] #this shows the first row of data for all columns
## # A tibble: 1 × 8
## state county name fips median_income trump_votes total_votes vote_share
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Alabama Wilcox Wilcox … 1131 24442 1737 6118 0.284
3b. What county is in this row? And how many votes did Trump win in this county? > Trump won 1737 votes in Wilcox County, Alabama.
Here are some usual functions to take a quick look at your data
head(d) #look at first rows
## # A tibble: 6 × 8
## state county name fips median_income trump_votes total_votes vote_share
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Alabama Wilcox Wilc… 1131 24442 1737 6118 0.284
## 2 Alabama Winston Wins… 1133 33896 9228 10313 0.895
## 3 Alaska District… Aleu… 2013 65926 4028 6533 0.617
## 4 Alaska District… Aleu… 2016 86964 3203 7436 0.431
## 5 Alaska District… Anch… 2020 80862 2187 7140 0.306
## 6 Arizona Apache Apac… 4001 32460 8240 27661 0.298
str(d) #again, see overall str of each variable
## spc_tbl_ [3,114 × 8] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ state : chr [1:3114] "Alabama" "Alabama" "Alaska" "Alaska" ...
## $ county : chr [1:3114] "Wilcox" "Winston" "District 13" "District 16" ...
## $ name : chr [1:3114] "Wilcox County, Alabama" "Winston County, Alabama" "Aleutians East Borough, Alaska" "Aleutians West Census Area, Alaska" ...
## $ fips : num [1:3114] 1131 1133 2013 2016 2020 ...
## $ median_income: num [1:3114] 24442 33896 65926 86964 80862 ...
## $ trump_votes : num [1:3114] 1737 9228 4028 3203 2187 ...
## $ total_votes : num [1:3114] 6118 10313 6533 7436 7140 ...
## $ vote_share : num [1:3114] 0.284 0.895 0.617 0.431 0.306 ...
## - attr(*, "spec")=
## .. cols(
## .. state = col_character(),
## .. county = col_character(),
## .. name = col_character(),
## .. fips = col_double(),
## .. median_income = col_double(),
## .. trump_votes = col_double(),
## .. total_votes = col_double(),
## .. vote_share = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
3c. According to the str(), what class of data is variable ‘county’? > The ‘county’ variable is character data.
Often when starting with data, a key early step is to make sure R knows what kind of data each of your variables are.
unique(d$state)
## [1] "Alabama" "Alaska" "Arizona"
## [4] "Arkansas" "Illinois" "California"
## [7] "Colorado" "Connecticut" "Delaware"
## [10] "District of Columbia" "Florida" "Georgia"
## [13] "Hawaii" "Idaho" "Kentucky"
## [16] "Louisiana" "Indiana" "Iowa"
## [19] "Kansas" "Missouri" "Montana"
## [22] "Maine" "Maryland" "Massachusetts"
## [25] "Michigan" "Minnesota" "Mississippi"
## [28] "North Carolina" "North Dakota" "Ohio"
## [31] "Nebraska" "Nevada" "New Hampshire"
## [34] "New Jersey" "New Mexico" "New York"
## [37] "Tennessee" "Texas" "Oklahoma"
## [40] "Oregon" "Pennsylvania" "Rhode Island"
## [43] "South Carolina" "South Dakota" "Virginia"
## [46] "Washington" "Utah" "Vermont"
## [49] "West Virginia" "Wisconsin" "Wyoming"
3d. In one or two sentences, what does the code above do? > The uique() function reads the trump_income.csv and displays the name of every state while removing duplicated variables.
min(d$median_income)
## [1] 18972
max(d$median_income)
## [1] 125672
3e. According to the output of the code above, what is the highest and lowest median income in the data set? > The lowest median income is 18972 and the highest median income is 125675
Let’s see what R can do. Right now our code is at the county-level. Let’s try and summarize it by state, so we we can figure out Trump’s share of state-level votes.
summary_2016 <- d %>% # This is a nifty operation called the "pipe" that lets you pass down arguments to subsequent functions i.e., the group_by is now performed on object d
group_by(state) %>% # summarize the data by state
mutate(state_trump_votes = sum(trump_votes)) %>% # Create a new variable called state_trump_votes that equals the sum of all trump votes in a given state
mutate(state_total_votes = sum(total_votes)) %>%# Create a new variable called state_total_votes that equals the sum of all votes in a given state
ungroup() %>% # Don't worry about this. It is just good practice to always ungroup a dataframe when you have done any grouping.
mutate(state_vote_share = round(state_trump_votes / state_total_votes, 2))
# Since we are interested in state-level data, we do not need 3114 observations, only 51 observations (DC is in here too)
# Let's drop the county-level information and remove any duplicates.
summary_2016 <- summary_2016 %>%
select(-name, -county, -fips, -median_income, -trump_votes, -total_votes, -vote_share) %>%
distinct()
# Finally, let's arrange the rows with the most Trump-supporting states at the top.
summary_2016 <- summary_2016 %>%
arrange(-state_vote_share)
#now, let's just view the top 10 trump-supporting states
head(summary_2016, 10)
## # A tibble: 10 × 4
## state state_trump_votes state_total_votes state_vote_share
## <chr> <dbl> <dbl> <dbl>
## 1 West Virginia 489371 713051 0.69
## 2 Wyoming 174419 255849 0.68
## 3 Oklahoma 949136 1452992 0.65
## 4 Kentucky 1202971 1924149 0.63
## 5 North Dakota 216794 344360 0.63
## 6 Alabama 1318250 2123367 0.62
## 7 South Dakota 227480 367188 0.62
## 8 Arkansas 684872 1129896 0.61
## 9 Tennessee 1522925 2508027 0.61
## 10 Idaho 409055 690433 0.59
3f. What state and vote share are listed in the fourth row? How many people voted in total in the state? > Kentucky, .63. The total number of votes in the state are 1924149.
3g. In the code chunk below, edit the previous code so that it also tells includes state-level median income data (hint: you will be using mutate(new_var = median(median_income) to create the new variable.)
summary_2016 <- d %>% # This is a nifty operation called the "pipe" that lets you pass down arguments to subsequent functions i.e., the group_by is now performed on object d
group_by(state) %>% # summarize the data by state
mutate(state_trump_votes = sum(trump_votes)) %>% # Create a new variable called state_trump_votes that equals the sum of all trump votes in a given state
mutate(state_total_votes = sum(total_votes)) %>%# Create a new variable called state_total_votes that equals the sum of all votes in a given state
mutate(median = median(median_income)) %>%
ungroup() %>% # Don't worry about this. It is just good practice to always ungroup a dataframe when you have done any grouping.
mutate(state_vote_share = round(state_trump_votes / state_total_votes, 2))
# Since we are interested in state-level data, we do not need 3114 observations, only 51 observations (DC is in here too)
# Let's drop the county-level information and remove any duplicates.
summary_2016 <- summary_2016 %>%
select(-name, -county, -fips, -median_income, -trump_votes, -total_votes, -vote_share) %>%
distinct()
# Finally, let's arrange the rows with the most Trump-supporting states at the top.
summary_2016 <- summary_2016 %>%
arrange(-median)
#now, let's just view the top 10 trump-supporting states
head(summary_2016, 10)
## # A tibble: 10 × 5
## state state_trump_votes state_total_votes median state_vote_share
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Alaska 9418 21109 80862 0.45
## 2 New Jersey 1601933 3874046 72999 0.41
## 3 District of Colu… 12723 311268 72935 0.04
## 4 Rhode Island 180490 463416 71347 0.39
## 5 Connecticut 673215 1644920 70773 0.41
## 6 Hawaii 128847 428937 68500. 0.3
## 7 Maryland 943169 2781446 68464. 0.34
## 8 Massachusetts 1090893 3274555 64458 0.33
## 9 New Hampshire 345790 744296 59850. 0.46
## 10 North Dakota 216794 344360 55900 0.63
3h. Report the five states with the highest median income in 2016
Alaska, New Jersey, District of Columbia, Rhode Island, and Connecticut.
Graphics are sometimes a better way of seeing basic data quickly. Let’s do a bar graph of Trump’s share of votes in a state.
We are going to use the summary_2016 dataframe we created above and the powerful ggplot function to create a bar plot.
Now, we use a powerful function called ggplot to create a barplot of these values
ggplot(data = summary_2016, #identify the data being used
aes(x = state, y = state_vote_share)) + #define the x and y variables
geom_bar(stat = "identity") #tells ggplot to use values as listed rather than aggregating
Pretty good, but the data lost its order. It would be easier to quickly get information from this plot if the data were ordered.
ggplot(summary_2016,
aes(x = reorder(state, -state_vote_share), #reorder
y = state_vote_share)) +
geom_bar(stat = "identity")
Better. But it’s hard to read and the labels are messy. So, we’re going to add more functions to label our plot.
plot <- ggplot(summary_2016,
aes(x = reorder(state, -state_vote_share), #reorder
y = state_vote_share)) +
geom_bar(stat = "identity") +
xlab("") +
ylab("Share of state votes") +
ggtitle("Trump's share of votes in 2016 election") +
scale_y_continuous() +
theme(axis.text.x = element_text(angle = 60, hjust = 1, size = 7)) # rotates county names so more readable
plot #What this did was assign the whole plotting code to a single object, and then just called that object.
Much better, but of course further improvements can be made.
One useful feature of ggplot is setting default graphics through the use of different themes. Here are a few.
plot +
theme_bw() #by assigning the prior plot to object 'plot'. I can make adjustments to it here in much more concise code (although the new theme overwrites the changes I made previously to the label formatting)
plot +
theme_dark()
plot +
theme_void()
#You can always download more themes! There are tons out there.
# (I am a dork and have my own custom theme #gradschool. You can take a look at it by running the code below.)
# install.packages('devtools')
# devtools::install_github('benfromfargo/BeRn')
# BeRn::set_my_theme()
#
# plot
# rm(my_theme)
3i. Make at least one edit to a plot above to create your own plot. You can try a new theme (not one listed above), change the labels, or mess with any part of it. It doesn’t have to be more clear than the plots above. The goal here is just to play around with the code.
plot <- ggplot(summary_2016,
aes(x = reorder(state, state_vote_share), #reorder from least to greatest
y = state_vote_share)) +
geom_bar(stat = "identity") +
xlab("") +
ylab("Cents per Dollar") + #Change title of y-axis
ggtitle("Amount of money donated to political campaigns") + #Change title of bar plot
scale_y_continuous() +
theme(axis.text.x = element_text(angle = 60, hjust = 1, size = 7))
plot
We have more fine-grained data than state-level data, right? And we have other information than just vote share, right? So let’s use both. Let’s use a dot plot to look at the relationship between median income and Trump support at the county level.
ggplot(d) +
geom_point(aes(x = median_income, y = vote_share))
That is cool. A lot of the data is clustered around about $50,000 and between 50% and 80% support for Trump, which kind of makes things difficult to read. We can address this by adding some transp?aloaranecy to our points.
ggplot(d) +
geom_point(aes(x = median_income, y = vote_share),
alpha = .3)
That is kind of interesting, but it is kind of all over the place too. There is a lot going on in there. It would be nice to be able to summarize the relationship between income and vote share.
One way to do this is with linear regression. We won’t go over the details of this here, but if you are unfamiliar with regression that is just fine. Think of it as a way of estimating the average value of a variable (in this case Trump’s vote share) given different values of another variable (in this case median income)
ggplot(d, aes(x = median_income, y = vote_share)) +
geom_point(alpha = .3) +
geom_smooth(formula = y ~ x,
method = 'lm', # specifying a linear model
se = F) # don't worry about this
Now we have a way of summarizing the relationship between our two variables. On average, counties with a higher median income were less supportive of Trump in 2016.
3j. Make at least three additions to the plot above. Perhaps some new labels? Titles are always helpful; maybe a caption including info about where I got the data?
ggplot(d, aes(x = median_income, y = vote_share)) +
geom_point(alpha = .2) +
ggtitle("Super Helpful Title") + #Add a Title
labs(subtitle = "By Pearl", caption = "Titles and labels are false") + #Add subtitle and caption
xlab("Income") + #Add label to X-axis
ylab("Amount of Corn Cobs Consumed per Hour") + #Add label to Y-axis
geom_smooth(formula = y ~ x,
method = 'lm', # specifying a linear model
se = F) # don't worry about this
Right now we are looking across the entire country, but what is we wanted to see what this relationship looked like in every state? One way to do this would be to use the facet_wrap function.
ggplot(d, aes(x = median_income, y = vote_share)) +
geom_point(alpha = .3) +
geom_smooth(formula = y ~ x,
method = 'lm', # specifying a linear model
se = F) + # don't worry about this
facet_wrap(~state)
Personally, I think this is a bit much but it is interesting to examine.
3k. In your own words, what does the facet_wrap function do here? Discuss a trend or finding from this plot that you would not learn from just looking at the single plot. > Facet_wrap() function seems to have made a plot chart that shows the income level (x-axis) and % of voters who voted for trump (y-axis) in every county in each state. One dot represents a single county.
It is OK if this doesn’t work 100%. Your plots do not need to be pretty, you just have to produce something similar. The goal here is to challenge you some at the end.
4a. Make a dot plot of the relationship between income and trump’s vote share in the state of Michigan. Give it nice labels and a title.
4b. Last challenge (bonus). Can you figure out how to save your two new plots as files? This will take some googling.
#remember to comment on your code
4c Bonus bonus: Create a dot plot of the relationship between median income and Trump’s vote share with two facets: one contains counties in states in which Trump won more votes than Clinton and the other contains counties in states in which Trump won fewer votes than Clinton.
#remember to comment on your code
4d Bonus bonus bonus: Replicate the dot plot of relationship between median income and Trump’s vote share across all counties in the US (this is just the simple plot without any facets). This time, though, figure out how to highlight Washtenaw county so that it is a different color than every other county in the US.
See assignment instructions for more info on knitting.