library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.6
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.1 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.2.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggrepel)
# --- 0. AONF形式の定数定義 ---
AONF_CAPTION <- "Archives from 2026 Onward and Notes for the Future\n2026年以降の記録 | https://ab.cocolog-nifty.com/note/"
# --- 1. データの読み込みと「名寄せ」の強化 ---
# SASの strip() と同様に R でも前後の空白を削除します
df_turnout <- read_csv("turnout72_result.csv") %>%
rename(自治体名 = 区市町村) %>%
mutate(自治体名 = str_trim(自治体名),
turnout_diff = 投票率_計 - 投票率_計_前回)
## Rows: 72 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): 区市町村
## dbl (8): 投票率_男_前回, 投票率_女_前回, 投票率_計_前回, 投票率_男, 投票率_女, 投票率_計, 男_増減, 女_増減...
## num (4): 有権者_男, 有権者_女, 投票数_男, 投票数_女
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_2024 <- read_csv("福岡2024比例_72自治体.csv") %>%
rename(自治体名 = city_town) %>%
mutate(自治体名 = str_trim(自治体名),
total_2024 = rowSums(select(., starts_with("得票数")), na.rm = TRUE),
ldp_share_2024 = (得票数7 / total_2024) * 100)
## Rows: 72 Columns: 10
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): city_town
## dbl (9): 得票数1, 得票数2, 得票数3, 得票数4, 得票数5, 得票数6, 得票数7, 得票数8, 得票数9...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_2026 <- read_csv("d_final_72_result.csv") %>%
mutate(自治体名 = str_trim(自治体名),
total_2026 = rowSums(select(., where(is.numeric)), na.rm = TRUE),
ldp_share_2026 = (自由民主党 / total_2026) * 100)
## Rows: 72 Columns: 12
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): 自治体名
## dbl (11): れいわ新選組, 日本保守党, 自由民主党, 中道改革連合, 減税日本_ゆうこく, チームみらい, 社会民主党, 日本維新の会, 参政...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# --- 2. データの結合 ---
df_combined <- df_turnout %>%
inner_join(df_2024, by = "自治体名") %>%
inner_join(df_2026, by = "自治体名") %>%
mutate(ldp_share_diff = ldp_share_2026 - ldp_share_2024)
# --- 【デバッグ】結合後の状態を確認 ---
cat("結合後の行数:", nrow(df_combined), "\n")
## 結合後の行数: 72
if (nrow(df_combined) == 0) {
stop("エラー:データが結合できていません。自治体名の表記(全角/半角、スペースなど)を確認してください。")
}
# --- 3. 相関係数の算出(NAをより柔軟に扱う) ---
# use = "pairwise.complete.obs" を使うことで、有効なペアを最大限利用します
cor_value <- cor(df_combined$turnout_diff,
df_combined$ldp_share_diff,
use = "pairwise.complete.obs")
# --- 4. ggplot2による描画(ラベル表示を強化) ---
p <- ggplot(df_combined, aes(x = turnout_diff, y = ldp_share_diff)) +
# 0ライン(基準線)
geom_hline(yintercept = 0, linetype = "dashed", color = "gray60") +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray60") +
# 回帰直線
geom_smooth(method = "lm", color = "firebrick", fill = "firebrick", alpha = 0.1) +
# 散布図(点のサイズを有効投票数に連動)
geom_point(aes(size = total_2026), color = "steelblue", alpha = 0.5) +
# ラベル表示の調整
geom_text_repel(
data = filter(df_combined, abs(ldp_share_diff) > 1.5 | abs(turnout_diff) > 2.5),
aes(label = 自治体名),
family = "HiraKakuProN-W3",
size = 2.5,
segment.color = "gray70", # 引き出し線の色
segment.size = 0.3,
max.overlaps = Inf, # 重なりを無視してすべて表示
box.padding = 0.5 # ラベル周りの余白を広げて見やすく
) +
labs(
title = "投票率の変化と自民党得票率の変化における相関",
subtitle = paste0("福岡県内72自治体比較(2024年 vs 2026年) 相関係数: ", round(cor_value, 3)),
x = "投票率の変化 (pt) [前回比]",
y = "自民党得票率の変化 (pt) [前回比]",
size = "2026年 有効投票総数",
caption = AONF_CAPTION
) +
theme_minimal(base_family = "HiraKakuProN-W3") +
theme(
legend.position = "bottom",
plot.caption = element_text(size = 8, hjust = 1, color = "gray30"),
plot.title = element_text(face = "bold", size = 14),
panel.grid.minor = element_blank()
)
print(p)
## `geom_smooth()` using formula = 'y ~ x'

