R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

summary(cars)
##      speed           dist       
##  Min.   : 4.0   Min.   :  2.00  
##  1st Qu.:12.0   1st Qu.: 26.00  
##  Median :15.0   Median : 36.00  
##  Mean   :15.4   Mean   : 42.98  
##  3rd Qu.:19.0   3rd Qu.: 56.00  
##  Max.   :25.0   Max.   :120.00

Including Plots

You can also embed plots, for example:

Note that the echo = FALSE parameter was added to the code chunk to prevent printing of the R code that generated the plot.

library(readxl)
## Warning: package 'readxl' was built under R version 4.5.2
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.2
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.2
# 讀取桌面 wh 資料夾中的 Excel
vote <- read_excel(
  "~/Desktop/wh/idelpointall.xlsx",
  sheet = "1946-2024"
)

# 篩選 Vietnam、China、United States,2000–2024
vietnam_plot <- vote %>%
  filter(
    countryname %in% c("Vietnam", "China", "United States"),
    year >= 2000,
    year <= 2024
  )

# 畫折線圖
ggplot(
  vietnam_plot,
  aes(
    x = year,
    y = idealpointall,
    color = countryname,
    group = countryname
  )
) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 1.8) +

  # 2022 年分界線
  geom_vline(
    xintercept = 2022,
    linetype = "dashed",
    linewidth = 0.7,
    color = "grey40"
  ) +

  # X 軸每兩年顯示一次
  scale_x_continuous(
    breaks = seq(2000, 2024, by = 2)
  ) +

  # 三國顏色
  scale_color_manual(
    values = c(
      "Vietnam" = "#E69F00",
      "China" = "#D55E00",
      "United States" = "#0072B2"
    )
  ) +

  labs(
    title = "Vietnam's UNGA Voting Position Relative to China and the United States",
    subtitle = "2000–2024",
    x = "Year",
    y = "UNGA Ideal Point",
    color = NULL
  ) +

  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).

library(readxl)
library(dplyr)
library(tidyr)
## Warning: package 'tidyr' was built under R version 4.5.2
library(ggplot2)

# 1. 讀取資料
vote <- read_excel(
  "~/Desktop/wh/idelpointall.xlsx",
  sheet = "1946-2024"
)

# 2. ASEAN-8
asean8 <- c(
  "Philippines",
  "Vietnam",
  "Singapore",
  "Malaysia",
  "Indonesia",
  "Thailand",
  "Cambodia",
  "Laos"
)

# 3. ASEAN 資料
asean_data <- vote %>%
  filter(
    countryname %in% asean8,
    year >= 2000,
    year <= 2024
  ) %>%
  select(countryname, year, idealpointall) %>%
  rename(
    ASEAN_country = countryname,
    ASEAN_value = idealpointall
  )

# 4. 中國資料
china_data <- vote %>%
  filter(
    countryname == "China",
    year >= 2000,
    year <= 2024
  ) %>%
  select(year, idealpointall) %>%
  rename(
    China = idealpointall
  )

# 5. 美國資料
us_data <- vote %>%
  filter(
    countryname == "United States",
    year >= 2000,
    year <= 2024
  ) %>%
  select(year, idealpointall) %>%
  rename(
    United_States = idealpointall
  )

# 6. 合併
plot_data <- asean_data %>%
  left_join(china_data, by = "year") %>%
  left_join(us_data, by = "year")

# 7. 轉成 long format
plot_long <- plot_data %>%
  pivot_longer(
    cols = c(ASEAN_value, China, United_States),
    names_to = "Group",
    values_to = "IdealPoint"
  ) %>%
  mutate(
    Group = case_when(
      Group == "ASEAN_value" ~ "ASEAN country",
      Group == "China" ~ "China",
      Group == "United_States" ~ "United States"
    )
  )

# 8. 畫圖
ggplot(
  plot_long,
  aes(
    x = year,
    y = IdealPoint,
    color = Group,
    group = Group
  )
) +
  geom_line(linewidth = 1) +

  geom_vline(
    xintercept = 2022,
    linetype = "dashed",
    color = "grey50",
    linewidth = 0.6
  ) +

  facet_wrap(
    ~ ASEAN_country,
    ncol = 2
  ) +

  scale_color_manual(
    values = c(
      "ASEAN country" = "black",
      "China" = "red3",
      "United States" = "blue3"
    )
  ) +

  scale_x_continuous(
    breaks = seq(2000, 2024, by = 4)
  ) +

  labs(
    title = "ASEAN Voting Positions Relative to China and the United States",
    subtitle = "UNGA Ideal Point, 2000–2024",
    x = "Year",
    y = "UNGA Ideal Point",
    color = NULL
  ) +

  theme_minimal(base_size = 12) +

  theme(
    plot.title = element_text(
      face = "bold",
      size = 16
    ),
    strip.text = element_text(
      face = "bold",
      size = 11
    ),
    legend.position = "bottom",
    axis.text.x = element_text(
      angle = 45,
      hjust = 1
    )
  )
