ui <- fluidPage(
title="Football league competitiveness and countries European performance",lang="en",
theme="css.css",
useShinyjs(),
tags$head(
tags$script(HTML("
Shiny.addCustomMessageHandler('bindModalHidden', function(message) {
$('#shiny-modal').off('hidden.bs.modal.modalListener');
$('#shiny-modal').on('hidden.bs.modal.modalListener', function () {
Shiny.setInputValue('modal_closed_nonce', Math.random(), {priority: 'event'});
});
});
"),
"function sendWidth() {
Shiny.setInputValue('screen_width', window.innerWidth);
}
$(document).on('shiny:connected', sendWidth);
$(window).on('resize', sendWidth);"),
tags$style(
# the create_scrolly_side will return a list, the first object is the CSS classes that create the stick position scrolling behaviour.
# the second object is the javascript that links the scrolling to change CSS classes and update shiny inputs (loaded at end of page)
HTML(as.character(create_scrolly_side("time_plot")[1])),
HTML(as.character(create_scrolly_side("league_averages_plot")[1])),
HTML(as.character(create_scrolly_side("basic_profiling_plot")[1])),
HTML(as.character(create_scrolly_side("regression_current_year_plot")[1])),
HTML(as.character(create_scrolly_side("regression_next_year_plot")[1])),
HTML(as.character(create_scrolly_side("regression_competition_plot")[1])),
HTML(as.character(create_scrolly_side("clustering_plot")[1]))
),
HTML(
"
"
)
),
#### header ####
div(class = "header",
tags$div(
style = "display: flex; flex-direction: column;",
tags$a(`aria-label` = "Jump back to contents", href = "#contents", class = "jump-link", "Jump back to contents")
)
),
#### title and contents ####
div(id = "contents", class = "toc",
tags$h1(title),
tags$a(href = "https://youtu.be/_mnsaDJzpso?si=3EnfpdRqXp4afBiI", tags$strong("Click here for a link to a static version of the report")),
p(style = 'font-weight: bold; text-align: right; font-size: 1.2em;', "Scroll to begin ▼"),
tags$h3("Table of Contents"),
tags$ul(
tags$li(tags$a(href = "#motivation", tags$strong("Motivation"))),
tags$li(tags$a(href = "#exploratory_analysis", tags$strong("Exploratory analysis"))),
tags$ul(
tags$li(tags$a(href = "#time_plot", "Europe's top 6 leagues European performance since 1999-2000")),
tags$li(tags$a(href = "#variable_selection", "Variables used in analysis of leagues competitiveness")),
tags$li(tags$a(href = "#league_averages_plot", "Characteristics of leagues since 1999-2000")),
tags$li(tags$a(href = "#basic_profiling", "Characteristics of leagues grouped by performance"))
),
tags$li(tags$a(href = "#modelling", tags$strong("Modelling"))),
tags$ul(
tags$li(tags$a(href = "#variable_creation", tags$strong("Variable creation"))),
tags$li(tags$a(href = "#regression", tags$strong("Regression analysis"))),
tags$ul(
tags$li(tags$a(href = "#regression_current_year", "On league characteristics and same season's European performance")),
tags$li(tags$a(href = "#regression_next_year", "On league characteristics and next season's European performance")),
tags$li(tags$a(href = "#regression_competition", "On league characteristics and same season's European performance by competition"))
),
tags$li(tags$a(href = "#clustering", tags$strong("Clustering to group similar seasons together")))
),
tags$li(tags$a(href = "#conclusion", tags$strong("Conclusion")))
)
),
br(),
br(),
#### motivation ####
tags$header(
id = "motivation",
class = "colourheader",
tags$div(
class = "paddeddiv",
style = "position: relative;",
tags$h2(paste0("Motivation"), style = "font-weight: bold; text-align: center;"),
p(style = "margin-top: 5px; white-space: normal;", HTML(motivation_one)),
p(style = "margin-top: 5px;", paste0(motivation_two)),
p(style = "margin-top: 5px;", paste0(motivation_three)),
p(style = "margin-top: 20px;", paste0(date))
)
),
br(),
br(),
div(
class = "bigfixedimage",
style = paste0("background-image: url('psg.jpg');min-height: 100vh;")
),
br(),
br(),
#### Exploratory analysis ####
tags$header(id = "exploratory_analysis", class="colourheader",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Exploratory analysis"), style = "font-weight: bold; text-align: center;"),
p(style = "margin-top: 5px;", paste0(exploratory_analysis_one))
)
),
br(),
br(),
#### European performance over time ####
tags$div(ID = "time_plot",
div(class="scrolly",
tags$figure(class="sticky",style=("order: 0; display: flex; flex-direction: column;"),
tags$h4(style="text-align: center;", "European performance over time, from 1999-2000 to 2025-26"),
plotlyOutput("european_performance_over_time_plot", height = "100%")
),
tags$article(
div(class="time_plot text-article", `data-width`="1",`data-index`="0",
p(strong(" Spanish teams European performance "),
br(),
europe_s_top_6_leagues_european_performance_since_1999_2000_one)),
div(class="time_plot text-article", `data-width`="1",`data-index`="1",
p(strong(" English teams European performance "),
br(),
europe_s_top_6_leagues_european_performance_since_1999_2000_two)),
div(class="time_plot text-article", `data-width`="1",`data-index`="2",
p(strong(" German teams European performance "),
br(),
europe_s_top_6_leagues_european_performance_since_1999_2000_three)),
div(class="time_plot text-article", `data-width`="1",`data-index`="3",
p(strong(" Italian teams European performance "),
br(),
europe_s_top_6_leagues_european_performance_since_1999_2000_four)),
div(class="time_plot text-article", `data-width`="1",`data-index`="4",
p(strong(" French teams European performance "),
br(),
europe_s_top_6_leagues_european_performance_since_1999_2000_five)),
div(class="time_plot text-article", `data-width`="1",`data-index`="5",
p(strong(" Portuguese teams European performance "),
br(),
europe_s_top_6_leagues_european_performance_since_1999_2000_six))
))
),
br(),
br(),
#### Variable selection ####
tags$header(id = "variable_selection", class="colourheader3",
tags$div(
class = "paddeddiv",
style = "position: relative;",
tags$h3(
"Variables used in analysis of leagues competitiveness",
style = "font-weight: bold; text-align: center;"
),
lapply(
c(
variables_used_in_analysis_of_leagues_competitiveness_one,
variables_used_in_analysis_of_leagues_competitiveness_two,
variables_used_in_analysis_of_leagues_competitiveness_three,
variables_used_in_analysis_of_leagues_competitiveness_four,
variables_used_in_analysis_of_leagues_competitiveness_five,
variables_used_in_analysis_of_leagues_competitiveness_six,
variables_used_in_analysis_of_leagues_competitiveness_seven,
variables_used_in_analysis_of_leagues_competitiveness_eight,
variables_used_in_analysis_of_leagues_competitiveness_nine,
variables_used_in_analysis_of_leagues_competitiveness_ten,
variables_used_in_analysis_of_leagues_competitiveness_eleven,
variables_used_in_analysis_of_leagues_competitiveness_twelve,
variables_used_in_analysis_of_leagues_competitiveness_thirteen,
variables_used_in_analysis_of_leagues_competitiveness_fourteen,
variables_used_in_analysis_of_leagues_competitiveness_fifteen,
variables_used_in_analysis_of_leagues_competitiveness_sixteen
),
function(x) p(style = "margin-top: 5px;", HTML(x))
)
)
),
br(),
br(),
#### League average characteristics ####
tags$div(ID = "league_averages_plot",
div(class="scrolly",
tags$figure(class="sticky",style=("order: 0; display: flex; flex-direction: column;"),
tags$h4(style="text-align: center;", "Average characteristics of leagues, from 1999-2000 to 2025-26"),
plotlyOutput("league_characteristics_plot", height = "100%")
),
tags$article(
div(class="league_averages_plot text-article", `data-width`="1",`data-index`="0",
p(strong(" Spanish teams European performance "),
br(),
characteristics_of_leagues_since_1999_2000_one)),
div(class="league_averages_plot text-article", `data-width`="1",`data-index`="1",
p(strong(" English teams European performance "),
br(),
characteristics_of_leagues_since_1999_2000_two)),
div(class="league_averages_plot text-article", `data-width`="1",`data-index`="2",
p(strong(" German teams European performance "),
br(),
characteristics_of_leagues_since_1999_2000_three)),
div(class="league_averages_plot text-article", `data-width`="1",`data-index`="3",
p(strong(" Italian teams European performance "),
br(),
characteristics_of_leagues_since_1999_2000_four)),
div(class="league_averages_plot text-article", `data-width`="1",`data-index`="4",
p(strong(" French teams European performance "),
br(),
characteristics_of_leagues_since_1999_2000_five)),
div(class="league_averages_plot text-article", `data-width`="1",`data-index`="5",
p(strong(" Portuguese teams European performance "),
br(),
characteristics_of_leagues_since_1999_2000_six))
))
),
br(),
br(),
tags$header(class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
p(style="margin-top: 5px;",paste0(characteristics_of_leagues_extra_one)),
p(style="margin-top: 5px;",paste0(characteristics_of_leagues_extra_two))
)
),
br(),
br(),
#### Basic profiles characteristics ####
tags$header(id = "basic_profiling", class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
p(style="margin-top: 5px;",paste0(characteristics_of_leagues_grouped_by_performance))
)
),
br(),
br(),
tags$div(ID = "basic_profiling_plot",
div(class="scrolly",
tags$figure(class="sticky",style=("order: 0; display: flex; flex-direction: column;"),
tags$h4(style="text-align: center;", "Average characteristics of leagues, grouped by performance"),
plotlyOutput("basic_profiles_characteristic_plot", height = "100%")
),
tags$article(
div(class="basic_profiling_plot text-article", `data-width`="1",`data-index`="0",
p(strong(" Characteristics of worst performing European seasons "),
br(),
characteristics_of_leagues_grouped_by_performance_one)),
div(class="basic_profiling_plot text-article", `data-width`="1",`data-index`="1",
p(strong(" Characteristics of best performing European seasons "),
br(),
characteristics_of_leagues_grouped_by_performance_two)),
div(class="basic_profiling_plot text-article", `data-width`="1",`data-index`="2",
p(strong(" Characteristics of middle performing European seasons "),
br(),
characteristics_of_leagues_grouped_by_performance_three))
))
),
br(),
br(),
div(
class = "bigfixedimage",
style = paste0("background-image: url('aston-villa.jpg');min-height: 100vh;")
),
br(),
br(),
#### Modelling ####
tags$header(id = "modelling", class="colourheader",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Modelling"), style = "font-weight: bold; text-align: center;"),
p(style="margin-top: 5px;",paste0(modelling_one)),
p(style="margin-top: 5px;",paste0(modelling_two))
)
),
br(),
br(),
#### Variable creation ####
tags$header(id = "variable_creation", class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Variable creation"), style = "font-weight: bold; text-align: center;"),
tags$h3(paste0(competitiveness_indices), style = "font-weight: bold;"),
lapply(
c(
competitiveness_indices_one,
competitiveness_indices_two,
competitiveness_indices_three,
competitiveness_indices_four,
competitiveness_indices_five,
competitiveness_indices_six,
competitiveness_indices_seven
),
function(x) p(style = "margin-top: 5px;", HTML(x))
),
br(),
tags$h3(paste0(principal_component_analysis_pca), style = "font-weight: bold;"),
lapply(
c(
principal_component_analysis_pca_one,
the_five_principal_components_can_be_broadly_interpreted_as,
the_five_principal_components_can_be_broadly_interpreted_as_one,
the_five_principal_components_can_be_broadly_interpreted_as_two,
the_five_principal_components_can_be_broadly_interpreted_as_three,
the_five_principal_components_can_be_broadly_interpreted_as_four,
the_five_principal_components_can_be_broadly_interpreted_as_five,
the_five_principal_components_can_be_broadly_interpreted_as_six
),
function(x) p(style = "margin-top: 5px;", HTML(x))
)
)
),
br(),
br(),
#### Regression ####
tags$header(id = "regression", class="colourheader2",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Regression analysis"), style = "font-weight: bold; text-align: center;"),
p(style="margin-top: 5px;",paste0(regression_analysis_one)),
p(style="margin-top: 5px;",paste0(regression_analysis_two)),
tags$button(
class = "btn btn-light mt-3 detail-toggle-btn-black",
type = "button",
"data-toggle-target" = "#regression-moreContent",
"data-show-text" = "Click to view more detailed description of methodology ▼",
"data-hide-text" = "Show less ▲",
"Click to view more detailed description of methodology ▼"
),
tags$div(
id = "regression-moreContent",
class = "collapse mt-3",
p(style = "margin-top: 5px;", paste0(hidden_click_to_view_more_detailed_description_of_methodology_one)),
p(style = "margin-top: 5px;", paste0(hidden_click_to_view_more_detailed_description_of_methodology_two)),
p(style = "margin-top: 5px;", paste0(hidden_click_to_view_more_detailed_description_of_methodology_three))
),
)
),
br(),
br(),
#### Regression in one season ####
tags$header(id = "regression_current_year", class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Regression analysis on league characteristics and same season's European performance"), style = "font-weight: bold; text-align: center;"),
p(style = "margin-top: 5px;", paste0(on_league_characteristics_and_same_season_s_european_performance_one))
)
),
br(),
br(),
tags$div(ID = "regression_current_year_plot",
div(class="scrolly",
tags$figure(class="sticky",style=("order: 0; display: flex; flex-direction: column;"),
tags$h4(style="text-align: center;", "Coefficient estimates for regression"),
plotlyOutput("regression_coefficients_current_plot", height = "100%")
),
tags$article(
div(class="regression_current_year_plot text-article", `data-width`="1",`data-index`="0",
p(strong(" Using all variables (R2 = 0.069) "),
br(),
on_league_characteristics_and_same_season_s_european_performance_two)),
div(class="regression_current_year_plot text-article", `data-width`="1",`data-index`="1",
p(strong(" Using principle components (R2 = 0.049) "),
br(),
on_league_characteristics_and_same_season_s_european_performance_three)),
div(class="regression_current_year_plot text-article", `data-width`="1",`data-index`="2",
p(strong(" Using competitive indices (R2 = 0.040) "),
br(),
on_league_characteristics_and_same_season_s_european_performance_four))
))
),
br(),
br(),
#### Regression in next season ####
tags$header(id = "regression_next_year", class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Regression analysis on league characteristics and next season's European performance"), style = "font-weight: bold; text-align: center;"),
p(style = "margin-top: 5px;", paste0(on_league_characteristics_and_next_season_s_european_performance_one))
)
),
br(),
br(),
tags$div(ID = "regression_next_year_plot",
div(class="scrolly",
tags$figure(class="sticky",style=("order: 0; display: flex; flex-direction: column;"),
tags$h4(style="text-align: center;", "Coefficient estimates for regression"),
plotlyOutput("regression_coefficients_next_plot", height = "100%")
),
tags$article(
div(class="regression_next_year_plot text-article", `data-width`="1",`data-index`="0",
p(strong(" Using all variables (R2 = 0.128) "),
br(),
on_league_characteristics_and_next_season_s_european_performance_two)),
div(class="regression_next_year_plot text-article", `data-width`="1",`data-index`="1",
p(strong(" Using principle components (R2 = 0.112) "),
br(),
on_league_characteristics_and_next_season_s_european_performance_three)),
div(class="regression_next_year_plot text-article", `data-width`="1",`data-index`="2",
p(strong(" Using competitive indices (R2 = 0.090) "),
br(),
on_league_characteristics_and_next_season_s_european_performance_four))
))
),
br(),
br(),
#### Regression by competition ####
tags$header(id = "regression_competition", class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Regression analysis on league characteristics and same season's European performance by competition"), style = "font-weight: bold; text-align: center;"),
p(style = "margin-top: 5px;", paste0(on_league_characteristics_and_same_season_s_european_performance_by_co_one))
)
),
br(),
br(),
tags$div(ID = "regression_competition_plot",
div(class="scrolly",
tags$figure(class="sticky",style=("order: 0; display: flex; flex-direction: column;"),
tags$h4(style="text-align: center;", "Coefficient estimates for regression"),
plotlyOutput("regression_coefficients_competition_plot", height = "100%")
),
tags$article(
div(class="regression_competition_plot text-article", `data-width`="1",`data-index`="0",
p(strong(" Using all variables (R2 = 0.099) "),
br(),
on_league_characteristics_and_same_season_s_european_performance_by_co_two)),
div(class="regression_competition_plot text-article", `data-width`="1",`data-index`="1",
p(strong(" Using principle components (R2 = 0.049) "),
br(),
on_league_characteristics_and_same_season_s_european_performance_by_co_three)),
div(class="regression_competition_plot text-article", `data-width`="1",`data-index`="2",
p(strong(" Using competitive indices (R2 = 0.042) "),
br(),
on_league_characteristics_and_same_season_s_european_performance_by_co_four))
))
),
br(),
br(),
#### Clustering ####
tags$header(id = "clustering", class="colourheader2",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Clustering to group similar seasons together"), style = "font-weight: bold; text-align: center;"),
p(style = "margin-top: 5px;", paste0(clustering_to_group_similar_seasons_together_one)),
p(style = "margin-top: 5px;", paste0(clustering_to_group_similar_seasons_together_two)),
p(style = "margin-top: 5px;", paste0(clustering_to_group_similar_seasons_together_three))
)
),
br(),
br(),
tags$div(ID = "clustering_plot",
div(class="scrolly",
tags$figure(class="sticky",style=("order: 0; display: flex; flex-direction: column;"),
tags$h4(style="text-align: center;", "Average characteristics of clusters"),
plotlyOutput("clustering_characteristics_plot", height = "100%")
),
tags$article(
div(class="clustering_plot text-article", `data-width`="1",`data-index`="0",
p(strong(" Elite competition with wider league separation "),
br(),
radar_plots_for_clusters_one)),
div(class="clustering_plot text-article", `data-width`="1",`data-index`="1",
p(strong(" Elite dominance across the league "),
br(),
radar_plots_for_clusters_two)),
div(class="clustering_plot text-article", `data-width`="1",`data-index`="2",
p(strong(" Most competitive league profile "),
br(),
radar_plots_for_clusters_three))
))
),
br(),
br(),
tags$header(class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
p(style = "margin-top: 5px;", paste0(radar_plots_for_clusters_overall))
)
),
br(),
br(),
div(
class = "bigfixedimage",
style = paste0("background-image: url('cpfc.jpg');min-height: 100vh;")
),
#### Conclusion ####
tags$header(id = "conclusion", class="colourheader",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Conclusion"), style = "font-weight: bold; text-align: center;"),
lapply(
c(
overall_conclusion_one,
overall_conclusion_two,
overall_conclusion_three,
overall_conclusion_four,
overall_conclusion_five,
overall_conclusion_six,
overall_conclusion_seven
),
function(x) {
p(
style = "margin-top: 5px;",
HTML(x)
)
}
)
)
),
br(),
br(),
#### Limitations ####
tags$header(class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Limitations"), style = "font-weight: bold; text-align: center;"),
lapply(
c(
limitations_one,
limitations_two,
limitations_three,
limitations_four,
limitations_five,
limitations_six,
limitations_seven
),
function(x) {
p(
style = "margin-top: 5px;",
HTML(x)
)
}
)
)
),
br(),
br(),
#### Footnote ####
tags$header(class="colourheader3",
tags$div(class="paddeddiv",style="position: relative;",
tags$h2(paste0("Data collection, sources and analysis process"), style = "font-weight: bold; text-align: center;"),
lapply(
c(
data_sources_and_how_data_was_collected_and_analysis_was_done_one,
data_sources_and_how_data_was_collected_and_analysis_was_done_eleven,
data_sources_and_how_data_was_collected_and_analysis_was_done_two,
data_sources_and_how_data_was_collected_and_analysis_was_done_three,
data_sources_and_how_data_was_collected_and_analysis_was_done_four,
data_sources_and_how_data_was_collected_and_analysis_was_done_five,
data_sources_and_how_data_was_collected_and_analysis_was_done_six,
data_sources_and_how_data_was_collected_and_analysis_was_done_seven,
data_sources_and_how_data_was_collected_and_analysis_was_done_eight,
data_sources_and_how_data_was_collected_and_analysis_was_done_nine,
data_sources_and_how_data_was_collected_and_analysis_was_done_ten
),
function(x) {
p(
style = "margin-top: 5px;",
HTML(x)
)
}
)
)
),
br(),
br(),
#### ending section ####
tags$header(class="colourheader",
style="background:#010056 ; color:white;",
tags$div(class="paddeddiv",style="position: relative;",
tags$h1(paste0(title)),
tags$h3(name),
tags$h3(date))
),
#### expandable/collapsable text function ####
tags$script(HTML("
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('[data-toggle-target]').forEach(function(button) {
const targetSelector = button.getAttribute('data-toggle-target');
const target = document.querySelector(targetSelector);
if (!target) return;
const showText = (button.getAttribute('data-show-text') || button.textContent || '').trim();
const hideText = (button.getAttribute('data-hide-text') || 'Show less ▲').trim();
const isVisible = function(el) {
return window.getComputedStyle(el).display !== 'none' && !el.hidden;
};
button.textContent = isVisible(target) ? hideText : showText;
button.addEventListener('click', function() {
if (isVisible(target)) {
target.classList.remove('show');
target.style.display = 'none';
button.textContent = showText;
} else {
target.classList.add('show');
target.style.display = 'block';
button.textContent = hideText;
}
});
});
});
")),
#### scrolly javascript ####
HTML(""),
HTML(""),
HTML(""),
HTML(as.character(create_scrolly_side("time_plot")[2])),
HTML(as.character(create_scrolly_side("league_averages_plot")[2])),
HTML(as.character(create_scrolly_side("basic_profiling_plot")[2])),
HTML(as.character(create_scrolly_side("regression_current_year_plot")[2])),
HTML(as.character(create_scrolly_side("regression_next_year_plot")[2])),
HTML(as.character(create_scrolly_side("regression_competition_plot")[2])),
HTML(as.character(create_scrolly_side("clustering_plot")[2]))
)