Overview

Row

Total Applicants

156

Approved

143

Countries

31

Female Applicants

53.8%

Young Researchers

51.3%

ITC Countries

75%

Row

Working Group Membership

Applicants by Country (Top 15)

Row

WG Membership per Applicant

Application Status

Gender × Young Researcher

WG Analysis

Row

WG Co-occurrence Heatmap

Country Representation per WG

Row

Gender Balance by WG

Young Researcher Ratio by WG

ITC Representation by WG

Applicant Directory

Row

Full Applicant Database

WG1

Row

WG1 — Medical Imaging Acquisition

WG2

Row

WG2 — Dataset Creation & Annotation

WG3

Row

WG3 — AI Development & Engineering

WG4

Row

WG4 — Clinical Validation

WG5

Row

WG5 — Data Management & Privacy

WG6

Row

WG6 — Dissemination & Communication

WG7

Row

WG7 — Training & Education

About

Row

About this Dashboard

COST Action CA24147 — AID-AgE: Artificial Intelligence Driven Dental Age Estimation Network

This interactive dashboard summarises the Working Group (WG) applications for the AID-AgE COST Action. It provides an at-a-glance view of applicant demographics, geographic distribution, WG membership patterns, and cross-group collaboration potential.

Data source: e-COST WG applications export (12 February 2026, 156 applicants).

Dashboard structure:

  • Overview — Key performance indicators, WG sizes, country distribution, status and demographics.
  • WG Analysis — Co-occurrence heatmap showing cross-WG membership, country breakdown per WG, gender balance, Young Researcher and ITC ratios across all seven groups.
  • Applicant Directory — Searchable, filterable, exportable table of all applicants with their WG memberships and profile attributes.
  • Working Groups (dropdown) — Dedicated filterable tables for each WG (WG1–WG7) with expertise summaries.

Required R packages: flexdashboard, tidyverse, plotly, DT, scales, RColorBrewer, crosstalk.

To publish on RPubs: Click Knit in RStudio, then use PublishRPubs from the preview window.

Dashboard prepared for the AID-AgE Management Committee.

---
title: "COST Action CA24147 — AID-AgE"
subtitle: "Working Group Applications Dashboard"
output:
  flexdashboard::flex_dashboard:
    orientation: rows
    vertical_layout: scroll
    theme:
      version: 4
      bootswatch: lux
    css: !expr NULL
    navbar:
      - { title: "CA24147", href: "https://www.cost.eu/actions/CA24147/", align: right }
    source_code: embed
---

```{css custom-styles}
/* ── Global ── */
body {
  font-family: 'Source Sans Pro', 'Segoe UI', Tahoma, sans-serif;
  background-color: #f8f9fc;
}

.navbar {
  background-color: #0d2137 !important;
  border-bottom: 3px solid #e8a838;
}

.navbar-brand {
  font-weight: 700;
  letter-spacing: 0.5px;
}

/* ── Value Boxes ── */
.value-box {
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}

.value-box .inner {
  padding: 12px 16px;
}

.value-box .value {
  font-size: 32px;
  font-weight: 700;
}

.value-box .caption {
  font-size: 13px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.8px;
}

/* ── Chart containers ── */
.chart-wrapper {
  border-radius: 8px;
  box-shadow: 0 1px 6px rgba(0,0,0,0.06);
  background: white;
  overflow: hidden;
}

.chart-title {
  font-weight: 600;
  font-size: 14px;
  color: #0d2137;
  letter-spacing: 0.3px;
  border-bottom: 2px solid #e8a838;
  padding-bottom: 6px;
}

/* ── Section headers ── */
.section-title {
  color: #0d2137;
  font-weight: 700;
}

/* ── DT table styling ── */
.dataTables_wrapper {
  font-size: 12px;
}

table.dataTable thead th {
  background-color: #0d2137 !important;
  color: white !important;
  font-weight: 600;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

table.dataTable tbody tr:hover {
  background-color: #edf2f9 !important;
}

table.dataTable.stripe tbody tr.odd {
  background-color: #f8f9fc;
}

/* ── Page navigation ── */
.nav-tabs-custom > .nav-tabs > li.active > a {
  border-top-color: #e8a838;
}
```