## Warning: Removed 24 rows containing missing values or values outside the scale range
## (`geom_line()`).

distance_data <- plot_data %>%
  mutate(
    Distance_China = abs(ASEAN_value - China),
    Distance_US = abs(ASEAN_value - United_States)
  )
library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)

# 1. 讀取資料
vote <- read_excel(
  "~/Desktop/wh/idelpointall.xlsx",
  sheet = "1946-2024"
)

# 2. ASEAN-8
asean8 <- c(
  "Philippines",
  "Vietnam",
  "Singapore",
  "Malaysia",
  "Indonesia",
  "Thailand",
  "Cambodia",
  "Laos"
)

# 3. ASEAN 資料:2010–2024
asean_data <- vote %>%
  filter(
    countryname %in% asean8,
    year >= 2010,
    year <= 2024
  ) %>%
  select(countryname, year, idealpointall) %>%
  rename(
    ASEAN_country = countryname,
    ASEAN_value = idealpointall
  )

# 4. 中國資料
china_data <- vote %>%
  filter(
    countryname == "China",
    year >= 2010,
    year <= 2024
  ) %>%
  select(year, idealpointall) %>%
  rename(China = idealpointall)

# 5. 美國資料
us_data <- vote %>%
  filter(
    countryname == "United States",
    year >= 2010,
    year <= 2024
  ) %>%
  select(year, idealpointall) %>%
  rename(United_States = idealpointall)

# 6. 合併資料
plot_data <- asean_data %>%
  left_join(china_data, by = "year") %>%
  left_join(us_data, by = "year")

# 7. 計算與中國、美國的距離
distance_data <- plot_data %>%
  mutate(
    Distance_China = abs(ASEAN_value - China),
    Distance_US = abs(ASEAN_value - United_States)
  )

# 8. 轉為 long format
distance_long <- distance_data %>%
  select(
    ASEAN_country,
    year,
    Distance_China,
    Distance_US
  ) %>%
  pivot_longer(
    cols = c(Distance_China, Distance_US),
    names_to = "Reference",
    values_to = "Distance"
  ) %>%
  mutate(
    Reference = case_when(
      Reference == "Distance_China" ~ "Distance from China",
      Reference == "Distance_US" ~ "Distance from United States"
    )
  )

# 9. 畫圖
ggplot(
  distance_long,
  aes(
    x = year,
    y = Distance,
    color = Reference,
    group = Reference
  )
) +
  geom_line(linewidth = 1.1) +
  geom_point(size = 1.5) +

  # 2022 分界
  geom_vline(
    xintercept = 2022,
    linetype = "dashed",
    color = "grey50",
    linewidth = 0.6
  ) +

  facet_wrap(
    ~ ASEAN_country,
    ncol = 2
  ) +

  scale_color_manual(
    values = c(
      "Distance from China" = "red3",
      "Distance from United States" = "blue3"
    )
  ) +

  scale_x_continuous(
    breaks = seq(2010, 2024, by = 2)
  ) +

  labs(
    title = "ASEAN Voting Distance from China and the United States",
    subtitle = "Absolute Distance in UNGA Ideal Point, 2010–2024",
    x = "Year",
    y = "Absolute Ideal Point Distance",
    color = NULL
  ) +

  theme_minimal(base_size = 12) +

  theme(
    plot.title = element_text(
      face = "bold",
      size = 16
    ),
    strip.text = element_text(
      face = "bold",
      size = 11
    ),
    legend.position = "bottom",
    axis.text.x = element_text(
      angle = 45,
      hjust = 1
    )
  )
## Warning: Removed 16 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 16 rows containing missing values or values outside the scale range
## (`geom_point()`).

library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)

# 1. 讀取資料
vote <- read_excel(
  "~/Desktop/wh/idelpointall.xlsx",
  sheet = "1946-2024"
)

# 2. ASEAN-8
asean8 <- c(
  "Philippines",
  "Vietnam",
  "Singapore",
  "Malaysia",
  "Indonesia",
  "Thailand",
  "Cambodia",
  "Laos"
)

# 3. ASEAN 資料
asean_data <- vote %>%
  filter(
    countryname %in% asean8,
    year >= 2010,
    year <= 2024
  ) %>%
  select(countryname, year, idealpointall) %>%
  rename(
    ASEAN_country = countryname,
    ASEAN_value = idealpointall
  )

# 4. 中國資料
china_data <- vote %>%
  filter(
    countryname == "China",
    year >= 2010,
    year <= 2024
  ) %>%
  select(year, idealpointall) %>%
  rename(
    China = idealpointall
  )

