--- title: "Vote vs judges: historic upsets (proxy only)" subtitle: "Data with the Stars · An Artometrics project" date: 2026-11-03 format: html: toc: true embed-resources: true theme: cosmo pdf: documentclass: article geometry: margin=1in execute: echo: false warning: false message: false --- > **Note:** judges-only proxy **Finding.** 36 top-half-on-judges eliminations as a vote-tension proxy; no actual vote totals in dataset. ```{r} #| label: setup #| include: false source("R/_setup.R") ``` ## Charts ```{r} #| label: 19_upsets_by_season #| fig-cap: "19_upsets_by_season" #| echo: false # Rebuild chart with ggplot2 from bundled CSVs / story data.csv story_dir <- file.path(root, "public/downloads/stories", "19_vote_vs_judges_upsets") df <- read_csv(file.path(story_dir, "data.csv"), show_col_types = FALSE) # Prefer a pre-defined plot expression file if present; else smart default plot_r <- file.path(root, "reports/qmd/R/plots", "19_upsets_by_season.R") if (file.exists(plot_r)) { source(plot_r, local = TRUE) # expects object `p` } else { # Default: if typical named mean columns, bar them num_cols <- names(df)[sapply(df, is.numeric)] chr_cols <- names(df)[sapply(df, function(z) is.character(z) || is.factor(z))] ycol <- intersect(c("mean","wins","delta","boost","composite","accuracy","n","perfects","share","lift","pro_mean","resid","streak","guest_mean","field_mean","pts"), num_cols) ycol <- if (length(ycol)) ycol[[1]] else num_cols[[1]] xcol <- intersect(c("dance_style","pro","celebrity","judge","bucket","theme_key","hometown_state","checkpoint","label","song","professional","role","era","bin","metric"), chr_cols) xcol <- if (length(xcol)) xcol[[1]] else if (length(chr_cols)) chr_cols[[1]] else NULL if (!is.null(xcol)) { dd <- df if (nrow(dd) > 20) dd <- dd[1:20,] dd[[xcol]] <- as.character(dd[[xcol]]) dd <- dd[!duplicated(dd[[xcol]]), , drop = FALSE] dd[[xcol]] <- factor(dd[[xcol]], levels = rev(unique(dd[[xcol]]))) p <- ggplot(dd, aes(.data[[ycol]], .data[[xcol]], fill = .data[[ycol]])) + geom_col() + scale_fill_gradient(low = "#A8DADC", high = "#6B4CE6") + labs(title = "19_upsets_by_season", x = ycol, y = NULL) + theme_dwts() + theme(legend.position = "none") } else { p <- ggplot(df, aes(.data[[num_cols[[1]]]])) + geom_histogram(bins = 30, fill = "#6B4CE6", color = "white") + labs(title = "19_upsets_by_season") + theme_dwts() } } save_both(p, "19_upsets_by_season") p ``` [PNG](charts/19_upsets_by_season.png){download="19_upsets_by_season.png"} · [SVG](charts/19_upsets_by_season.svg){download="19_upsets_by_season.svg"} ```{r} #| label: 19_upsets_examples #| fig-cap: "19_upsets_examples" #| echo: false # Rebuild chart with ggplot2 from bundled CSVs / story data.csv story_dir <- file.path(root, "public/downloads/stories", "19_vote_vs_judges_upsets") df <- read_csv(file.path(story_dir, "data.csv"), show_col_types = FALSE) # Prefer a pre-defined plot expression file if present; else smart default plot_r <- file.path(root, "reports/qmd/R/plots", "19_upsets_examples.R") if (file.exists(plot_r)) { source(plot_r, local = TRUE) # expects object `p` } else { # Default: if typical named mean columns, bar them num_cols <- names(df)[sapply(df, is.numeric)] chr_cols <- names(df)[sapply(df, function(z) is.character(z) || is.factor(z))] ycol <- intersect(c("mean","wins","delta","boost","composite","accuracy","n","perfects","share","lift","pro_mean","resid","streak","guest_mean","field_mean","pts"), num_cols) ycol <- if (length(ycol)) ycol[[1]] else num_cols[[1]] xcol <- intersect(c("dance_style","pro","celebrity","judge","bucket","theme_key","hometown_state","checkpoint","label","song","professional","role","era","bin","metric"), chr_cols) xcol <- if (length(xcol)) xcol[[1]] else if (length(chr_cols)) chr_cols[[1]] else NULL if (!is.null(xcol)) { dd <- df if (nrow(dd) > 20) dd <- dd[1:20,] dd[[xcol]] <- as.character(dd[[xcol]]) dd <- dd[!duplicated(dd[[xcol]]), , drop = FALSE] dd[[xcol]] <- factor(dd[[xcol]], levels = rev(unique(dd[[xcol]]))) p <- ggplot(dd, aes(.data[[ycol]], .data[[xcol]], fill = .data[[ycol]])) + geom_col() + scale_fill_gradient(low = "#A8DADC", high = "#6B4CE6") + labs(title = "19_upsets_examples", x = ycol, y = NULL) + theme_dwts() + theme(legend.position = "none") } else { p <- ggplot(df, aes(.data[[num_cols[[1]]]])) + geom_histogram(bins = 30, fill = "#6B4CE6", color = "white") + labs(title = "19_upsets_examples") + theme_dwts() } } save_both(p, "19_upsets_examples") p ``` [PNG](charts/19_upsets_examples.png){download="19_upsets_examples.png"} · [SVG](charts/19_upsets_examples.svg){download="19_upsets_examples.svg"} ## Data Analysis CSV: [data.csv](../../public/downloads/stories/19_vote_vs_judges_upsets/data.csv){download="19_vote_vs_judges_upsets-data.csv"} Source tables: `performances.csv`, `scores.csv`, `contestants.csv`, `seasons.csv` under `/downloads/`.