```{r setup, include=FALSE}
# ── Load libraries ──
library(flexdashboard)
library(tidyverse)
library(plotly)
library(DT)
library(scales)
library(RColorBrewer)
library(crosstalk)

knitr::opts_chunk$set(echo = FALSE, warning = FALSE, message = FALSE)

# ── Colour palette ──
# Deep navy / amber / teal professional palette
pal_main   <- "#0d2137"
pal_accent <- "#e8a838"
pal_teal   <- "#1a8a7d"
pal_coral  <- "#d95f5f"
pal_slate  <- "#5a6f8a"
pal_light  <- "#edf2f9"

# 7 distinct colours for WG1-WG7
pal_wg <- c(
  "WG1" = "#2c6fbb",  # Medical Imaging — blue

"WG2" = "#e8a838",  # Dataset Creation — amber
"WG3" = "#1a8a7d",  # AI Development — teal
"WG4" = "#d95f5f",  # Clinical Validation — coral
"WG5" = "#7b5ea7",  # Data Management — purple
"WG6" = "#e07830",  # Dissemination — orange
"WG7" = "#3a9e5c"   # Training — green
)

# ── Load data ──
# NOTE: Place the CSV in the same directory as this Rmd file, or adjust the path below.
df <- read.csv2("WG_applications_export_12-02-2026.csv",
                fileEncoding = "UTF-8-BOM",
                stringsAsFactors = FALSE,
                sep = ";",
                quote = '"')

# ── Clean column names ──
wg_cols <- grep("^WG", names(df), value = TRUE)

wg_labels <- c(
  "WG1" = "Medical Imaging Acquisition",
  "WG2" = "Dataset Creation & Annotation",
  "WG3" = "AI Development & Engineering",
  "WG4" = "Clinical Validation",
  "WG5" = "Data Management & Privacy",
  "WG6" = "Dissemination & Communication",
  "WG7" = "Training & Education"
)

# Short names for each WG column
wg_short <- paste0("WG", 1:7)
names(wg_cols) <- wg_short

# Convert y/n to logical
for (col in wg_cols) {
  df[[col]] <- tolower(trimws(df[[col]])) == "y"
}

# Clean country field (remove quotes)
df$country <- gsub('"', '', df$country)

# Extract ISO code from country string, e.g. "Türkiye (TR)" → "TR"
df$country_iso <- gsub(".*\\(([A-Z]{2})\\).*", "\\1", df$country)
df$country_name <- gsub("\\s*\\([A-Z]{2}\\)\\s*", "", df$country)

# Number of WGs per applicant
df$n_wgs <- rowSums(df[, wg_cols])

# Clean affiliation
df$affiliation <- gsub('^"|"$', '', df$affiliation)
```

# Overview {data-icon="fa-chart-bar"}

## Row {data-height=120}

### Total Applicants {.value-box}

```{r}
valueBox(nrow(df), icon = "fa-users", color = pal_main)
```

### Approved {.value-box}

```{r}
n_approved <- sum(df$status == "approved")
valueBox(n_approved, icon = "fa-check-circle", color = pal_teal)
```

### Countries {.value-box}

```{r}
valueBox(n_distinct(df$country_iso), icon = "fa-globe", color = pal_accent)
```

### Female Applicants {.value-box}

```{r}
pct_f <- round(100 * mean(df$gender == "Female"), 1)
valueBox(paste0(pct_f, "%"), icon = "fa-venus", color = pal_coral)
```

### Young Researchers {.value-box}

```{r}
pct_yr <- round(100 * mean(tolower(df$youngResearcher) == "y"), 1)
valueBox(paste0(pct_yr, "%"), icon = "fa-graduation-cap", color = pal_slate)
```

### ITC Countries {.value-box}

```{r}
pct_itc <- round(100 * mean(tolower(df$itc) == "y"), 1)
valueBox(paste0(pct_itc, "%"), icon = "fa-flag", color = "#7b5ea7")
```

## Row {data-height=420}

### Working Group Membership

```{r}
# Count members per WG
wg_counts <- tibble(
  wg    = wg_short,
  label = wg_labels[wg_short],
  n     = sapply(wg_cols, function(col) sum(df[[col]]))
)

wg_counts <- wg_counts %>% arrange(desc(n))

p1 <- plot_ly(wg_counts,
              x = ~reorder(wg, n), y = ~n,
              type = "bar",
              marker = list(
                color = pal_wg[wg_counts$wg],
                line = list(color = pal_main, width = 1)
              ),
              text = ~paste0(wg, ": ", label, "<br><b>", n, " applicants</b>"),
              hoverinfo = "text") %>%
  layout(
    xaxis = list(title = "", tickfont = list(size = 12, family = "Source Sans Pro")),
    yaxis = list(title = "Applicants", gridcolor = "#eee"),
    margin = list(b = 40),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p1
```