# 5. 美國資料
us_data <- vote %>%
  filter(
    countryname == "United States",
    year >= 2010,
    year <= 2024
  ) %>%
  select(year, idealpointall) %>%
  rename(
    United_States = idealpointall
  )

# 6. 合併
plot_data <- asean_data %>%
  left_join(china_data, by = "year") %>%
  left_join(us_data, by = "year")

# 7. 轉成 long format
plot_long <- plot_data %>%
  pivot_longer(
    cols = c(ASEAN_value, China, United_States),
    names_to = "Group",
    values_to = "IdealPoint"
  ) %>%
  mutate(
    Group = case_when(
      Group == "ASEAN_value" ~ "ASEAN country",
      Group == "China" ~ "China",
      Group == "United_States" ~ "United States"
    )
  )

# 8. 畫圖
ggplot(
  plot_long,
  aes(
    x = year,
    y = IdealPoint,
    color = Group,
    group = Group
  )
) +
  geom_line(linewidth = 1) +

  geom_vline(
    xintercept = 2022,
    linetype = "dashed",
    color = "grey50",
    linewidth = 0.6
  ) +

  facet_wrap(
    ~ ASEAN_country,
    ncol = 2
  ) +

  scale_color_manual(
    values = c(
      "ASEAN country" = "black",
      "China" = "red3",
      "United States" = "blue3"
    )
  ) +

  scale_x_continuous(
    breaks = seq(2010, 2024, by = 4)
  ) +

  labs(
    title = "ASEAN Voting Positions Relative to China and the United States",
    subtitle = "UNGA Ideal Point, 2000–2024",
    x = "Year",
    y = "UNGA Ideal Point",
    color = NULL
  ) +

  theme_minimal(base_size = 12) +

  theme(
    plot.title = element_text(
      face = "bold",
      size = 16
    ),
    strip.text = element_text(
      face = "bold",
      size = 11
    ),
    legend.position = "bottom",
    axis.text.x = element_text(
      angle = 45,
      hjust = 1
    )
  )
## Warning: Removed 24 rows containing missing values or values outside the scale range
## (`geom_line()`).

library(readxl)
library(dplyr)
library(tidyr)

# 讀取資料
vote <- read_excel(
  "~/Desktop/wh/idelpointall.xlsx",
  sheet = "1946-2024"
)

# ASEAN-8
asean8 <- c(
  "Philippines",
  "Vietnam",
  "Singapore",
  "Malaysia",
  "Indonesia",
  "Thailand",
  "Cambodia",
  "Laos"
)

# 轉成 wide format
wide_data <- vote %>%
  filter(
    countryname %in% c(asean8, "China", "United States"),
    year >= 2010,
    year <= 2024
  ) %>%
  select(countryname, year, idealpointall) %>%
  pivot_wider(
    names_from = countryname,
    values_from = idealpointall
  )

# 每一個 ASEAN 國家逐年計算
result <- data.frame()

for (country in asean8) {

  temp <- wide_data %>%
    transmute(
      Country = country,
      Year = year,

      # ASEAN ideal point
      ASEAN = .data[[country]],

      China = China,
      US = `United States`,

      # 原始距離
      ASEAN_China_Distance = abs(ASEAN - China),
      ASEAN_US_Distance = abs(ASEAN - US),

      # 美中距離
      US_China_Distance = abs(US - China),

      # 除以美中距離
      Normalized_China =
        ASEAN_China_Distance / US_China_Distance,

      Normalized_US =
        ASEAN_US_Distance / US_China_Distance
    )

  result <- bind_rows(result, temp)
}

# 各國 2010–2023 平均
summary_table <- result %>%
  group_by(Country) %>%
  summarise(
    China_Distance = mean(
      Normalized_China,
      na.rm = TRUE
    ),
    US_Distance = mean(
      Normalized_US,
      na.rm = TRUE
    )
  ) %>%
  mutate(
    China_Distance = round(China_Distance, 3),
    US_Distance = round(US_Distance, 3)
  )

summary_table
## # A tibble: 8 × 3
##   Country     China_Distance US_Distance
##   <chr>                <dbl>       <dbl>
## 1 Cambodia             0.115       0.991
## 2 Indonesia            0.082       1.01 
## 3 Laos                 0.1         1.04 
## 4 Malaysia             0.098       0.937
## 5 Philippines          0.129       0.892
## 6 Singapore            0.142       0.88 
## 7 Thailand             0.139       0.878
## 8 Vietnam              0.096       1.02
library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)

# 1. 讀取資料
vote <- read_excel(
  "~/Desktop/wh/idelpointall.xlsx",
  sheet = "1946-2024"
)

# 2. ASEAN-8
asean8 <- c(
  "Philippines",
  "Vietnam",
  "Singapore",
  "Malaysia",
  "Indonesia",
  "Thailand",
  "Cambodia",
  "Laos"
)

