This report summarises Year 3 course unit enrolment data by discipline and course type.
This section explores overall student enrolments across Year 3 course units. It highlights which units have the highest and lowest student numbers, helping to identify courses that are particularly popular or under-utilised.
library(tidyverse)
library(DT)
# Filter relevant rows
enrolment_data <- df %>%
filter(Measure == "Number of students overall on the course unit", !is.na(Value))
# Top 10 most enrolled units
top_units <- enrolment_data %>%
arrange(desc(Value)) %>%
select(`Unit Code`, `Unit Name`, Value) %>%
head(10)
# Bottom 10 least enrolled units
bottom_units <- enrolment_data %>%
arrange(Value) %>%
select(`Unit Code`, `Unit Name`, Value) %>%
head(10)
# Display with DT
datatable(top_units, caption = "Top 10 Most Enrolled Units", options = list(pageLength = 5))
This section provides a breakdown of total enrolments across different disciplines.
# Prepare summary data
discipline_summary <- df %>%
filter(Measure == "Number of students overall on the course unit", !is.na(Value)) %>%
group_by(Discipline) %>%
summarise(Total_Enrolment = sum(Value), .groups = "drop") %>%
arrange(desc(Total_Enrolment))
# Display data table
datatable(discipline_summary, caption = "Total Enrolment by Discipline", options = list(pageLength = 10))
# Plot enrolment by discipline
ggplot(discipline_summary, aes(x = reorder(Discipline, -Total_Enrolment), y = Total_Enrolment)) +
geom_col(fill = "lightblue", colour = "black", width = 0.7) +
geom_text(aes(label = round(Total_Enrolment, 0)),
vjust = -0.5,
size = 3.5) +
coord_flip() +
labs(title = "Total Enrolments by Discipline (Year 3)",
x = "Discipline",
y = "Number of Students") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
axis.text.y = element_text(size = 10),
axis.text.x = element_text(size = 10),
axis.title = element_text(size = 12)
)
This chart shows the total number of students enrolled in Year 3 course units across disciplines, broken down by academic year group (Student Group codes 1191–1241). It helps identify trends in subject popularity and can guide programme restructuring.
We can observe whether certain disciplines are consistently popular, gaining momentum, or declining in interest across cohorts.
## Discipline Enrolment Trends by Academic Year
# Load the cleaned long-format data
y3 <- read_csv("Y3_Long.csv")
# Ensure Value is numeric
y3$Value <- suppressWarnings(as.numeric(y3$Value))
# Filter and summarise overall course unit enrolments by discipline and student group
discipline_trend <- y3 %>%
filter(Measure == "Number of students overall on the course unit" & !is.na(Value)) %>%
group_by(Discipline, `Student Group`) %>%
summarise(Total = sum(Value, na.rm = TRUE), .groups = 'drop') %>%
mutate(`Student Group` = as.character(`Student Group`))
# Plot
ggplot(discipline_trend, aes(x = `Student Group`, y = Total, fill = Discipline)) +
geom_bar(stat = "identity", position = "stack", colour = "black") +
labs(
title = "Year 3 Enrolment by Discipline Across Academic Years",
x = "Academic Year (Student Group Code)",
y = "Total Students Enrolled",
fill = "Discipline"
) +
theme_minimal(base_size = 13) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(face = "bold", hjust = 0.5),
axis.title = element_text(face = "bold")
)
This section compares enrolments by course type (e.g., Core Optional, Pathway Option). It provides insights into student preferences and the effectiveness of curriculum design. Higher enrolment in certain types of courses may suggest relevance or popularity, while lower enrolment could highlight areas for review.
# Prepare summary by course type
course_type_summary <- df %>%
filter(Measure == "Number of students overall on the course unit", !is.na(Value)) %>%
group_by(`Course Type`) %>%
summarise(Total_Enrolment = sum(Value), .groups = "drop") %>%
arrange(desc(Total_Enrolment))
# Display data table
datatable(course_type_summary, caption = "Total Enrolment by Course Type", options = list(pageLength = 10))
# Plot enrolment by course type
ggplot(course_type_summary, aes(x = reorder(`Course Type`, -Total_Enrolment), y = Total_Enrolment)) +
geom_col(fill = "lightgreen", colour = "black", width = 0.7) +
geom_text(aes(label = round(Total_Enrolment, 0)),
vjust = -0.5,
size = 3.5) +
coord_flip() +
labs(title = "Total Enrolments by Course Type (Year 3)",
x = "Course Type",
y = "Number of Students") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
axis.text.y = element_text(size = 10),
axis.text.x = element_text(size = 10),
axis.title = element_text(size = 12)
)
This section explores the number of students from each academic year cohort (identified by Student Group codes, e.g., 1191 to 1241) enrolled in individual Year 3 course units.
Tracking enrolment by academic year helps identify:
# Filter for relevant pathway-specific data
pathway_counts <- df %>%
filter(Measure == "Number by BASS pathway", !is.na(Value)) %>%
select(`Unit Code`, `Unit Name`, `Student Group`, Value, Discipline) %>%
arrange(desc(Value))
# Preview top 20 entries
datatable(head(pathway_counts, 20),
caption = "Sample of Enrolments by BASS Pathway per Course Unit",
options = list(pageLength = 10))
The heatmap below visualises the number of students from each academic year cohort (identified by Student Group codes) enrolled in individual Year 3 course units.
Darker shades indicate higher enrolment. This visual representation helps highlight:
It also helps identify units that are consistently in demand versus those with limited or cohort-specific appeal.
# Prepare data
heatmap_data <- df %>%
filter(Measure == "Number by BASS pathway", !is.na(Value)) %>%
mutate(Pathway = as.factor(`Student Group`)) %>%
select(`Unit Code`, `Unit Name`, Pathway, Value)
# Create plot with Unit Code on Y axis and Unit Name in tooltip
p <- ggplot(heatmap_data, aes(x = Pathway, y = reorder(`Unit Code`, Value), fill = Value, text = paste(
"Unit Code:", `Unit Code`, "<br>",
"Unit Name:", `Unit Name`, "<br>",
"Year:", Pathway, "<br>",
"Students:", round(Value, 0)
))) +
geom_tile(colour = "white") +
scale_fill_gradient(low = "white", high = "darkblue") +
labs(title = "Interactive Heatmap: Enrolment by BASS Pathway and Course Unit",
x = "BASS Pathway (Student Group)",
y = "Unit Code",
fill = "Number of Students") +
theme_minimal()
# Convert to interactive plot
ggplotly(p, tooltip = "text")
The heatmap below shows how student enrolments in the top 20 most popular Year 3 units are distributed across academic disciplines. This provides insight into which departments offer widely chosen units and where overlaps or interdisciplinary engagement occur.
# Prepare data: enrolment by unit and discipline
heatmap_data <- df %>%
filter(Measure == "Number of students overall on the course unit", !is.na(Value)) %>%
select(`Unit Code`, Discipline, Value)
# Get top 20 most enrolled unit codes
top_units <- heatmap_data %>%
group_by(`Unit Code`) %>%
summarise(Total = sum(Value), .groups = "drop") %>%
slice_max(Total, n = 20)
# Filter to top units only
heatmap_data <- heatmap_data %>%
filter(`Unit Code` %in% top_units$`Unit Code`)
# Plot
p <- ggplot(heatmap_data, aes(
x = Discipline,
y = fct_reorder(`Unit Code`, Value, .fun = sum),
fill = Value,
text = paste(
"Unit Code:", `Unit Code`, "<br>",
"Discipline:", Discipline, "<br>",
"Students:", round(Value, 0)
)
)) +
geom_tile(colour = "white") +
scale_fill_gradient(low = "white", high = "darkblue") +
labs(
title = "Top 20 Units by Enrolment (by Discipline)",
x = "Discipline",
y = "Unit Code",
fill = "No. of Students"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
axis.text.y = element_text(size = 9)
)
ggplotly(p, tooltip = "text")
How to Read the Heatmap: Top 20 Year 3 Units by Discipline
This interactive heatmap displays enrolments in the 20 most popular Year 3 course units, broken down by student discipline. It highlights cross-disciplinary engagement and course popularity across departments.
The table below lists all Year 3 course units along with their total BASS enrolment across years, overall enrolment, and BASS pathway percentage. You can filter and sort the table to identify the most and least popular course units.
# Filter for total course unit data
df_filtered <- df %>%
filter(Measure == "Number of students overall on the course unit")
# Total enrolment per course unit (BASS + non-BASS)
total_enrolment <- df_filtered %>%
group_by(`Unit Code`, `Unit Name`) %>%
summarise(`Total Enrolment` = sum(Value), .groups = "drop")
# BASS enrolment is the same as this filtered dataset
bass_enrolment <- df_filtered %>%
group_by(`Unit Code`, `Unit Name`) %>%
summarise(`BASS Enrolment` = sum(Value), .groups = "drop")
# Merge and calculate %
unit_summary <- left_join(total_enrolment, bass_enrolment,
by = c("Unit Code", "Unit Name")) %>%
mutate(`BASS %` = round(`BASS Enrolment` / `Total Enrolment` * 100, 1)) %>%
arrange(desc(`BASS Enrolment`))
# Display as datatable
datatable(unit_summary, options = list(pageLength = 10), rownames = FALSE)
You can explore enrolment patterns by discipline or course unit using the interactive dashboard:
https://sisteranalyst.shinyapps.io/year3/
This visual shows which units are especially popular for particular academic cohorts (i.e., year groups). It helps identify units that may have been core, required, or particularly aligned with a given year’s programme structure.
The chart below focuses on the top 15 Year 3 course units based on total BASS enrolment across all academic cohorts (from 1191 to 1241).
These units were identified by summing the number of BASS students enrolled in each unit across all years, and selecting the 9 with the highest cumulative enrolment. This ensures the visual highlights the most impactful or widely taken units in the programme, offering a clearer comparison of how their popularity varied by cohort year.
This can reveal:
# Prepare data
df_units_by_year <- df %>%
filter(Measure == "Number by BASS pathway") %>%
mutate(UnitLabel = paste(`Unit Code`),
CohortYear = as.character(`Student Group`)) # Academic year as string
# Aggregate totals per unit and cohort
unit_year_totals <- df_units_by_year %>%
group_by(UnitLabel, CohortYear) %>%
summarise(Enrolment = sum(Value), .groups = "drop")
# Filter to top 9 units overall for readability
top_units <- unit_year_totals %>%
group_by(UnitLabel) %>%
summarise(Total = sum(Enrolment), .groups = "drop") %>%
top_n(12, Total) %>%
pull(UnitLabel)
unit_year_top <- unit_year_totals %>%
filter(UnitLabel %in% top_units)
# Plot with 3 plots per row
ggplot(unit_year_top, aes(x = CohortYear, y = Enrolment, fill = CohortYear)) +
geom_col(show.legend = FALSE) +
facet_wrap(~ UnitLabel, scales = "free_y", ncol = 3) +
labs(title = "Top Units: Enrolment by Cohort Year",
x = "Academic Year", y = "No. of Students") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
This bar chart compares enrolment across course types (e.g., core optional modules vs pathway options) to explore whether students favour flexible choices over structured ones.
This bar chart compares student enrolment across different course types (e.g., core optional modules vs pathway options). It summarises total enrolment for each course type across all academic years and disciplines.
By grouping units by their Course Type
and summing the
number of students enrolled in each, the chart shows whether students
tend to prefer structured offerings (like “Core Optional for POLI
Pathway”) or more flexible choices (like “POLI Pathway Option”).
This comparison is useful for understanding:
# Filter relevant measure
df_filtered <- df %>%
filter(Measure == "Number of students overall on the course unit")
# Summarise by Course Type
course_type_summary <- df_filtered %>%
group_by(`Course Type`) %>%
summarise(`Total Enrolment` = sum(Value, na.rm = TRUE), .groups = "drop") %>%
arrange(desc(`Total Enrolment`))
# Plot
ggplot(course_type_summary, aes(x = reorder(`Course Type`, `Total Enrolment`),
y = `Total Enrolment`)) +
geom_col(fill = "darkgreen", colour = "black") +
geom_text(aes(label = `Total Enrolment`), vjust = -0.3, size = 3) +
labs(title = "Uptake of Core vs Pathway Option Units",
x = "Course Type", y = "No. of Students Enrolled") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 30, hjust = 1))
What the Chart Shows
The chart indicates that some pathway options (like those in Politics) attract significantly more students than core optional units. For example, Politics Pathway Option enrolments exceed 4,000, while Core Optional for Poli Pathway is notably lower. This suggests that BASS students may be exercising greater choice in their third year, favouring optional modules over core recommendations.
This bubble chart shows the number of students from each discipline enrolled in the top 15 most enrolled course units. Hover to see exact student numbers for each discipline-unit pair. The chart uses only unit codes for compactness and a reference table is provided below.
# Create UnitLabel and get top 15 by total enrolment
df_top_units <- df %>%
filter(Measure == "Number of students overall on the course unit") %>%
mutate(UnitCode = `Unit Code`,
UnitName = `Unit Name`,
UnitLabel = paste(`Unit Code`, "—", `Unit Name`)) %>%
group_by(UnitCode, UnitName) %>%
summarise(Total = sum(Value), .groups = "drop") %>%
top_n(15, Total)
# Get labels
top_codes <- df_top_units$UnitCode
# Prepare data for bubble chart
df_bubble <- df %>%
filter(Measure == "Number of students overall on the course unit") %>%
filter(`Unit Code` %in% top_codes) %>%
group_by(UnitCode = `Unit Code`, Discipline) %>%
summarise(Enrolment = sum(Value), .groups = "drop")
# Plotly bubble chart
plot_ly(df_bubble,
x = ~Discipline,
y = ~UnitCode,
type = 'scatter',
mode = 'markers',
size = ~Enrolment,
sizes = c(10, 80),
marker = list(
opacity = 0.7,
color = 'steelblue',
line = list(width = 1, color = 'black')
),
text = ~paste("Unit:", UnitCode,
"<br>Students:", Enrolment),
hoverinfo = 'text') %>%
layout(title = "Discipline Enrolment in Top 15 Year 3 Units",
xaxis = list(title = "Discipline"),
yaxis = list(title = "Course Unit Code"),
showlegend = FALSE)
Course Unit Name
# Table of top unit codes with full names
datatable(df_top_units,
colnames = c("Unit Code", "Unit Name", "Total Enrolment"),
options = list(pageLength = 10, scrollX = TRUE),
rownames = FALSE)
The chart above displays the top 15 Year 3 course units by total enrolment, highlighting their associated discipline and relative popularity. Each bubble represents a course unit, positioned by discipline on the x-axis and identified by unit code on the y-axis. The size of the bubble corresponds to the number of students enrolled in that unit.
Key observations:
POLI30300
) to more niche options with moderate but
meaningful uptake.This type of visualisation is useful for identifying:
It can also support programme planning/restructuring, by tracking shifts in student preferences over time.
The table below lists the top 3 and bottom 3 Year 3 course units by total enrolment within each discipline. This allows us to identify the most and least popular units in each area of the programme.
Such insight helps identify:
This comparison supports both quality assurance and student choice alignment with the programme’s learning goals.
## Top and Bottom 3 Unique Units per Discipline (Coloured Rows)
# Ensure numeric
y3$Value <- suppressWarnings(as.numeric(y3$Value))
# Summarise total enrolment by unique unit
unit_totals <- y3 %>%
filter(Measure == "Number of students overall on the course unit", !is.na(Value)) %>%
group_by(`Unit Code`, `Unit Name`, Discipline) %>%
summarise(Total = sum(Value), .groups = "drop")
# Top and bottom 3 per discipline, no duplicates
top_bottom_units <- unit_totals %>%
group_by(Discipline) %>%
mutate(
rank_top = row_number(desc(Total)),
rank_bottom = row_number(Total)
) %>%
filter(rank_top <= 3 | rank_bottom <= 3) %>%
mutate(
Position = case_when(
rank_top <= 3 & rank_bottom > 3 ~ "Top 3",
rank_bottom <= 3 & rank_top > 3 ~ "Bottom 3",
TRUE ~ NA_character_
)
) %>%
filter(!is.na(Position)) %>%
ungroup() %>%
arrange(Discipline, desc(Position), desc(Total)) %>%
select(Position, Discipline, `Unit Code`, `Unit Name`, Total)
# Add row styling
top_bottom_units %>%
kable("html", caption = "Top and Bottom 3 Unique Course Units by Enrolment (Coloured Rows)") %>%
kable_styling(full_width = FALSE) %>%
row_spec(which(top_bottom_units$Position == "Top 3"), background = "#d1f5d3") %>% # light green
row_spec(which(top_bottom_units$Position == "Bottom 3"), background = "#fddddd") # light red
Position | Discipline | Unit Code | Unit Name | Total |
---|---|---|---|---|
Top 3 | Anthropology | SOAN30251 | Anthropology of Health and Wellbeing | 326 |
Top 3 | Anthropology | SOAN30610 | Dissertation B | 270 |
Top 3 | Anthropology | SOAN30811 | Anthropology of Vision, Memory, and the Senses | 238 |
Bottom 3 | Anthropology | SOAN30452 | Anthropology of Displacement and Migration | 76 |
Bottom 3 | Anthropology | SOAN30382 | Ethnographies and Adventures in Manchester | 61 |
Bottom 3 | Anthropology | SOAN30600 | Dissertation A | 12 |
Top 3 | Criminology | CRIM30601 | Drugs and Society | 718 |
Top 3 | Criminology | CRIM30610 | Dissertation B | 718 |
Top 3 | Criminology | CRIM31101 | Youth, Crime and Justice | 395 |
Bottom 3 | Criminology | CRIM31051 | Criminology and Mass Violence | 60 |
Bottom 3 | Criminology | CRIM31152 | Crime Mapping: Intro to GIS and Spatial Analysis | 24 |
Bottom 3 | Criminology | CRIM30641 | Comparative Criminology | 19 |
Top 3 | Data Analytics | SOST30012 | Theory and Method in Demography | 959 |
Top 3 | Data Analytics | SOST30062 | Data Science Modelling | 238 |
Bottom 3 | Data Analytics | SOST30031 | Answering Social Research questions with Statistical Models | 129 |
Bottom 3 | Data Analytics | SOST30172 | Causal Inference for Policies, Interventions and Experiments | 114 |
Top 3 | Philosophy | PHIL30002 | Dissertation A | 214 |
Top 3 | Philosophy | PHIL30361 | Philosophy of Psychology | 212 |
Top 3 | Philosophy | PHIL30552 | Philosophy of Action | 179 |
Bottom 3 | Philosophy | PHIL30351 | Founding Mothers: Women Philosophers and their Role in the Development of Analytic Philosophy | 32 |
Bottom 3 | Philosophy | PHIL30442 | Special Author: Kant | 28 |
Bottom 3 | Philosophy | PHIL30252 | Special Author: Wittgenstein | 19 |
Top 3 | Politics | POLI30300 | Dissertation A | 1247 |
Top 3 | Politics | POLI31061 | American Politics: Why do they do that? | 509 |
Top 3 | Politics | POLI30380 | Dissertation B | 455 |
Bottom 3 | Politics | POLI31021 | Intimate Geopolitics of China | 20 |
Bottom 3 | Politics | POLI32221 | Feminist Policymaking in Global Politics | 14 |
Bottom 3 | Politics | POLI31081 | Knowledge Production and Peacebuilding | 9 |
Top 3 | Sociology | SOCY30930 | Dissertation B | 485 |
Top 3 | Sociology | SOCY30920 | Dissertation A | 303 |
Top 3 | Sociology | SOCY30171 | Identity Power, Modernity | 234 |
Bottom 3 | Sociology | SOCY30292 | Connections Matter: Sociological Applications of Social Networks | 110 |
Bottom 3 | Sociology | SOCY30352 | Security and Global Pandemics | 92 |
Bottom 3 | Sociology | SOCY30731 | Art and Society | 81 |
The chart above illustrates how Year 3 student enrolments are distributed across different course types within each discipline. Each bar represents a discipline, stacked by the total number of students enrolled in various course categories such as Core, Pathway Options, and Core Optionals tied to specific pathways.
# Ensure Value is numeric
y3$Value <- suppressWarnings(as.numeric(y3$Value))
# Filter to total enrolment per unit
course_type_summary <- y3 %>%
filter(Measure == "Number of students overall on the course unit", !is.na(Value)) %>%
group_by(Discipline, `Course Type`) %>%
summarise(Total = sum(Value), .groups = 'drop')
# Plot stacked bars
ggplot(course_type_summary, aes(x = Discipline, y = Total, fill = `Course Type`)) +
geom_bar(stat = "identity", position = "stack", colour = "black") +
labs(
title = "Enrolment by Course Type and Discipline (Year 3)",
x = "Discipline",
y = "Total Students",
fill = "Course Type"
) +
theme_minimal(base_size = 13) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(face = "bold", hjust = 0.5),
axis.title = element_text(face = "bold")
)
Key observations:
This breakdown helps:
This Year 3 enrolment report has provided a detailed exploration of student registrations across disciplines, course types, and academic years. It explores:
You can explore enrolment patterns by discipline or course unit using
shiny app, i.e. the interactive dashboard:
https://sisteranalyst.shinyapps.io/year3/
These findings can inform programme redesign and pedagogical strategies aimed at optimising student experience and sustaining healthy enrolment patterns.