### Applicants by Country (Top 15)

```{r}
country_counts <- df %>%
  count(country_name, country_iso, sort = TRUE) %>%
  head(15) %>%
  arrange(n)

p2 <- plot_ly(country_counts,
              y = ~reorder(paste0(country_name, " (", country_iso, ")"), n),
              x = ~n,
              type = "bar",
              orientation = "h",
              marker = list(
                color = colorRampPalette(c(pal_light, pal_main))(15),
                line = list(color = pal_main, width = 0.5)
              ),
              text = ~n,
              textposition = "outside",
              hoverinfo = "y+x") %>%
  layout(
    xaxis = list(title = "Applicants", gridcolor = "#eee"),
    yaxis = list(title = "", tickfont = list(size = 11)),
    margin = list(l = 160),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p2
```

## Row {data-height=400}

### WG Membership per Applicant

```{r}
wg_dist <- df %>%
  count(n_wgs) %>%
  mutate(pct = round(100 * n / sum(n), 1))

p3 <- plot_ly(wg_dist,
              x = ~factor(n_wgs), y = ~n,
              type = "bar",
              marker = list(
                color = c(pal_slate, pal_accent, pal_teal, pal_coral,
                          "#7b5ea7", "#e07830", "#3a9e5c")[1:nrow(wg_dist)],
                line = list(color = pal_main, width = 0.8)
              ),
              text = ~paste0(n, " (", pct, "%)"),
              textposition = "outside",
              hoverinfo = "text") %>%
  layout(
    xaxis = list(title = "Number of WGs joined"),
    yaxis = list(title = "Applicants", gridcolor = "#eee"),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p3
```

### Application Status

```{r}
status_df <- df %>%
  count(status) %>%
  mutate(pct = round(100 * n / sum(n), 1))

p4 <- plot_ly(status_df,
              labels = ~status,
              values = ~n,
              type = "pie",
              hole = 0.55,
              textinfo = "label+value+percent",
              textfont = list(size = 13, family = "Source Sans Pro"),
              marker = list(
                colors = c("approved" = pal_teal, "submitted" = pal_accent)[status_df$status],
                line = list(color = "white", width = 2)
              ),
              hoverinfo = "label+value+percent") %>%
  layout(
    showlegend = FALSE,
    annotations = list(
      text = paste0("<b>", nrow(df), "</b><br>Total"),
      showarrow = FALSE, font = list(size = 16, color = pal_main)
    ),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p4
```

### Gender × Young Researcher

```{r}
cross_df <- df %>%
  mutate(YR = ifelse(tolower(youngResearcher) == "y", "Young Researcher", "Established")) %>%
  count(gender, YR)

p5 <- plot_ly(cross_df,
              x = ~gender, y = ~n,
              color = ~YR,
              colors = c("Young Researcher" = pal_accent, "Established" = pal_main),
              type = "bar",
              text = ~n,
              textposition = "inside",
              hoverinfo = "x+text+name") %>%
  layout(
    barmode = "stack",
    xaxis = list(title = ""),
    yaxis = list(title = "Applicants", gridcolor = "#eee"),
    legend = list(orientation = "h", y = -0.15, x = 0.2),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p5
```


# WG Analysis {data-icon="fa-project-diagram"}

## Row {data-height=480}

### WG Co-occurrence Heatmap