# 3. ASEAN 資料
asean_data <- vote %>%
  filter(
    countryname %in% asean8,
    year >= 2014,
    year <= 2023
  ) %>%
  select(countryname, year, idealpointall) %>%
  rename(
    ASEAN_country = countryname,
    ASEAN_value = idealpointall
  )

# 4. 中國資料
china_data <- vote %>%
  filter(
    countryname == "China",
    year >= 2014,
    year <= 2023
  ) %>%
  select(year, idealpointall) %>%
  rename(
    China = idealpointall
  )

# 5. 美國資料
us_data <- vote %>%
  filter(
    countryname == "United States",
    year >= 2014,
    year <= 2023
  ) %>%
  select(year, idealpointall) %>%
  rename(
    United_States = idealpointall
  )

# 6. 合併
plot_data <- asean_data %>%
  left_join(china_data, by = "year") %>%
  left_join(us_data, by = "year")

# 7. 轉成 long format
plot_long <- plot_data %>%
  pivot_longer(
    cols = c(ASEAN_value, China, United_States),
    names_to = "Group",
    values_to = "IdealPoint"
  ) %>%
  mutate(
    Group = case_when(
      Group == "ASEAN_value" ~ "ASEAN country",
      Group == "China" ~ "China",
      Group == "United_States" ~ "United States"
    )
  )

# 8. 畫圖
ggplot(
  plot_long,
  aes(
    x = year,
    y = IdealPoint,
    color = Group,
    group = Group
  )
) +
  geom_line(linewidth = 1) +

  geom_vline(
    xintercept = 2022,
    linetype = "dashed",
    color = "grey50",
    linewidth = 0.6
  ) +

  facet_wrap(
    ~ ASEAN_country,
    ncol = 2
  ) +

  scale_color_manual(
    values = c(
      "ASEAN country" = "black",
      "China" = "red3",
      "United States" = "blue3"
    )
  ) +

  scale_x_continuous(
    breaks = seq(2014, 2023, by = 4)
  ) +

  labs(
    title = "ASEAN Voting Positions Relative to China and the United States",
    subtitle = "UNGA Ideal Point, 2014–2023",
    x = "Year",
    y = "UNGA Ideal Point",
    color = NULL
  ) +

  theme_minimal(base_size = 12) +

  theme(
    plot.title = element_text(
      face = "bold",
      size = 16
    ),
    strip.text = element_text(
      face = "bold",
      size = 11
    ),
    legend.position = "bottom",
    axis.text.x = element_text(
      angle = 45,
      hjust = 1
    )
  )

library(readxl)
library(dplyr)
library(fixest)
## Warning: package 'fixest' was built under R version 4.5.2
library(modelsummary)
## Warning: package 'modelsummary' was built under R version 4.5.2
# 讀取資料
data <- read_excel(
  "research0927regression.xlsx",
  sheet = "hedging csv"
)

# 先確認實際欄位名稱
names(data)
##  [1] "Country"                 "Year"                   
##  [3] "Political stability"     "FSI(100-FSI)"         
##  [5] "Democracy"               "Post2022"               
##  [7] "SCS"                     "Trade China"            
##  [9] "Sec US"                  "Dis Elite Preference"   
## [11] "Relative Position Index"
# 重新命名
data <- data %>%
  rename(
    Political_Stability = `Political stability`,
    FSI = `FSI(100-FSI)`,
    Trade_China = `Trade China`,
    Sec_US = `Sec US`,
    Elite_Preference = `Dis Elite Preference`,
    Relative_Position = `Relative Position Index`
  )
library(readxl)
library(dplyr)
library(fixest)

data <- read_excel(
  "research0927regression.xlsx",
  sheet = "hedging csv"
)

data <- data %>%
  rename(
    Political_Stability = `Political stability`,
    FSI = `FSI(100-FSI)`,
    Trade_China = `Trade China`,
    Sec_US = `Sec US`,
    Elite_Preference = `Dis Elite Preference`,
    Relative_Position = `Relative Position Index`
  ) %>%
  mutate(
    Elite_Preference = na_if(Elite_Preference, "NA"),
    Elite_Preference = as.numeric(Elite_Preference),
    Relative_Position = as.numeric(Relative_Position),
    Democracy = as.numeric(Democracy),
    Post2022 = as.numeric(Post2022),
    SCS = as.numeric(SCS),
    Political_Stability = as.numeric(Political_Stability),
    FSI = as.numeric(FSI),
    Trade_China = as.numeric(Trade_China),
    Sec_US = as.numeric(Sec_US)
  )

model_elite <- feols(
  Elite_Preference ~
    Democracy +
    Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)
## NOTE: 40 observations removed because of NA values (LHS: 40).
model_relative <- feols(
  Relative_Position ~
    Democracy +
    Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)

