This report analyses enrolment trends across the BA Social Sciences (BASS) programmes at the University of Manchester from 2019/20 to 2024/25. It explores patterns by programme, academic year, and year of study, identifying areas of growth, stability, and decline.
data <- read_csv("BASS_Pr_Enrolment_PE&IS.csv")
# Clean and classify programmes
data <- data %>%
mutate(
programme_clean = tolower(programme),
category = case_when(
grepl("with is", programme_clean, fixed = TRUE) ~ "International Study",
grepl("with pe", programme_clean, fixed = TRUE) ~ "Professional Experience",
TRUE ~ "Standard"
),
programme_base = str_remove(programme, " with IS| with PE"),
programme_short = str_remove(programme_base, "BA \\(Hons\\) Social Sciences \\(|\\)$")
)
data %>%
select(-programme_clean, -programme_base, -programme_short) %>%
head(5) %>%
kable(caption = "Preview of Enrolment Data (Main Columns Only)") %>%
kable_styling(full_width = FALSE)
no | programme | academic_year | year_study | no_students | category |
---|---|---|---|---|---|
1 | BA (Hons) Social Anthropology and Quantitative Methods | 2019/20 | 1 | 0 | Standard |
1 | BA (Hons) Social Anthropology and Quantitative Methods | 2019/20 | 2 | 0 | Standard |
1 | BA (Hons) Social Anthropology and Quantitative Methods | 2019/20 | 3 | 0 | Standard |
1 | BA (Hons) Social Anthropology and Quantitative Methods | 2020/21 | 1 | 2 | Standard |
1 | BA (Hons) Social Anthropology and Quantitative Methods | 2020/21 | 2 | 0 | Standard |
What you’re seeing:
This table shows the total number of students enrolled in each BASS
programme across all academic years.
What stands out:
Observations:
The more popular combinations may align better with student interests or
career aspirations?!?!.
programme_summary <- data %>%
group_by(programme) %>%
summarise(total_students = sum(no_students), .groups = "drop") %>%
arrange(desc(total_students))
kable(programme_summary, caption = "Total Enrolment by Programme") %>%
kable_styling()
programme | total_students |
---|---|
BA (Hons) Social Sciences (Politics and Philosophy) | 584 |
BA (Hons) Social Sciences (Sociology & Criminology) | 527 |
BA (Hons) Social Sciences (Politics and Sociology) | 502 |
BA (Hons) Social Sciences (Politics) | 254 |
BA (Hons) Social Sciences (Sociology & Social Anthropology) | 216 |
BA (Hons) Social Sciences (Politics & Criminology) | 176 |
BA (Hons) Social Sciences (Politics & Social Anthropology) | 132 |
BA (Hons) Social Sciences (Sociology and Data Analytics) | 102 |
BA (Hons) Social Sciences (Sociology & Philosophy) | 92 |
BA (Hons) Social Sciences (Sociology) | 79 |
BA (Hons) Social Sciences (Politics and Data Analytics) | 66 |
BA (Hons) Social Sciences (Criminology) | 61 |
BA (Hons) Social Sciences (Philosophy & Criminology) | 54 |
BA (Hons) Social Sciences (Philosophy) | 50 |
BA (Hons) Social Sciences (Social Anthropology & Criminology) | 50 |
BA (Hons) Social Sciences (Social Anthropology & Philosophy) | 48 |
BA (Hons) Social Sciences (Social Anthropology) | 43 |
BA (Hons) Social Sciences (Sociology and Quantitative Methods) | 23 |
BA (Hons) Social Sciences (Politics and Sociology) with PE | 16 |
BA (Hos) Social Sciences (Criminology and Data Analytics) | 16 |
BA (Hons) Social Sciences (Criminology and Quantitative Methods) | 15 |
BA (Hons) Social Science (Social Anthropology and Data Analytics) | 12 |
BA (Hons) Social Sciences (Politics and Data Analytics) with PE | 12 |
BA (Hons) Social Sciences (Politics and Quantitative Methods) | 12 |
BA (Hons) Social Sciences (Politics and Philosophy) with PE | 11 |
BA (Hons) Social Sciences (Politics & Social Anthropology) with PE | 8 |
BA (Hons) Social Sciences (Sociology & Social Anthropology) with PE | 7 |
BA (Hons) Social Sciences (Philosophy and Politics) with IS | 6 |
BA (Hons) Social Sciences (Politics & Sociology) with IS | 6 |
BA (Hons) Social Sciences (Philosophy and Data Analytics) | 5 |
BA (Hons) Social Anthropology and Quantitative Methods | 4 |
BA (Hons) Social Sciences (Criminology and Data Analytics) with PE | 4 |
BA (Hons) Social Sciences (Politics & Criminology) with PE | 4 |
BA (Hons) Social Sciences (Politics) with PE | 4 |
BA (Hons) Social Sciences (Politics & Criminology) with IS | 3 |
BA (Hons) Social Sciences (Politics & Data Analytics) with IS | 3 |
BA (Hons) Social Sciences (Social Anthropology & Philosophy) with PE | 3 |
BA (Hons) Social Sciences (Sociology & Criminology) with PE | 3 |
BA (Hons) Social Sciences (Sociology & Data Analytics) with IS | 3 |
BA (Hons) Social Sciences (Philosophy and Quantitative Methods) | 1 |
What you’re seeing:
This line chart displays the total enrolment numbers across all
programmes for each academic year.
Trends noticed:
Observations:
The BASS programme has shown resilience and strong demand, even during
uncertain times. This growth suggests consistent appeal and possibly
effective outreach and/or curriculum design.
yearly_trend <- data %>%
group_by(academic_year) %>%
summarise(total_students = sum(no_students), .groups = "drop")
min_val <- min(yearly_trend$total_students)
max_val <- max(yearly_trend$total_students)
ggplot(yearly_trend, aes(x = academic_year, y = total_students, group = 1)) +
geom_line(color = "steelblue", linewidth = 1) +
geom_point(color = "black", size = 2) +
geom_text(aes(label = total_students), vjust = -1, size = 4) +
scale_y_continuous(
limits = c(min_val - 10, max_val + 10),
breaks = pretty(c(min_val, max_val), n = 5)
) +
labs(
title = "Yearly Enrolment Trends",
subtitle = "Total Enrolment by Academic Year",
x = "Academic Year",
y = "No. of Students"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", size = 18),
plot.subtitle = element_text(size = 14),
axis.text.x = element_text(angle = 45, hjust = 1)
)
What you’re seeing:
This bar chart breaks down student numbers by year of study (Year 1,
Year 2, etc.).
Patterns noticed:
Observations:
This reflects retention and progression as any significant drop-off
between years could warrant further investigation into student support
or satisfaction.
study_year_summary <- data %>%
group_by(year_study) %>%
summarise(total_students = sum(no_students), .groups = "drop")
ggplot(study_year_summary, aes(x = factor(year_study), y = total_students)) +
geom_bar(stat = "identity", fill = "steelblue") +
geom_text(aes(label = total_students), vjust = -0.5, size = 4, color = "steelblue") +
labs(
title = "Enrolment by Year of Study",
subtitle = "Total number of students across study years",
x = "Year of Study",
y = "No. of Students"
) +
theme_minimal(base_size = 14) +
scale_y_continuous(expand = expansion(mult = c(0, 0.1)))
What you’re seeing:
This chart shows the enrolment trends over time for the top 5 most
popular programmes.
What’s interesting:
Takeaway:
# Summarise by base programme name
programme_summary <- data %>%
group_by(programme_base) %>%
summarise(total_students = sum(no_students), .groups = "drop") %>%
arrange(desc(total_students))
# Top 5 by total across all variants
top_programmes <- programme_summary %>%
top_n(5, total_students) %>%
pull(programme_base)
# Filter and summarise data
filtered_data <- data %>%
filter(programme_base %in% top_programmes) %>%
group_by(programme_base, academic_year) %>%
summarise(no_students = sum(no_students), .groups = "drop") %>%
mutate(
tooltip_text = paste0(
"Programme: ", programme_base, "\n",
"Year: ", academic_year, "\n",
"Students: ", no_students
)
)
# Plot
p <- ggplot(filtered_data, aes(x = academic_year, y = no_students,
color = programme_base, group = programme_base,
text = tooltip_text)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
labs(
title = "Top 5 Combined Programmes Over Time",
subtitle = "Including IS/PE variants grouped into base programmes",
x = "Academic Year",
y = "No. of Students",
color = "Programme"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", size = 18),
plot.subtitle = element_text(size = 14),
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom",
plot.margin = margin(b = 100) # make space for full legend
)
# Convert to Plotly
ggplotly(p, tooltip = "text") %>%
layout(
legend = list(
orientation = "h",
x = 0.5,
xanchor = "center",
y = -0.35,
yanchor = "top"
),
margin = list(b = 120) # ensure space below
)
What you’re seeing:
This interactive line chart shows enrolment trends over time for all
BASS programmes.
Insights available:
Use case:
Helpful for spotting underperforming or consistently strong programmes
across the full landscape.
all_data_summary <- data %>%
group_by(programme, academic_year) %>%
summarise(no_students = sum(no_students), .groups = "drop") %>%
mutate(tooltip_text = paste0(
"Programme: ", programme, "\n",
"Year: ", academic_year, "\n",
"Students: ", no_students
))
p <- ggplot(all_data_summary, aes(x = academic_year, y = no_students, color = programme, group = programme, text = tooltip_text)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
labs(
title = "Programme Enrolment Trends Over Time",
x = "Academic Year",
y = "No. of Students"
) +
theme_minimal(base_size = 13)
ggplotly(p, tooltip = "text") %>%
layout(
legend = list(
orientation = "h",
x = 0.5, xanchor = "center",
y = -0.2, yanchor = "top"
)
)
What you’re seeing:
This chart shows the enrolment trends over time for the top 5 BASS
programmes, where all variants (Standard, with IS, with PE) are combined
under a single programme. The colour represents the programme, and the
shape indicates the year of study.
What stands out:
Actionable insight:
This breakdown helps monitor student progression and retention within
programmes over time. Programmes with irregular patterns may benefit
from reviewing year-to-year transition support, and understanding the
impact of IS/PE pathways on enrolment duration and attrition.
# Prepare the data
filtered_data_detailed <- data %>%
filter(programme_base %in% top_programmes) %>%
mutate(
tooltip_text = paste0(
"Programme: ", programme, "\n",
"Year: ", academic_year, "\n",
"Study Year: ", year_study, "\n",
"Students: ", no_students
)
)
# Create the ggplot object
p <- ggplot(filtered_data_detailed, aes(
x = academic_year,
y = no_students,
group = interaction(programme_base, year_study),
text = tooltip_text
)) +
geom_line(aes(color = programme_base), linewidth = 1) +
geom_point(aes(color = programme_base, shape = factor(year_study)),
size = 2, stroke = 1, fill = "white") +
labs(
title = "Top 5 Programmes Over Time by Year of Study",
subtitle = "Each coloured line is a programme (IS/PE combined); shapes indicate study year",
x = "Academic Year",
y = "No. of Students",
color = "Programme"
) +
theme_minimal(base_size = 13) +
theme(
legend.position = "bottom",
legend.box = "vertical",
plot.margin = margin(b = 100)
) +
guides(shape = "none") # hide shape legend to reduce clutter
# Convert to Plotly
ggplotly(p, tooltip = "text") %>%
layout(
legend = list(
orientation = "h",
x = 0.5,
xanchor = "center",
y = -0.35,
yanchor = "top"
),
margin = list(b = 120)
)
You can also explore an interactive version of this analysis through a Shiny app. This dashboard allows you to:
To launch the app click on the link: https://tanjakeco.shinyapps.io/BASS_Enrolment/
What you’re seeing:
The line chart shows how the proportion of students enrolled in each
type of BASS programme, Standard, International Study (IS), or
Professional Experience (PE) has changed over academic years. This
complements the summary table below, which gives the overall totals and
percentages.
What stands out:
Actionable insight:
Despite being resource-intensive, IS and PE options are not widely
adopted. This may reflect low student interest, awareness, or structural
barriers. These figures provide useful context for discussions around
programme offer viability, promotion, and long-term strategic investment
in these IS/PE routes.
programme_type_summary <- data %>%
group_by(category) %>%
summarise(total_students = sum(no_students), .groups = "drop") %>%
mutate(
percentage = paste0(round(100 * total_students / sum(total_students), 1), "%")
)
datatable(
programme_type_summary,
caption = "Programme Enrolment by Type (with Percentages)",
options = list(pageLength = 5)
)
# Prepare % share per category by academic year
yearly_share <- data %>%
group_by(academic_year, category) %>%
summarise(count = sum(no_students), .groups = "drop") %>%
group_by(academic_year) %>%
mutate(
percentage = 100 * count / sum(count)
)
# Plot
ggplot(yearly_share, aes(x = academic_year, y = percentage, color = category, group = category)) +
geom_line(linewidth = 1) +
geom_point(size = 3) +
geom_text(aes(label = paste0(round(percentage, 1), "%")), vjust = -1, size = 3.5, show.legend = FALSE) +
labs(
title = "Enrolment Share by Programme Type Over Time",
subtitle = "Each line shows the % share of students in IS, PE, or Standard routes per year",
x = "Academic Year",
y = "Percentage of Students",
color = "Programme Type"
) +
scale_y_continuous(labels = scales::percent_format(scale = 1), expand = expansion(mult = c(0, 0.1))) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom"
)
# Create summary table of share per year
# Transpose the summary table so programme types are rows
yearly_share_transposed <- yearly_share %>%
select(academic_year, category, percentage) %>%
pivot_wider(
names_from = academic_year,
values_from = percentage
) %>%
mutate(across(where(is.numeric), ~ round(.x, 1))) # round % values
# Display with kable
kable(
yearly_share_transposed,
caption = "Percentage of Students by Programme Type Across Academic Years"
) %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
category | 2019/20 | 2020/21 | 2021/22 | 2022/23 | 2023/24 | 2024/25 |
---|---|---|---|---|---|---|
International Study | 0.0 | 0.0 | 0.0 | 1.2 | 1.2 | 1.2 |
Professional Experience | 0.5 | 1.5 | 2.3 | 3.3 | 3.1 | 2.2 |
Standard | 99.5 | 98.5 | 97.7 | 95.5 | 95.7 | 96.6 |
What you’re seeing:
This bar chart shows the total number of students enrolled in Standard,
International Study (IS), and Professional Experience (PE) pathways over
each academic year.
What stands out:
Observations:
While Standard pathways dominate overall numbers, the modest rise in IS
and PE participation suggests there is some interest, though not at
scale. This may point to limited student awareness, perceived
complexity, or eligibility barriers.
Actionable insight:
If the institution wishes to grow these “extended pathways”, there may
be value in reviewing how they are positioned, supported, and
communicated to prospective students.
yearly_participation <- data %>%
group_by(academic_year, category) %>%
summarise(total_students = sum(no_students), .groups = "drop")
ggplot(yearly_participation, aes(x = academic_year, y = total_students, fill = category)) +
geom_col(position = "dodge") +
labs(
title = "IS and PE Enrolment Over Time",
x = "Academic Year",
y = "No. of Students",
fill = "Programme Type"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1)
)
What you’re seeing:
This sortable table lists all BASS programmes that include either
International Study (IS) or Professional Experience (PE), showing the
total number of students enrolled in each.
How to use it:
You can click on column headers (e.g., total_students or percentage) to
sort and explore which specific IS or PE routes have the highest or
lowest uptake.
About the percentage column:
The percentage represents the proportion of students enrolled in each
specific IS/PE programme relative to the total number of students in
that category.
For example, if there are 21 students across all IS programmes, and 6
are on one specific route, that route accounts for 28.6% of IS
enrolments.
What stands out:
Actionable insight:
These figures can help identify which IS/PE routes are performing better
and where targeted support or review might be needed. This is useful for
refining the programme offer or better supporting under-represented
options.
programme_breakdown <- data %>%
group_by(category, programme) %>%
summarise(total_students = sum(no_students), .groups = "drop") %>%
group_by(category) %>%
mutate(
percentage = round(100 * total_students / sum(total_students), 1)
)
datatable(
programme_breakdown,
caption = "Programme Enrolment by Type (with Percentages)",
options = list(pageLength = 10)
)
What you’re seeing:
This bar chart compares the number of students across each year of study
(1–4) by programme type: Standard, International Study (IS), and
Professional Experience (PE).
What stands out:
Observations:
Actionable insight:
This breakdown helps confirm that PE and IS routes are being used as
intended structurally, but their small numbers highlight an opportunity
to revisit how these IS/PE routes are presented or supported across
years.
# Aggregate by year and category
study_year_dist <- data %>%
group_by(year_study, category) %>%
summarise(total_students = sum(no_students), .groups = "drop")
# Plot with labels
ggplot(study_year_dist, aes(x = factor(year_study), y = total_students, fill = category)) +
geom_col(position = position_dodge(width = 0.8)) +
geom_text(
aes(label = total_students),
position = position_dodge(width = 0.8),
vjust = -0.5,
size = 3.5
) +
labs(
title = "Year of Study Distribution by Programme Type",
x = "Year of Study",
y = "No. of Students",
fill = "Category"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold"),
legend.position = "right"
) +
scale_y_continuous(expand = expansion(mult = c(0, 0.1)))