```{r fig.height=5}
# Build co-occurrence matrix
co_mat <- matrix(0, nrow = 7, ncol = 7,
                 dimnames = list(wg_short, wg_short))

for (i in 1:7) {
  for (j in 1:7) {
    co_mat[i, j] <- sum(df[[wg_cols[i]]] & df[[wg_cols[j]]])
  }
}

# Off-diagonal only for heatmap (diagonal = WG size)
co_display <- co_mat
diag(co_display) <- NA

# Custom hover text
hover_text <- matrix("", 7, 7)
for (i in 1:7) {
  for (j in 1:7) {
    if (i == j) {
      hover_text[i,j] <- paste0(wg_short[i], " total: ", co_mat[i,j])
    } else {
      hover_text[i,j] <- paste0(wg_short[i], " ∩ ", wg_short[j], ": ", co_mat[i,j], " shared members")
    }
  }
}

p6 <- plot_ly(
  z = co_display,
  x = wg_short, y = wg_short,
  type = "heatmap",
  colorscale = list(c(0, "#edf2f9"), c(0.5, "#5a9bd5"), c(1, "#0d2137")),
  text = hover_text,
  hoverinfo = "text",
  showscale = TRUE,
  colorbar = list(title = "Shared\nMembers", len = 0.6)
) %>%
  layout(
    xaxis = list(title = "", tickfont = list(size = 12)),
    yaxis = list(title = "", tickfont = list(size = 12), autorange = "reversed"),
    margin = list(l = 50, t = 30),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

# Add text annotations
for (i in 1:7) {
  for (j in 1:7) {
    val <- co_mat[i, j]
    p6 <- p6 %>% add_annotations(
      x = wg_short[j], y = wg_short[i],
      text = val,
      showarrow = FALSE,
      font = list(
        size = 11,
        color = ifelse(i == j, pal_accent, ifelse(val > 25, "white", pal_main)),
        family = "Source Sans Pro"
      )
    )
  }
}

p6
```

### Country Representation per WG

```{r fig.height=5}
# Build long-form data: each row = one WG membership for one person
wg_country <- bind_rows(
  lapply(1:7, function(i) {
    df %>%
      filter(!!sym(wg_cols[i])) %>%
      transmute(wg = wg_short[i], country_name, country_iso)
  })
)

# Top 10 countries overall
top10 <- df %>% count(country_name, sort = TRUE) %>% head(10) %>% pull(country_name)

wg_country_top <- wg_country %>%
  filter(country_name %in% top10) %>%
  count(wg, country_name) %>%
  mutate(country_name = factor(country_name, levels = rev(top10)))

p7 <- plot_ly(wg_country_top,
              x = ~n, y = ~country_name,
              color = ~wg,
              colors = pal_wg,
              type = "bar",
              orientation = "h",
              hoverinfo = "x+name+y") %>%
  layout(
    barmode = "stack",
    xaxis = list(title = "Applicants"),
    yaxis = list(title = ""),
    legend = list(orientation = "h", y = -0.12, x = 0, font = list(size = 10)),
    margin = list(l = 140),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p7
```

## Row {data-height=420}

### Gender Balance by WG

```{r}
gender_wg <- bind_rows(
  lapply(1:7, function(i) {
    df %>%
      filter(!!sym(wg_cols[i])) %>%
      transmute(wg = wg_short[i], gender)
  })
) %>%
  count(wg, gender) %>%
  group_by(wg) %>%
  mutate(pct = round(100 * n / sum(n), 1)) %>%
  ungroup()

p8 <- plot_ly(gender_wg,
              x = ~wg, y = ~pct,
              color = ~gender,
              colors = c("Female" = pal_coral, "Male" = pal_main),
              type = "bar",
              text = ~paste0(n, " (", pct, "%)"),
              hoverinfo = "text+name") %>%
  layout(
    barmode = "stack",
    xaxis = list(title = ""),
    yaxis = list(title = "Percentage", range = c(0, 105), gridcolor = "#eee"),
    legend = list(orientation = "h", y = -0.12, x = 0.3),
    shapes = list(
      list(type = "line", x0 = -0.5, x1 = 6.5, y0 = 50, y1 = 50,
           line = list(color = pal_accent, width = 1.5, dash = "dot"))
    ),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p8
```

### Young Researcher Ratio by WG

```{r}
yr_wg <- bind_rows(
  lapply(1:7, function(i) {
    df %>%
      filter(!!sym(wg_cols[i])) %>%
      transmute(
        wg = wg_short[i],
        yr_status = ifelse(tolower(youngResearcher) == "y", "Young Researcher", "Established")
      )
  })
) %>%
  count(wg, yr_status) %>%
  group_by(wg) %>%
  mutate(pct = round(100 * n / sum(n), 1)) %>%
  ungroup()

p9 <- plot_ly(yr_wg,
              x = ~wg, y = ~pct,
              color = ~yr_status,
              colors = c("Young Researcher" = pal_teal, "Established" = pal_slate),
              type = "bar",
              text = ~paste0(n, " (", pct, "%)"),
              hoverinfo = "text+name") %>%
  layout(
    barmode = "stack",
    xaxis = list(title = ""),
    yaxis = list(title = "Percentage", range = c(0, 105), gridcolor = "#eee"),
    legend = list(orientation = "h", y = -0.12, x = 0.2),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p9
```