library(tidyverse)
library(ggrepel)
# --- 0. AONF形式の定数定義 ---
AONF_CAPTION <- "Archives from 2026 Onward and Notes for the Future\n2026年以降の記録 | https://ab.cocolog-nifty.com/note/"
# --- 1. データの読み込みと結合 ---
df_turnout <- read_csv("turnout72_result.csv") %>%
rename(自治体名 = 区市町村) %>%
mutate(自治体名 = str_trim(自治体名),
turnout_diff = 投票率_計 - 投票率_計_前回)
## Rows: 72 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): 区市町村
## dbl (8): 投票率_男_前回, 投票率_女_前回, 投票率_計_前回, 投票率_男, 投票率_女, 投票率_計, 男_増減, 女_増減...
## num (4): 有権者_男, 有権者_女, 投票数_男, 投票数_女
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_mod_change <- read_csv("中道改革連合変化分析.csv") %>%
mutate(自治体名 = str_trim(自治体名))
## Rows: 72 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): 自治体名
## dbl (3): mod_share_2024, mod_share_2026, mod_diff
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# 2026年の有効投票総数をバブルサイズ用に追加
df_2026_votes <- read_csv("d_final_72_result.csv") %>%
mutate(自治体名 = str_trim(自治体名),
total_2026 = rowSums(select(., where(is.numeric)), na.rm = TRUE))
## Rows: 72 Columns: 12
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): 自治体名
## dbl (11): れいわ新選組, 日本保守党, 自由民主党, 中道改革連合, 減税日本_ゆうこく, チームみらい, 社会民主党, 日本維新の会, 参政...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_plot <- df_mod_change %>%
inner_join(df_turnout, by = "自治体名") %>%
inner_join(df_2026_votes, by = "自治体名")
# 相関係数
cor_val <- cor(df_plot$turnout_diff, df_plot$mod_diff, use = "pairwise.complete.obs")
# --- 2. 描画 ---
p <- ggplot(df_plot, aes(x = turnout_diff, y = mod_diff)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray60") +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray60") +
geom_smooth(method = "lm", color = "darkgreen", fill = "darkgreen", alpha = 0.1) +
geom_point(aes(size = total_2026), color = "seagreen", alpha = 0.5) +
geom_text_repel(
data = filter(df_plot, abs(mod_diff) > 2 | abs(turnout_diff) > 3),
aes(label = 自治体名),
family = "HiraKakuProN-W3", size = 3, max.overlaps = Inf
) +
labs(
title = "投票率の変化と中道改革連合得票率の変化における相関",
subtitle = paste0("福岡県内72自治体比較(2024年 vs 2026年) 相関係数: ", round(cor_val, 3)),
x = "投票率の変化 (pt) [前回比]",
y = "中道改革連合得票率の変化 (pt) [24年立憲+公明比]",
size = "2026年 有効投票総数",
caption = AONF_CAPTION
) +
theme_minimal(base_family = "HiraKakuProN-W3") +
theme(
legend.position = "bottom",
plot.caption = element_text(size = 8, hjust = 1, color = "gray30"),
plot.title = element_text(face = "bold", size = 14)
)
print(p)
## `geom_smooth()` using formula = 'y ~ x'