summary(model_elite)
## OLS estimation, Dep. Var.: Elite_Preference
## Observations: 40
## Standard-errors: Clustered (Country) 
##                       Estimate Std. Error   t value Pr(>|t|)    
## (Intercept)          90.448053  61.744159  1.464884 0.186370    
## Democracy            -7.266026   2.874404 -2.527838 0.039357 *  
## Post2022             -9.197635   5.980917 -1.537830 0.167977    
## SCS                  17.790264   8.950939  1.987531 0.087208 .  
## Political_Stability  -0.117698   0.687905 -0.171096 0.868989    
## FSI                   0.020637   0.516190  0.039980 0.969226    
## Trade_China         -17.096027  41.901784 -0.408002 0.695463    
## Sec_US              -24.368290  17.577559 -1.386330 0.208196    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 18.5   Adj. R2: 0.245355
summary(model_relative)
## OLS estimation, Dep. Var.: Relative_Position
## Observations: 80
## Standard-errors: Clustered (Country) 
##                      Estimate Std. Error    t value   Pr(>|t|)    
## (Intercept)          0.800144   0.169021   4.733998 2.1226e-03 ** 
## Democracy           -0.044047   0.012741  -3.457077 1.0589e-02 *  
## Post2022            -0.461130   0.045933 -10.039227 2.0849e-05 ***
## SCS                  0.080841   0.034468   2.345377 5.1436e-02 .  
## Political_Stability  0.006965   0.002669   2.609181 3.4955e-02 *  
## FSI                 -0.005051   0.002157  -2.341343 5.1743e-02 .  
## Trade_China         -0.149383   0.269856  -0.553563 5.9711e-01    
## Sec_US               0.192676   0.086719   2.221836 6.1710e-02 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 0.190515   Adj. R2: 0.536776
modelsummary(
  list(
    "(1) Elite Preference Distance" = model_elite,
    "(2) Relative Position Index" = model_relative
  ),
  output = "regression_table.docx",
  stars = c("*" = 0.1, "**" = 0.05, "***" = 0.01),
  statistic = "({std.error})",
  coef_map = c(
    "Democracy" = "Democracy",
    "Post2022" = "Post-2022",
    "SCS" = "SCS Claimant",
    "Political_Stability" = "Political Stability",
    "FSI" = "State Capacity",
    "Trade_China" = "Trade with China",
    "Sec_US" = "U.S. Security Ties"
  ),
  gof_map = c(
    "nobs",
    "r.squared",
    "adj.r.squared"
  ),
  notes = "Clustered standard errors by country in parentheses. * p < 0.10, ** p < 0.05, *** p < 0.01."
)
library(modelsummary)

modelsummary(
  list(
    "(1) Elite Preference Distance" = model_elite,
    "(2) Relative Position Index" = model_relative
  ),
  stars = c("*" = 0.1, "**" = 0.05, "***" = 0.01),
  statistic = "({std.error})",
  coef_map = c(
    "Democracy" = "Democracy",
    "Post2022" = "Post-2022",
    "SCS" = "SCS Claimant",
    "Political_Stability" = "Political Stability",
    "FSI" = "State Capacity",
    "Trade_China" = "Trade with China",
    "Sec_US" = "U.S. Security Ties"
  ),
  gof_map = c(
    "nobs",
    "r.squared",
    "adj.r.squared"
  ),
  notes = "Clustered standard errors by country in parentheses. * p < 0.10, ** p < 0.05, *** p < 0.01."
)
(1) Elite Preference Distance (2) Relative Position Index
* p < 0.1, ** p < 0.05, *** p < 0.01
Clustered standard errors by country in parentheses. * p < 0.10, ** p < 0.05, *** p < 0.01.
Democracy -7.266** -0.044**
(2.874) (0.013)
Post-2022 -9.198 -0.461***
(5.981) (0.046)
SCS Claimant 17.790* 0.081*
(8.951) (0.034)
Political Stability -0.118 0.007**
(0.688) (0.003)
State Capacity 0.021 -0.005*
(0.516) (0.002)
Trade with China -17.096 -0.149
(41.902) (0.270)
U.S. Security Ties -24.368 0.193*
(17.578) (0.087)
Num.Obs. 40 80
R2 0.381 0.578
R2 Adj. 0.245 0.537
library(plm)
## 
## Attaching package: 'plm'
## The following objects are masked from 'package:dplyr':
## 
##     between, lag, lead
pdata <- pdata.frame(
  data,
  index = c("Country", "Year")
)

model_re <- plm(
  Relative_Position ~
    Democracy +
    Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = pdata,
  model = "random"
)