### ITC Representation by WG

```{r}
itc_wg <- bind_rows(
  lapply(1:7, function(i) {
    df %>%
      filter(!!sym(wg_cols[i])) %>%
      transmute(
        wg = wg_short[i],
        itc_status = ifelse(tolower(itc) == "y", "ITC", "Non-ITC")
      )
  })
) %>%
  count(wg, itc_status) %>%
  group_by(wg) %>%
  mutate(pct = round(100 * n / sum(n), 1)) %>%
  ungroup()

p10 <- plot_ly(itc_wg,
               x = ~wg, y = ~pct,
               color = ~itc_status,
               colors = c("ITC" = "#7b5ea7", "Non-ITC" = "#c4b5d9"),
               type = "bar",
               text = ~paste0(n, " (", pct, "%)"),
               hoverinfo = "text+name") %>%
  layout(
    barmode = "stack",
    xaxis = list(title = ""),
    yaxis = list(title = "Percentage", range = c(0, 105), gridcolor = "#eee"),
    legend = list(orientation = "h", y = -0.12, x = 0.3),
    plot_bgcolor = "white",
    paper_bgcolor = "white"
  ) %>%
  config(displayModeBar = FALSE)

p10
```


# Applicant Directory {data-icon="fa-address-book"}

## Row

### Full Applicant Database {data-height=800}

```{r}
# Build display table
tbl <- df %>%
  mutate(
    Name      = paste(firstName, lastName),
    WGs       = apply(df[, wg_cols], 1, function(x) paste(wg_short[x], collapse = ", ")),
    ITC       = ifelse(tolower(itc) == "y", "Yes", "No"),
    YR        = ifelse(tolower(youngResearcher) == "y", "Yes", "No"),
    Country   = country_name,
    Status    = status
  ) %>%
  select(Name, affiliation, Country, Status, gender, YR, ITC, WGs, n_wgs) %>%
  rename(
    Affiliation    = affiliation,
    Gender         = gender,
    `Young Res.`   = YR,
    `WG Count`     = n_wgs,
    `Working Groups` = WGs
  ) %>%
  arrange(Name)

datatable(
  tbl,
  filter     = "top",
  rownames   = FALSE,
  extensions = c("Buttons", "Scroller"),
  options    = list(
    dom         = "Bfrtip",
    buttons     = c("csv", "excel", "pdf"),
    scrollY     = "520px",
    scroller    = TRUE,
    pageLength  = 156,
    autoWidth   = TRUE,
    columnDefs  = list(
      list(width = "140px", targets = 0),
      list(width = "180px", targets = 1),
      list(width = "80px",  targets = 2),
      list(width = "55px",  targets = c(3, 4, 5, 6, 8)),
      list(width = "130px", targets = 7)
    ),
    language = list(
      search     = "Search applicants:",
      info       = "Showing _START_ to _END_ of _TOTAL_ applicants"
    )
  )
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(
      c("approved", "submitted"),
      c("#e8f5e9", "#fff8e1")
    ),
    fontWeight = "bold"
  ) %>%
  formatStyle("WG Count",
    background = styleColorBar(c(0, 7), pal_teal),
    backgroundSize = "95% 70%",
    backgroundRepeat = "no-repeat",
    backgroundPosition = "center"
  )
```


# WG1 {data-icon="fa-x-ray" data-navmenu="Working Groups"}

## Row

### WG1 — Medical Imaging Acquisition {data-height=600}

```{r}
wg_table <- function(wg_index) {
  col <- wg_cols[wg_index]
  df %>%
    filter(!!sym(col)) %>%
    mutate(
      Name    = paste(firstName, lastName),
      Country = country_name,
      YR      = ifelse(tolower(youngResearcher) == "y", "Yes", "No"),
      ITC     = ifelse(tolower(itc) == "y", "Yes", "No"),
      Status  = status,
      Expertise = substr(scientificExpertise, 1, 120)
    ) %>%
    select(Name, affiliation, Country, Status, gender, YR, ITC, Expertise) %>%
    rename(Affiliation = affiliation, Gender = gender, `Young Res.` = YR) %>%
    arrange(Name)
}

datatable(
  wg_table(1),
  filter   = "top",
  rownames = FALSE,
  options  = list(
    dom        = "frtip",
    pageLength = 60,
    scrollY    = "450px",
    autoWidth  = TRUE
  )
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(c("approved", "submitted"), c("#e8f5e9", "#fff8e1")),
    fontWeight = "bold"
  )
```


