Activity: Getting Started
From a question in the field to your first plot in R
Worksheet: Getting Started
π₯ Download the data (.csv) π₯ Download the data (.xlsx)
pine_data.csv / pine_data.xlsx
Both files hold the same six columns, with exactly these names. Type them exactly as written β R is case-sensitive, and Needle_Length or needle_length will not work:
| Column | What it is |
|---|---|
source_file |
the raw team file the row came from |
team |
field team β one team = one tree |
replicate |
needle number within a tree side (1-8) |
side |
sun exposure β "shady" or "sunny" |
needle_length_mm |
needle length, millimetres |
needle_width_mm |
needle width, millimetres |
After you read the file in, run names(pine_df) and check the names on your screen against this table before you write any other code.
Part 1 Β· Todayβs question
Recap
- We are asking whether pine needle length differs between the shady side and the sunny side of a tree.
- The tree, not the needle, is our unit of replication β one tree is not enough (this is called pseudoreplication).
βοΈ Your turn: Write your own null and alternate hypotheses in your own words.
H0:
Ha:
βοΈ Your turn: Is the following statement inductive or deductive reasoning? βI measured needles on three trees, all showed the shady side longer, so I expect a fourth tree to show the same pattern.β Why canβt we test a hypothesis like this using only one tree?
Reasoning type:
Why one tree isn't enough:
Field collection plan
As a group, agree on and record your answers before you go outside:
Sample height on tree:
Definition of "mature" needle:
Needles per side, per tree:
Label convention for the side column (shady / sunny):
Part 2 Β· Build your project folder
Why a project folder?
Everything for this project lives in one folder, so every file path is relative to it β no more hunting for where a file went.
π Read more: R4DS Β§6 β Workflow: scripts and projects, and Gotelli & Ellison Ch. 8 (Managing and Curating Data) on Canvas.
Create the folder structure
Make a new folder called pine_project. Inside it, create four sub-folders:
pine_project/
βββ data/ β your CSV and Excel files go here
βββ scripts/ β your .R code goes here
βββ figures/ β plots you save go here
βββ output/ β place to save modified dataframes
Copy pine_data.csv into pine_project/data/.
β οΈ Important: Leave this copy alone β it is raw data. We will read it but never overwrite it. (Your own field data will get cleaned up and added here starting in Wrangling Your Data.)
βοΈ Your turn: Full path to your pine_project folder:
_________________________________________________________________________________________________________________________________________________________________
Part 3 Β· Enter your data in Excel
Before R ever sees your numbers, they have to get from your field notes into a spreadsheet. How you do that now determines how much pain youβre in later β so we do it deliberately.
Set up your header row first
Open Excel and make row 1 your column headers β nothing else goes in that row. Use the same controlled vocabulary your group already agreed on in Part 1, written the lower_snake_case way (no spaces, no units hidden in the text): what will they be?
| Column | units? | What goes in it |
|---|---|---|
β οΈ Watch out!
Needle Length (mm)andneedle_length_mmlook equally clear to a human β only one of them is a header R can use without a fight. Spaces, parentheses, and units in the header text all cause problems later.
One row = one measurement
This is the part people get wrong under time pressure: every single needle you measured gets its own row. Not one row per tree with eight length columns crammed in β one row per needle, with team, side, and replicate repeated on every row that needle belongs to. Yes, that means typing shady over and over. That repetition is doing real work β itβs what lets R filter, group, and plot by any of those columns later.
β οΈ Watch out! β Common Excel data-entry mistakes
- Merged cells. They look nice, they break every import. Never merge.
- Blank rows or blank columns used as visual spacers. R reads them as missing data, not as whitespace.
- More than one header row, or notes typed above row 1. R will try to read your note as a column name.
- Numbers stored as text.
20 mmin a cell is text;20is a number. Keep units in the header, not in the cell. - Inconsistent spelling of the same category β
Sunny,sunny(trailing space), andsunnyare three different values to R, even though they mean the same thing to you. - Color-coding instead of a column. Highlighting a row yellow to mean something is invisible to R. If it matters, it needs its own column.
Enter your groupβs data
βΆ Do this now: Using the measurements your group collected today, enter one row per needle into Excel using the header row above.
βοΈ Your turn: How many rows should your sheet have, if your group measured ______________ needles per
side, per tree, on _____________ trees? Show your arithmetic:
________________________
π Honest preview β this probably isnβt βtidyβ yet
Excel invites you to spread related numbers across columns β one column per tree, or one column per needle. Thatβs a completely normal way to enter data quickly, and it is not the same as tidy data: the rule (from R for Data Science) that every variable is a column, every observation is a row, and every value is a cell. If your sheet doesnβt fully follow that yet, thatβs fine β turning a wide, human-friendly layout into a tidy one is exactly what weβll do with pivot_longer() in Wrangling Your Data. Today, just get the numbers in accurately.
Save it β both formats
File β Save As, into your pine_project/data/ folder, twice:
- Once as an Excel workbook (
.xlsx) β keeps any formatting you added. - Once as CSV UTF-8 (
.csv) β plain text, no hidden formatting, and the format every other tool (including R) can read without a special library.
β οΈ Important: Save both into
data/, and β likepine_data.csvβ treat them as raw data from this point on: read them, never hand-edit them again. Corrections happen in R, where every change is a line of code you can see and undo.
βοΈ Your turn: What are the two file names you just saved, and are they both sitting in pine_project/data/?
______________________________________________________________________________________
Part 4 Β· Orient yourself in Positron
Open your project folder as your workspace: File β Open Folderβ¦
Four panes youβll use constantly:
| Pane | Where | What it does |
|---|---|---|
| Editor | top-left | your scripts live here |
| Console | bottom | where code actually runs |
| Environment | right | every object youβve stored |
| Plots / Files | right (tab) | your figures and project files |
βοΈ Your turn: Click the Console tab. Type 1 + 1 and press Enter. Result:
_____________
Part 5 Β· R as a calculator, and storing values
βΆ Run this in the Console:
# ββ Part 5.1 Β· R as a calculator, and storing values ββββββββββββββββββββ
3 + 5
12 / 7
2 ^ 10
sqrt(144)β οΈ Watch out! A
+at the start of a console line (instead of the usual>prompt) means R is still waiting for you to finish typing something. Press Esc to cancel.
Now store a value with the assignment operator <- (shortcut: Alt/Option + -):
βΆ Run this:
# ββ Part 5.2 Β· R as a calculator, and storing values ββββββββββββββββββββ
x <- 7 # store 7 under the name x
x # read it back
x * 2 # use it in mathLook for x in the Environment pane.
βοΈ Your turn: Store the number 42 as my_number, then multiply it by x. Result:
__________________
# ββ Part 5.3 Β· R as a calculator, and storing values ββββββββββββββββββββ
# Write your code in the R script:π If you finish early: Try x / my_number and my_number %% x (the remainder operator). Predict each result before you run it.
Part 6 Β· Naming things well
Good names make code readable months later: be explicit (needle_length, not x2), never start with a number, and R is case-sensitive (needle_length_mm β Needle_Length_mm). Use lower_snake_case.
βοΈ Your turn: Which of these are valid R object names? Circle Y or N.
needle_length Y / N
3rd_needle Y / N
Needle_Length_mm Y / N
my.needle.data Y / N
side Y / N
Part 7 Β· Comments
Anything after # is ignored by R β a note for humans.
βΆ Run this in your Script:
# ββ Part 7.1 Β· Comments βββββββββββββββββββββββββββββββββββββββββββββββββ
# average of four needle lengths, in mm
needle_length <- c(20, 21, 23, 25)
mean(needle_length) # average needle lengthπ‘ Key idea: If a line confused you while writing it, comment why you did it β future you will forget.
Part 8 Β· Functions and arguments
A function is called by name and takes arguments in ().
βΆ Run this in the Console:
# ββ Part 8.1 Β· Functions and arguments ββββββββββββββββββββββββββββββββββ
sqrt(10)
round(3.14159) # default: 0 decimal places
round(3.14159, 2) # 2 decimal places
round(x = 3.14159, digits = 2)Stuck? ?round opens the help page.
βοΈ Your turn: Use round() to round pi (R knows this by name) to 4 decimal places. Result:
_______________
# ββ Part 8.2 Β· Functions and arguments ββββββββββββββββββββββββββββββββββ
# Write your code in the R script:Part 9 Β· Vectors and data types
A vector is a series of values built with c() which is also called a concatenated list and we will see it more. A spreadsheet column is really just a vector.
βΆ Run this in your Script:
# ββ Part 9.1 Β· Vectors and data types βββββββββββββββββββββββββββββββββββ
needle_length_mm <- c(20, 21, 23, 25) # numeric vector
side <- c("n", "s") # character vector β needs quotes
length(needle_length_mm) # how many values?
class(needle_length_mm) # what type?β οΈ Watch out!
"n"in quotes is text. Without quotes, R looks for an object callednand errors if none exists.
βοΈ Your turn: Make a character vector called my_sides with the values "n" and "s". Check its length() and class().
# ββ Part 9.2 Β· Vectors and data types βββββββββββββββββββββββββββββββββββ
# Write your code in the R script:π If you finish early: Make a numeric vector of 5 needle lengths you make up. Run mean() and sd() on it β both work directly on a vector, no data frame needed.
Part 10 Β· Packages and libraries
Install once, in the Console:
# Console only β do NOT put this line in your script
install.packages("tidyverse")Load every session β put this at the very top of every script:
βΆ Run this at the top of your Script:
# ββ Part 10.2 Β· Packages and libraries ββββββββββββββββββββββββββββββββββ
library(tidyverse)βοΈ Your turn: First line R prints after library(tidyverse):
________________________
π Read more: R4DS Β§2 β Workflow: basics and Β§4 β Workflow: code style.
Part 11 Β· Load the pine needle data
Create your script
File β New File β R Script. Save it immediately as 01_getting_started.R inside pine_project/scripts/.
βΆ Run this in your Script:
# ββ Part 11.1 Β· Load the pine needle data βββββββββββββββββββββββββββββββ
pine_df <- read_csv("data/pine_data.csv")
pine_df # print to consoleThe path "data/..." is relative to your project folder β it works on anyoneβs computer, not just yours.
π Read more: R4DS Β§7 β Data import.
Always look before you trust it
βΆ Run each of these:
# ββ Part 11.2 Β· Load the pine needle data βββββββββββββββββββββββββββββββ
head(pine_df) # first 6 rows
dim(pine_df) # (rows, columns)
names(pine_df) # column namesβοΈ Your turn: Answer from the output above.
Rows: Columns:
Type of side: Values in side:
βοΈ Your turn: The file has 64 rows. But how many trees were actually sampled? (Hint: count the teams, and remember each team measured one tree.)
________________________
βοΈ Your turn: If two needles come off the same branch of the same tree, are they really two independent pieces of evidence about sun exposure? Why or why not?
________________________
Part 12 Β· Your first plot
Every ggplot is built from three pieces, joined with +: data, aes() (which columns map to x/y), and a geom (how to draw it).
π Read more: R4DS Β§1 β Data visualization. For why we plot before we test, see Whitlock & Schluter Ch. 2 (Displaying Data) on Canvas.
βΆ Run this β the simplest possible plot:
# ββ Part 12.1 Β· Your first plot βββββββββββββββββββββββββββββββββββββββββ
ggplot(pine_df, aes(x = side, y = needle_length_mm)) +
geom_point()β οΈ Watch out! The
+sits at the end of a line, never the start.
Improve it one layer at a time
βΆ Run this:
# ββ Part 12.2 Β· Your first plot βββββββββββββββββββββββββββββββββββββββββ
ggplot(pine_df, aes(x = side, y = needle_length_mm)) +
geom_boxplot() +
geom_jitter(width = 0.15, alpha = 0.6) +
labs(x = "Sun exposure", y = "Needle length (mm)")βοΈ Your turn: Make the same plot using team instead of side on the x-axis. Copy the code above and change whatβs needed.
# ββ Part 12.3 Β· Your first plot βββββββββββββββββββββββββββββββββββββββββ
# Write your modified code in the R script:What pattern do you see β does the shady or sunny side tend to have longer needles?
________________________
βοΈ Your turn: In your team plot, how much do the four teams differ from one another compared with how much the two sides differ?
________________________
π If you finish early: Try geom_violin() instead of geom_boxplot(), or add color = team inside aes() to see each field teamβs data separately.
Part 13 Β· Save your plot
βΆ Run this:
# ββ Part 13.1 Β· Save your plot ββββββββββββββββββββββββββββββββββββββββββ
needle_plot <- ggplot(pine_df, aes(x = side, y = needle_length_mm)) +
geom_boxplot() +
geom_jitter(width = 0.15, alpha = 0.6) +
labs(x = "Sun exposure", y = "Needle length (mm)")
ggsave("figures/needle_length.png",
plot = needle_plot,
width = 3,
height = 3,
units = "in",
dpi = 300)Check your figures/ folder β the PNG should be there.
β οΈ Watch out!
ggsave()wants the filename first, thenplot =. Always usedpi = 300.
Part 14 Β· Review and checkpoint
At this point you can:
βοΈ Your turn β before you move on: Run your whole script top to bottom (or line by line). Ran cleanly? Y / N β if not, the error was:
________________________
π€ What to turn in before next class
Upload both of these to the course management system:
- Your code β the
scripts/folder (or just01_getting_started.R) - This worksheet, with your written answers
Part 15 Β· Going further β optional in class, or take-home if youβd like more practice
Work through this if you finish early. There are no wrong answers β the goal is to see what
ggplotcan do.
Histograms, split by team
βΆ Try this:
# ββ Part 15.1 Β· Going further βββββββββββββββββββββββββββββββββββββββββββ
ggplot(pine_df, aes(x = needle_length_mm, fill = side)) +
geom_histogram(binwidth = 2, position = position_dodge2(width = 0.5)) +
labs(x = "Needle length (mm)", y = "Count", fill = "Sun exposure")βοΈ Your turn: Are the two distributions similar in shape, or different?
________________________
Facets β one panel per team
# ββ Part 15.2 Β· Going further βββββββββββββββββββββββββββββββββββββββββββ
ggplot(pine_df, aes(x = needle_length_mm)) +
geom_histogram(binwidth = 2) +
facet_wrap(~team)Violin plots
# ββ Part 15.3 Β· Going further βββββββββββββββββββββββββββββββββββββββββββ
ggplot(pine_df, aes(x = side, y = needle_length_mm, fill = side)) +
geom_violin(alpha = 0.5) +
geom_jitter(width = 0.1, size = 2) +
theme(legend.position = "none")Themes β change the look
Add any of these to a plot above:
# ββ Part 15.4 Β· Going further βββββββββββββββββββββββββββββββββββββββββββ
+ theme_bw()
+ theme_minimal()
+ theme_classic()βοΈ Your turn: Which theme do you like best for this kind of biological comparison? Why?
________________________
What your finished project folder looks like
pine_project/
βββ data/
β βββ pine_data.csv <- never touch this
βββ scripts/
β βββ 01_getting_started.R <- your complete script
βββ figures/
βββ needle_length.png <- Part 13
This is the structure we will use for every analysis this term.
| Folder | Contents | Rule |
|---|---|---|
data/ |
raw files | read-only, never overwrite |
scripts/ |
.R code |
one script per module |
figures/ |
saved plots | always PNG, always dpi = 300 |
Readings
Before next class β chapter PDFs are posted on Canvas:
- Whitlock & Schluter, The Analysis of Biological Data β Ch. 1, Statistics and Samples (populations vs. samples, why we sample, sampling error)
- Gotelli & Ellison, A Primer of Ecological Statistics β Ch. 8, Managing and Curating Data (raw data, metadata, project organization)
If you want more:
- Whitlock & Schluter, Ch. 2 β Displaying Data
- Gotelli & Ellison, Ch. 4 β Framing and Testing Hypotheses
R for Data Science (2nd ed.) β free online at r4ds.hadley.nz. The chapters behind todayβs worksheet:
| Chapter | Covers | Worksheet part |
|---|---|---|
| Β§1 β Data visualization | ggplot(), aes(), geoms |
Parts 12, 15 |
| Β§2 β Workflow: basics | objects, <-, functions |
Parts 5-8 |
| Β§4 β Workflow: code style | naming things, comments | Parts 6-7 |
| Β§6 β Workflow: scripts and projects | scripts, project folders, relative paths | Parts 2, 11 |
| Β§7 β Data import | read_csv(), checking what you loaded |
Part 11 |
| Β§8 β Workflow: getting help | reading errors, asking good questions | reading errors |
Homework
You will build a project from scratch β directories, a Quarto file, and a script β and read in a dataset you have not seen in class: Arctic grayling from lakes I-3 and I-8, measured on the North Slope of Alaska. You read the same data twice, once from .csv and once from .xlsx, then summarise and plot it and save the figure to PDF.
Data: gray_I3_I8.csv and gray_I3_I8.xlsx β a course field dataset, not a textbook one, so there is no chapter to look up.