summary(model_re)
## Oneway (individual) effect Random Effect Model 
##    (Swamy-Arora's transformation)
## 
## Call:
## plm(formula = Relative_Position ~ Democracy + Post2022 + SCS + 
##     Political_Stability + FSI + Trade_China + Sec_US, data = pdata, 
##     model = "random")
## 
## Balanced Panel: n = 8, T = 10, N = 80
## 
## Effects:
##                   var std.dev share
## idiosyncratic 0.03812 0.19523 0.577
## individual    0.02795 0.16717 0.423
## theta: 0.6536
## 
## Residuals:
##      Min.   1st Qu.    Median   3rd Qu.      Max. 
## -0.294071 -0.127037 -0.023878  0.079352  0.493831 
## 
## Coefficients:
##                       Estimate Std. Error z-value  Pr(>|z|)    
## (Intercept)          0.9136352  0.4344475  2.1030   0.03547 *  
## Democracy           -0.0411358  0.0351953 -1.1688   0.24249    
## Post2022            -0.4512179  0.0589175 -7.6585 1.882e-14 ***
## SCS                  0.0495093  0.1368412  0.3618   0.71750    
## Political_Stability  0.0055811  0.0061488  0.9077   0.36405    
## FSI                 -0.0045600  0.0037315 -1.2220   0.22170    
## Trade_China         -0.3589299  0.4985386 -0.7200   0.47155    
## Sec_US               0.2005146  0.1764417  1.1364   0.25577    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Total Sum of Squares:    5.6825
## Residual Sum of Squares: 2.6037
## R-Squared:      0.5418
## Adj. R-Squared: 0.49725
## Chisq: 85.1368 on 7 DF, p-value: 1.229e-15
model_elite <- feols(
  Elite_Preference ~
    Democracy +
    Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)
## NOTE: 40 observations removed because of NA values (LHS: 40).
model_relative <- feols(
  Relative_Position ~
    Democracy +
    Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)
fig1 <- ggplot(
  data,
  aes(
    x = Year,
    y = Relative_Position,
    group = Country,
    linetype = Country,
    shape = Country
  )
) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 2) +
  geom_vline(
    xintercept = 2022,
    linetype = "dashed",
    linewidth = 0.7
  ) +
  scale_x_continuous(
    breaks = 2014:2023
  ) +
  labs(
    title = "ASEAN-8 Relative Position, 2014–2023",
    subtitle = "Dashed line indicates the post-2022 period",
    x = "Year",
    y = "Relative Position Index",
    linetype = "Country",
    shape = "Country"
  ) +
  theme_classic(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold"),
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "right"
  )

fig1
## Warning: The shape palette can deal with a maximum of 6 discrete values because more
## than 6 becomes difficult to discriminate
## ℹ you have requested 8 values. Consider specifying shapes manually if you need
##   that many of them.
## Warning: Removed 20 rows containing missing values or values outside the scale range
## (`geom_point()`).

model_elite <- feols(
  Elite_Preference ~
    Democracy +
    Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)
## NOTE: 40 observations removed because of NA values (LHS: 40).
model_relative <- feols(
  Relative_Position ~
    Democracy +
    Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)
# -----------------------------
# Extract coefficients from fixest models
# -----------------------------

# Elite Preference model
elite_est <- coef(model_elite)
elite_ci  <- confint(model_elite, level = 0.95)

elite_coef <- data.frame(
  term = names(elite_est),
  estimate = as.numeric(elite_est),
  conf.low = elite_ci[, 1],
  conf.high = elite_ci[, 2],
  Outcome = "Option Leader Preference Index"
)

# Relative UNGA Position model
relative_est <- coef(model_relative)
relative_ci  <- confint(model_relative, level = 0.95)

relative_coef <- data.frame(
  term = names(relative_est),
  estimate = as.numeric(relative_est),
  conf.low = relative_ci[, 1],
  conf.high = relative_ci[, 2],
  Outcome = "Relative UNGA Position Index"
)

# Combine two models
coef_data <- bind_rows(
  elite_coef,
  relative_coef
) %>%
  filter(term != "(Intercept)") %>%
  mutate(
    Variable = recode(
      term,
      "Democracy" = "Democracy",
      "Post2022" = "Post-2022",
      "SCS" = "SCS Claimant",
      "Political_Stability" = "Political Stability",
      "FSI" = "State Capacity (100-FSI)",
      "Trade_China" = "Trade with China",
      "Sec_US" = "U.S. Security Ties"
    )
  )
fig2 <- ggplot(
  coef_data,
  aes(
    x = estimate,
    y = Variable
  )
) +
  geom_vline(
    xintercept = 0,
    linetype = "dashed"
  ) +
  geom_errorbarh(
    aes(
      xmin = conf.low,
      xmax = conf.high
    ),
    height = 0
  ) +
  geom_point(size = 2.8) +
  facet_wrap(
    ~ Outcome,
    scales = "free_x",
    nrow = 1
  ) +
  labs(
    title = "Determinants of ASEAN Hedging",
    subtitle = "OLS estimates with 95% confidence intervals",
    x = "Coefficient Estimate",
    y = NULL
  ) +
  theme_classic(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold"),
    strip.text = element_text(face = "bold"),
    strip.background = element_blank()
  )