# WG2 {data-icon="fa-database" data-navmenu="Working Groups"}

## Row

### WG2 — Dataset Creation & Annotation {data-height=600}

```{r}
datatable(
  wg_table(2), filter = "top", rownames = FALSE,
  options = list(dom = "frtip", pageLength = 70, scrollY = "450px", autoWidth = TRUE)
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(c("approved", "submitted"), c("#e8f5e9", "#fff8e1")),
    fontWeight = "bold"
  )
```


# WG3 {data-icon="fa-microchip" data-navmenu="Working Groups"}

## Row

### WG3 — AI Development & Engineering {data-height=600}

```{r}
datatable(
  wg_table(3), filter = "top", rownames = FALSE,
  options = list(dom = "frtip", pageLength = 75, scrollY = "450px", autoWidth = TRUE)
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(c("approved", "submitted"), c("#e8f5e9", "#fff8e1")),
    fontWeight = "bold"
  )
```


# WG4 {data-icon="fa-stethoscope" data-navmenu="Working Groups"}

## Row

### WG4 — Clinical Validation {data-height=600}

```{r}
datatable(
  wg_table(4), filter = "top", rownames = FALSE,
  options = list(dom = "frtip", pageLength = 60, scrollY = "450px", autoWidth = TRUE)
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(c("approved", "submitted"), c("#e8f5e9", "#fff8e1")),
    fontWeight = "bold"
  )
```


# WG5 {data-icon="fa-shield-alt" data-navmenu="Working Groups"}

## Row

### WG5 — Data Management & Privacy {data-height=600}

```{r}
datatable(
  wg_table(5), filter = "top", rownames = FALSE,
  options = list(dom = "frtip", pageLength = 40, scrollY = "450px", autoWidth = TRUE)
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(c("approved", "submitted"), c("#e8f5e9", "#fff8e1")),
    fontWeight = "bold"
  )
```


# WG6 {data-icon="fa-bullhorn" data-navmenu="Working Groups"}

## Row

### WG6 — Dissemination & Communication {data-height=600}

```{r}
datatable(
  wg_table(6), filter = "top", rownames = FALSE,
  options = list(dom = "frtip", pageLength = 60, scrollY = "450px", autoWidth = TRUE)
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(c("approved", "submitted"), c("#e8f5e9", "#fff8e1")),
    fontWeight = "bold"
  )
```


# WG7 {data-icon="fa-chalkboard-teacher" data-navmenu="Working Groups"}

## Row

### WG7 — Training & Education {data-height=600}

```{r}
datatable(
  wg_table(7), filter = "top", rownames = FALSE,
  options = list(dom = "frtip", pageLength = 80, scrollY = "450px", autoWidth = TRUE)
) %>%
  formatStyle("Status",
    backgroundColor = styleEqual(c("approved", "submitted"), c("#e8f5e9", "#fff8e1")),
    fontWeight = "bold"
  )
```


# About {data-icon="fa-info-circle"}

## Row {data-height=300}

### About this Dashboard

**COST Action CA24147 — AID-AgE: Artificial Intelligence Driven Dental Age Estimation Network**

This interactive dashboard summarises the Working Group (WG) applications for the AID-AgE COST Action. It provides an at-a-glance view of applicant demographics, geographic distribution, WG membership patterns, and cross-group collaboration potential.

**Data source:** e-COST WG applications export (12 February 2026, `r nrow(df)` applicants).

**Dashboard structure:**

- **Overview** — Key performance indicators, WG sizes, country distribution, status and demographics.
- **WG Analysis** — Co-occurrence heatmap showing cross-WG membership, country breakdown per WG, gender balance, Young Researcher and ITC ratios across all seven groups.
- **Applicant Directory** — Searchable, filterable, exportable table of all applicants with their WG memberships and profile attributes.
- **Working Groups** (dropdown) — Dedicated filterable tables for each WG (WG1–WG7) with expertise summaries.

**Required R packages:** `flexdashboard`, `tidyverse`, `plotly`, `DT`, `scales`, `RColorBrewer`, `crosstalk`.

**To publish on RPubs:** Click *Knit* in RStudio, then use *Publish* → *RPubs* from the preview window.

*Dashboard prepared for the AID-AgE Management Committee.*