# Load some dependencies
library(tidyverse)
library(sf)
library(terra)
library(janitor)
library(stringi)
library(downloadthis)Changes in Ho Chi Minh city map
Summary
Changes in administrative levels in HCM city from 2000 - 2026
2003 - 2 new districts and reorganize communes (ref)
Tan Phu (split from Tan Binh)
Binh Tan (split from Binh Chanh)
2006 - Reorganize communes in 3 districts (ref)
- Adjust communes in 3 districts: Go Vap, District 12, Tan Binh
2021 - Establish Thu Duc city and more commune adjustments (ref)
Thu Duc city merged from 3 districts: 2, 9 and Thu Duc
Adjust communes under Thu Duc city
2023 - early 2025 - Reorganize communes (again) (ref)
- Adjust communes in several districts: 3,4,5,6,8,10, 11,Phu Nhuan, Binh Thanh, Go Vap
- Most of these changes were in effect by 2025-01-01
July 2025 - Expand city and remove district level (ref)
Merge Binh Duong and Vung Tau to Ho Chi Minh city
Remove districts level, merge existing communes into 168 communes
Overview
2000 - 2003: 22 districts, 317 communes
2003 - 2021: 24 districts, 322 communes
2021 - 2023: 22 districts, 312 communes
2023 - 2025: 22 districts, 273 communes
2025 - present (April, 2026): 168 communes
Data for R
Preparing data
Since not all changes are captured on open-sourced shapefile data, we can use available datasets for major changes and manually merge polygons for minor ones.
Source for raw data
Before 2021 reform:
- GADM 4.1 (24 districts, 322 communes)
2021 - 2023
- GISvn (312 HCMC communes, Ba Ria - Vung Tau and Binh Duong communes before merging)
After 2025 reform: GIS VN (168 communes)
Preparing district data
# Roughly HCMC spatial extent
hcmc_cropvector <- c(106.2, 107.2, 10.2, 11.3)
# hcmc_extent <- ext(cropvector)
district_24 <- read_sf("data/raw/before_reforms/gadm41_VNM_shp/gadm41_VNM_2.shp",
options = "ENCODING=UTF-8") %>%
clean_names() %>%
st_crop(
xmin = hcmc_cropvector[1],
xmax = hcmc_cropvector[2],
ymin = hcmc_cropvector[3],
ymax = hcmc_cropvector[4]
) %>%
filter(gid_1 == "VNM.25_1")Preparing commune data
# The 312 communes map fr GISvn
commune_gis <- read_sf(
"data/raw/before_reforms/gisvn_vnm_shp/Việt Nam (phường xã) - 63.shp",
options = "ENCODING=UTF-8"
) %>%
clean_names() %>%
mutate(
ten_xa = str_remove(ten_xa, "^0+(?=[1-9])")
) %>%
rename(
name_1 = ten_tinh,
id_1 = ma_tinh,
name_2 = ten_huyen,
id_2 = ma_huyen,
name_3 = ten_xa,
id_3 = ma_xa,
type_3 = loai,
) %>%
mutate(
varname_2 = stri_trans_general(name_2, id = "Latin-ASCII"),
varname_3 = stri_trans_general(name_3, id = "Latin-ASCII")
) %>%
select(
name_1, id_1, name_2, id_2, varname_2, name_3, id_3, varname_3, geometry
)
# Get communes for Binh Duong and Ba Ria - Vung Tau right before merge as well
commune_312 <- commune_gis %>%
filter(name_1 == "TP. Hồ Chí Minh")
commune_binhduong <- commune_gis %>%
filter(name_1 == "Bình Dương")
commune_br_vt <- commune_gis %>%
filter(name_1 == "Bà Rịa - Vũng Tàu")
# The 322 communes map fr GADM
commune_322 <- read_sf("data/raw/before_reforms/gadm41_VNM_shp/gadm41_VNM_3.shp",
options = "ENCODING=UTF-8") %>%
clean_names() %>%
st_crop(
xmin = hcmc_cropvector[1],
xmax = hcmc_cropvector[2],
ymin = hcmc_cropvector[3],
ymax = hcmc_cropvector[4]
) %>%
filter(gid_1 == "VNM.25_1")
# The 168 communes map fr GIS vn
commune_168 <- read_sf("data/raw/after_2025_reforms/Việt Nam (phường xã) - 34/",
options = "ENCODING=UTF-8") %>%
filter(ten_tinh == "TP. Hồ Chí Minh")
# rename GISvn data for consistency
commune_168 <- commune_168 %>%
rename(
name_1 = ten_tinh,
id_1 = ma_tinh,
name_2 = ten_xa,
id_2 = ma_xa,
type_2 = loai,
merged_fr = sap_nhap
) %>%
mutate(
# make it a bit more consistent
name_1 = str_remove(name_1, "TP. "),
varname_2 = stri_trans_general(name_2, id = "Latin-ASCII")
) %>%
select(
name_1, id_1, name_2, id_2, varname_2, type_2, merged_fr, geometry
)Merge function
# merge function
merge_polygon <- function(sf_dat, merge_map=list(
"Thu Duc" = c("District 2", "District 9", "Thu Duc")
), colname="varname_2"){
walk(names(merge_map), \(new_shp) {
old_shps <- merge_map[[new_shp]]
merged <- sf_dat %>%
filter(.data[[colname]] %in% old_shps) %>%
st_union()
if (new_shp %in% sf_dat[[colname]]) {
# new_shp already exists --> update its geometry and drop other old shapes
rm_shapes <- setdiff(old_shps, new_shp)
sf_dat <<- sf_dat %>%
mutate(geometry = if_else(.data[[colname]] == new_shp, merged, geometry)) %>%
filter(!(.data[[colname]] %in% rm_shapes))
} else {
# new_shp doesn't exist --> append new row and drop old shapes
new_row <- tibble("{colname}" := new_shp, geometry = merged) %>% st_sf()
sf_dat <<- sf_dat %>%
filter(!(.data[[colname]] %in% old_shps)) %>%
bind_rows(new_row)
}
})
sf_dat
}Data for download
hcmc_shapefile <- list(
boundary_pre_reform = district_24 %>% summarize(),
boundary_post_reform = commune_168 %>% summarize(),
district_24 = district_24, # sf
commune_322 = commune_322, # sf
commune_312 = commune_312, # sf
commune_binhduong = commune_binhduong, # sf
commune_br_vt = commune_br_vt, # sf
commune_168 = commune_168, # sf
merge_polygon = merge_polygon # function to merge polygons
)Download data
Data for download is an R list with the following items
boundary_pre_reform- HCM city boundary before merging with Vung Tau, Binh Duongboundary_post_reform- HCM city boundary after merging with Vung Tau, Binh Duongdistrict_24- 24 districts in HCM city (during 2003 - 2021)commune_322- 322 communes in HCM city (during 2003 - 2021)commune_312- 312 communes in HCM city (during 2021 - 2023)commune_168- 168 communes in HCM city (after 2025 reform)