## Warning: `geom_errorbarh()` was deprecated in ggplot2 4.0.0.
## ℹ Please use the `orientation` argument of `geom_errorbar()` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
fig2
## `height` was translated to `width`.

democracy_data <- coef_data %>%
  filter(term == "Democracy")

fig3 <- ggplot(
  democracy_data,
  aes(
    x = estimate,
    y = Outcome
  )
) +
  geom_vline(
    xintercept = 0,
    linetype = "dashed"
  ) +
  geom_errorbarh(
    aes(
      xmin = conf.low,
      xmax = conf.high
    ),
    height = 0.15
  ) +
  geom_point(size = 3.5) +
  labs(
    title = "Estimated Effect of Democracy",
    subtitle = "Effects across two dimensions of hedging",
    x = "Coefficient Estimate",
    y = NULL
  ) +
  theme_classic(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold")
  )

fig3
## `height` was translated to `width`.

model_post_interaction <- feols(
  Relative_Position ~
    Democracy * Post2022 +
    SCS +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)

summary(model_post_interaction)
## OLS estimation, Dep. Var.: Relative_Position
## Observations: 80
## Standard-errors: Clustered (Country) 
##                      Estimate Std. Error   t value  Pr(>|t|)    
## (Intercept)          0.838152   0.162593  5.154915 0.0013168 ** 
## Democracy           -0.049288   0.013077 -3.769042 0.0069917 ** 
## Post2022            -0.589929   0.125972 -4.683020 0.0022528 ** 
## SCS                  0.085399   0.034828  2.452058 0.0439744 *  
## Political_Stability  0.006907   0.002466  2.801166 0.0264799 *  
## FSI                 -0.005104   0.002086 -2.446801 0.0443147 *  
## Trade_China         -0.129671   0.280399 -0.462452 0.6577882    
## Sec_US               0.173489   0.101451  1.710071 0.1309962    
## Democracy:Post2022   0.025334   0.019206  1.319060 0.2286589    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 0.189492   Adj. R2: 0.535283
pred_post <- marginaleffects::predictions(
  model_post_interaction,
  newdata = marginaleffects::datagrid(
    Democracy = seq(
      min(data$Democracy, na.rm = TRUE),
      max(data$Democracy, na.rm = TRUE),
      length.out = 50
    ),
    Post2022 = c(0, 1),
    SCS = mean(data$SCS, na.rm = TRUE),
    Political_Stability = mean(data$Political_Stability, na.rm = TRUE),
    FSI = mean(data$FSI, na.rm = TRUE),
    Trade_China = mean(data$Trade_China, na.rm = TRUE),
    Sec_US = mean(data$Sec_US, na.rm = TRUE)
  )
) %>%
  mutate(
    Period = ifelse(
      Post2022 == 1,
      "Post-2022",
      "Pre-2022"
    )
  )
fig4 <- ggplot(
  pred_post,
  aes(
    x = Democracy,
    y = estimate,
    linetype = Period
  )
) +
  geom_ribbon(
    aes(
      ymin = conf.low,
      ymax = conf.high,
      group = Period
    ),
    alpha = 0.15,
    inherit.aes = TRUE
  ) +
  geom_line(
    linewidth = 1
  ) +
  labs(
    title = "Democracy and Relative Position Before and After 2022",
    x = "Democracy Score",
    y = "Predicted Relative Position Index",
    linetype = "Period"
  ) +
  theme_classic(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom"
  )

fig4

model_scs_interaction <- feols(
  Relative_Position ~
    Democracy * SCS +
    Post2022 +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US,
  data = data,
  cluster = ~Country
)

summary(model_scs_interaction)
## OLS estimation, Dep. Var.: Relative_Position
## Observations: 80
## Standard-errors: Clustered (Country) 
##                      Estimate Std. Error   t value   Pr(>|t|)    
## (Intercept)          0.918510   0.255745  3.591503 8.8394e-03 ** 
## Democracy           -0.059959   0.027710 -2.163798 6.7230e-02 .  
## SCS                 -0.048031   0.165960 -0.289411 7.8065e-01    
## Post2022            -0.468956   0.053714 -8.730697 5.1954e-05 ***
## Political_Stability  0.005279   0.003880  1.360387 2.1589e-01    
## FSI                 -0.003581   0.003234 -1.107385 3.0472e-01    
## Trade_China         -0.058796   0.293105 -0.200596 8.4672e-01    
## Sec_US               0.192131   0.097169  1.977293 8.8534e-02 .  
## Democracy:SCS        0.025076   0.030665  0.817753 4.4044e-01    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 0.189952   Adj. R2: 0.533023
pred_scs <- marginaleffects::predictions(
  model_scs_interaction,
  newdata = marginaleffects::datagrid(
    Democracy = seq(
      min(data$Democracy, na.rm = TRUE),
      max(data$Democracy, na.rm = TRUE),
      length.out = 50
    ),
    SCS = c(0, 1),
    Post2022 = 0,
    Political_Stability = mean(data$Political_Stability, na.rm = TRUE),
    FSI = mean(data$FSI, na.rm = TRUE),
    Trade_China = mean(data$Trade_China, na.rm = TRUE),
    Sec_US = mean(data$Sec_US, na.rm = TRUE)
  )
) %>%
  dplyr::mutate(
    Claimant = ifelse(
      SCS == 1,
      "SCS Claimant",
      "Non-Claimant"
    )
  )
