library(readxl) # for reading Excel files
library(googlesheets4) # for reading Google Sheets
library(janitor) # for cleaning column names
library(tidyverse) # for data wrangling and plotting
library(gt) # for creating nice tablesClass Monitoring
Class monitoring
This work sheet is going to take you through how you can set up simple on-line forms and read the data directly into R enabling you to visualize and the data very quickly. We will start by simply reading data in, tidying it and displaying in a table. As the module continues we will develop this to learn how to track and visualise data over time, considering how to determine any important changes. Finally, we might consider if we can build an app that can be responsive to our needs and make it easy to make data informed decisions.
Monitoring Sheet
I have set up a sheet using google forms to collect data about how each class member is feeling about the module, as well as capturing training load and any muscular soreness.
It is completely up to you if you want to fill this in or not - for teaching purposes your data will be available for yourself and the rest of the group to view. By submitting a response you are given your consent for the data to be collect and analysed in the module for teaching purposes.
Should you wish to participate the form can be viewed here
R-Script
This workbook will take you through some recommended code stage by stage offering explanations and suggestions along the way.
I have set up an r-script template and added this to blackboard. I would recomend creating a project in a new directory (perhaps call this class_monitoring or simlar). You can then download the relevant files from blackboard to this folder.
Load packages
To enable us to read the data into R-Studio, tidy and wrangle it so as to provide a simple output we will need the following packages. Remember, if you have not installed these packages first you will not be able to load them.
To install packages you can either choose the “Packages” tab in the “Files”, “Plots”, “Packages” etc. window & then install or use the code install.packages() remembering to put the package in quotation marks e.g. install.packages("googlesheets4")
Import data
I have created a text file on blackboard called “training_monitoring_link.txt” which holds the link to a Google sheet where all responses to the form are kept. To import the data we are going to read this file into R using the code read_file() and cal this “cm_link”. We will then read the data in using read_sheet().
head() is used to show us the first 6 rows of our data.
cm_link <- read_file("training_monitoring_link.txt")
class_monitoring <- read_sheet(ss = cm_link)
head(class_monitoring)# A tibble: 1 × 28
Timestamp `Please insert your initials` `Please insert today's date`
<dttm> <chr> <dttm>
1 2026-01-19 16:32:44 MW 2026-01-19 00:00:00
# ℹ 25 more variables: `Have you rated how you feel today?` <chr>,
# `Please rate how you feel this morning [General muscle soreness]` <chr>,
# `Please rate how you feel this morning [Mood]` <chr>,
# `Please rate how you feel this morning [Hydration]` <chr>,
# `Please rate how you feel this morning [Sleep Quality]` <chr>,
# `Please rate how you feel this morning [Stress leves]` <chr>,
# `Please rate how you feel about this module [R-coding skill]` <chr>, …
Tidy and wrangle data
You will notice now that we have a lot of columns with long names, we need to tidy these up and choose the ones we are interested in. We will use clean_names() from the janitor package first to help us.
# auto clean all col names -----
class_monitoring <- clean_names(class_monitoring)For now we are going to focus on our so called “Wellness” items. We will use select() from the dplyr package (part of the Tidyverse packages), this will allow us to choose. Note it can be useful to see all of the column names in a data frame and to do this you can use the code col_names().
The code below chooses the “wellness” questions (alongside initials and date) using select(), inside the brackets we choose the column name and if we want to change it we put the desired column name before hand e.g. id = please_insert_your_initials. This leads to a more manageable set of data.
wellness <- class_monitoring %>%
select(id = please_insert_your_initials,
date = please_insert_todays_date,
muscle_soreness = please_rate_how_you_feel_this_morning_general_muscle_soreness,
mood = please_rate_how_you_feel_this_morning_mood,
hydration = please_rate_how_you_feel_this_morning_hydration,
sleep_quality = please_rate_how_you_feel_this_morning_sleep_quality,
stress = please_rate_how_you_feel_this_morning_stress_leves,
wellness_comments = please_provide_a_comment_on_how_you_feel_today)
head(wellness)# A tibble: 1 × 8
id date muscle_soreness mood hydration sleep_quality stress
<chr> <dttm> <chr> <chr> <chr> <chr> <chr>
1 MW 2026-01-19 00:00:00 Good Good Moderate Moderate Good
# ℹ 1 more variable: wellness_comments <chr>
Filter to look at data for a specific date
Filter data
The code below uses the filter() function from dplyr to select a specific date. Notice the use of == here.
wellness %>%
filter(date == "2026-01-19")# A tibble: 1 × 8
id date muscle_soreness mood hydration sleep_quality stress
<chr> <dttm> <chr> <chr> <chr> <chr> <chr>
1 MW 2026-01-19 00:00:00 Good Good Moderate Moderate Good
# ℹ 1 more variable: wellness_comments <chr>
Create GT table to make a nice output
You may have notice that above we use %>% regularly, this enables you to create a pipe which means we can build on one function with another functions. In the pipe above we are taken our data set “wellness” and filtering by date. Below we are filtering by date and then creating a table with “id” as a row name. We can the keep adding to the pipe.
NOTE: There are many ways to do things in R, this is just one way of creating a table - perhaps try and see if you can do this a different way?
wellness %>%
filter(date == "2026-01-19") %>%
gt(rowname_col = "id")| date | muscle_soreness | mood | hydration | sleep_quality | stress | wellness_comments | |
|---|---|---|---|---|---|---|---|
| MW | 2026-01-19 | Good | Good | Moderate | Moderate | Good | Good start - only one student. |
Improving our GT table
We can add on to our pipe function, below I have changed the column names so they lend themselves better to an table output (as opposed to column names for coding). Here we have used cols_label() to do this with the column name first and then our new names in quotation marks.
wellness %>%
filter(date == "2026-01-19") %>%
gt(rowname_col = "id") %>%
cols_label(
id = "ID",
muscle_soreness = "Muscle soreness",
mood = "Mood",
hydration = "Hydration",
sleep_quality = "Sleep quality",
stress = "Stress",
wellness_comments = "Wellness notes"
)| date | Muscle soreness | Mood | Hydration | Sleep quality | Stress | Wellness notes | |
|---|---|---|---|---|---|---|---|
| MW | 2026-01-19 | Good | Good | Moderate | Moderate | Good | Good start - only one student. |
Let’s add a header now and remove the column “date” as we do not need it.
We’ll use tab_header() to add the header “Daily Wellness – 19 Jan 2026” and we’ll use select() again but this time to deselect a row select(-c(date))
wellness %>%
filter(date == "2026-01-19") %>%
select(-c(date)) %>%
gt(rowname_col = "id") %>%
cols_label(
id = "ID",
muscle_soreness = "Muscle soreness",
mood = "Mood",
hydration = "Hydration",
sleep_quality = "Sleep quality",
stress = "Stress",
wellness_comments = "Wellness notes"
) %>%
tab_header(title = md("**Daily Wellness – 19 Jan 2026**")) | Daily Wellness – 19 Jan 2026 | ||||||
|---|---|---|---|---|---|---|
| Muscle soreness | Mood | Hydration | Sleep quality | Stress | Wellness notes | |
| MW | Good | Good | Moderate | Moderate | Good | Good start - only one student. |
Finally, I’ve given the table a name “well_table” and changed some of the formatting, including borders and font size, as well as cols_width to give more space for quals.
Try playing around with the tab options to see how this changes your output.
well_table <- wellness %>%
filter(date == "2026-01-19") %>%
select(-c(date)) %>%
gt(rowname_col = "id") %>%
cols_label(
id = "ID",
muscle_soreness = "Muscle soreness",
mood = "Mood",
hydration = "Hydration",
sleep_quality = "Sleep quality",
stress = "Stress",
wellness_comments = "Wellness notes"
) %>%
tab_header(title = md("**Daily Wellness – 19 Jan 2026**")) %>%
tab_options(
table.font.size = px(14),
data_row.padding = px(6),
heading.border.bottom.color = "grey80",
table.border.top.color = "white",
table.border.bottom.color = "white",
column_labels.font.weight = "bold"
) %>%
cols_width(
everything() ~ px(120),
wellness_comments ~ px(420)
)
well_table| Daily Wellness – 19 Jan 2026 | ||||||
|---|---|---|---|---|---|---|
| Muscle soreness | Mood | Hydration | Sleep quality | Stress | Wellness notes | |
| MW | Good | Good | Moderate | Moderate | Good | Good start - only one student. |