Class 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")

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 tables

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.