fig5 <- ggplot(
  pred_scs,
  aes(
    x = Democracy,
    y = estimate,
    linetype = Claimant
  )
) +
  geom_ribbon(
    aes(
      ymin = conf.low,
      ymax = conf.high,
      group = Claimant
    ),
    alpha = 0.15
  ) +
  geom_line(
    linewidth = 1
  ) +
  labs(
    title = "Democracy and Geopolitical Exposure",
    subtitle = "Conditional relationship by South China Sea claimant status",
    x = "Democracy Score",
    y = "Predicted Relative Position Index",
    linetype = NULL
  ) +
  theme_classic(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom"
  )

fig5

change_data <- data %>%
  mutate(
    Period = ifelse(
      Year >= 2022,
      "Post-2022",
      "Pre-2022"
    )
  ) %>%
  group_by(
    Country,
    Period
  ) %>%
  summarise(
    Mean_Relative_Position =
      mean(Relative_Position, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  pivot_wider(
    names_from = Period,
    values_from = Mean_Relative_Position
  )
change_data <- change_data %>%
  arrange(`Pre-2022`) %>%
  mutate(
    Country = factor(
      Country,
      levels = Country
    )
  )
fig6 <- ggplot(change_data) +
  geom_segment(
    aes(
      x = `Pre-2022`,
      xend = `Post-2022`,
      y = Country,
      yend = Country
    ),
    linewidth = 0.8
  ) +
  geom_point(
    aes(
      x = `Pre-2022`,
      y = Country,
      shape = "Pre-2022"
    ),
    size = 3
  ) +
  geom_point(
    aes(
      x = `Post-2022`,
      y = Country,
      shape = "Post-2022"
    ),
    size = 3
  ) +
  labs(
    title = "Change in Relative Position Before and After 2022",
    x = "Average Relative Position Index",
    y = NULL,
    shape = "Period"
  ) +
  theme_classic(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold"),
    legend.position = "bottom"
  )

fig6

model_relative_fe <- feols(
  Relative_Position ~
    Democracy +
    Post2022 +
    Political_Stability +
    FSI +
    Trade_China +
    Sec_US
  | Country,
  data = data,
  cluster = ~Country
)

summary(model_relative_fe)
## OLS estimation, Dep. Var.: Relative_Position
## Observations: 80
## Fixed-effects: Country: 8
## Standard-errors: Clustered (Country) 
##                      Estimate Std. Error   t value   Pr(>|t|)    
## Democracy           -0.011216   0.032019 -0.350288 0.73642591    
## Post2022            -0.425169   0.074474 -5.708918 0.00072861 ***
## Political_Stability -0.000724   0.005917 -0.122341 0.90606702    
## FSI                 -0.003896   0.003568 -1.091866 0.31104038    
## Trade_China         -0.625942   0.419518 -1.492053 0.17931578    
## Sec_US               0.206657   0.104559  1.976460 0.08864319 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 0.177329     Adj. R2: 0.562197
##                  Within R2: 0.544225
ols_robust <- data.frame(
  term = names(coef(model_relative)),
  estimate = as.numeric(coef(model_relative)),
  conf.low = confint(model_relative)[, 1],
  conf.high = confint(model_relative)[, 2]
) %>%
  mutate(
    Model = "Pooled OLS"
  )

fe_robust <- data.frame(
  term = names(coef(model_relative_fe)),
  estimate = as.numeric(coef(model_relative_fe)),
  conf.low = confint(model_relative_fe)[, 1],
  conf.high = confint(model_relative_fe)[, 2]
) %>%
  mutate(
    Model = "Country FE"
  )

robust_data <- bind_rows(
  ols_robust,
  fe_robust
) %>%
  filter(
    term %in% c(
      "Democracy",
      "Post2022",
      "SCS"
    )
  ) %>%
  mutate(
    Variable = recode(
      term,
      "Democracy" = "Democracy",
      "Post2022" = "Post-2022",
      "SCS" = "SCS Claimant"
    )
  )