R Codes

# Download data from https://ctt.hust.edu.vn/DisplayWeb/DisplayBaiViet?baiviet=41346&fbclid=IwAR3nemyk6PQhK36NCTIAvs1KwdXO3B1s0ZelOz8IdlwHo5U4Y3S35ZbzhZ0

library(pdftools)
library(tidyverse)

txt <- pdf_text("DS SV được HB KKHT đăng web.pdf") %>% readr::read_lines() 

txt[-c(1:6)] -> hocbong

hocbong %>% 
  str_split(pattern = "  +", simplify = TRUE) %>% 
  as.data.frame() -> df_hocbong

names(df_hocbong) <- c("code", "field", "department", "khoa", "gpa", "rl", "type")

df_hocbong %>% mutate(khoa = str_c("K", khoa), 
                      gpa = as.numeric(gpa), 
                      rl = as.numeric(rl)) -> df_hocbong


df_hocbong %>% mutate(department = case_when(department == "Trường Công nghệ thông tin và Truyền thông" ~ "Trường CNTT-TT", 
                                             department == "Viện Toán ứng dụng và Tin học" ~ "Viện Toán - Tin", 
                                             department == "Viện Dệt may, Da giầy và thời trang" ~ "Viện Dệt May - TT", 
                                             TRUE ~ department)) -> df_hocbong

df_hocbong %>% 
  filter(department != "") %>% 
  group_by(department, type) %>% 
  count() -> nhomhocbong_byKhoa

nhomhocbong_byKhoa %>% 
  group_by(department) %>% 
  mutate(rateA = case_when(type == "A" ~ n / sum(n))) %>% 
  filter(!is.na(rateA)) -> df_rateA

df_rateA %>% 
  arrange(rateA) %>% 
  pull(department) -> department_orderedA


nhomhocbong_byKhoa %>% 
  mutate(type = factor(type, levels = c("C", "B", "A"))) %>% 
  mutate(department = factor(department, levels = department_orderedA)) -> nhomhocbong_byKhoa

nhomhocbong_byKhoa %>% filter(type == "A") -> hocbongloaiA

nhomhocbong_byKhoa %>% filter(type == "C") -> hocbongloaiC

nhomhocbong_byKhoa %>% 
  group_by(department) %>% 
  mutate(rateB = case_when(type == "B" ~ n / sum(n))) %>% 
  filter(!is.na(rateB)) -> df_rateB

full_join(df_rateA, df_rateB %>% select(-type), by = "department") -> df_rateAB

df_rateAB %>% 
  mutate(x_pos = rateA + 0.5*rateB) -> df_positionB

my_font <- "Roboto Condensed"

library(showtext)

font_add_google(name = my_font, family = my_font)

showtext_auto()

my_cols <- c('#1b9e77','#d95f02','#7570b3')

nhomhocbong_byKhoa %>% 
  ggplot(aes(y = department, x = n, fill = type)) + 
  geom_col(position = "fill") + 
  scale_fill_manual(values = my_cols) + 
  theme(legend.position = "top") + 
  theme(text = element_text(family = my_font)) + 
  theme(axis.title = element_blank()) + 
  guides(fill = guide_legend(reverse = TRUE, title = "Loại học bổng")) +
  labs(title = "Số lượng và tỉ lệ các loại học bổng - học kì 2 năm học 2022-2023", 
       subtitle = "Có tất cả 1621 sinh viên được học bổng. Viện CNTT-TT có 193 sinh viên đạt học bổng loại A (77%),\nViện KH&CN Môi trường có tỉ lệ sinh viên đạt học bổng loại A là thấp nhất với 24%.", 
       caption = "Source: https://ctt.hust.edu.vn | Graphic: Nguyen Chi Dung") + 
  geom_text(data = hocbongloaiA, aes(x = 0.015, label = n), hjust = 0, color = "white", family = my_font, size = 5) + 
  geom_text(data = hocbongloaiC %>% filter(department != "Viện Ngoại ngữ"), aes(x = 0.985, label = n), hjust = 1, color = "white", family = my_font, size = 5) + 
  geom_text(data = df_positionB, aes(x = x_pos, label = n.y), hjust = 1, color = "white", family = my_font, size = 5) + 
  theme(axis.ticks = element_blank()) + 
  scale_x_continuous(expand = c(0, 0), labels = c("0%", "25%", "50%", "75%", "100%")) + 
  theme(legend.key.height = unit(0.35, "cm")) +  
  theme(legend.key.width = unit(0.35, "cm")) + 
  theme(plot.title.position = "plot") + 
  theme(plot.title = element_text(size = 20)) + 
  theme(plot.subtitle = element_text(size = 11, color = "grey20")) + 
  theme(plot.caption = element_text(size = 10, color = "grey40")) + 
  theme(plot.margin = margin(0.5, 1, 0.5, 0.5, "cm")) + 
  theme(axis.text.y = element_text(size = 11)) + 
  theme(axis.text.x = element_text(size = 12))  + 
  theme(legend.text = element_text(color = "grey30", family = my_font)) + 
  theme(legend.title = element_text(color = "grey30", family = my_font)) + 
  theme(panel.grid.minor = element_blank()) + 
  theme(panel.grid.major.x = element_line(color = "grey60", size = 0.8))
LS0tDQp0aXRsZTogIkjhu41jIGLhu5VuZyBo4buNYyBrw6wgMiBuxINtIGjhu41jIDIwMjAtMjAyMywgxJBIQksgSMOgIE7hu5lpIiANCiMgc3VidGl0bGU6ICJCdXNpbmVzcyBBbmFseXRpY3MgRGl2aXNpb24iDQphdXRob3I6ICJOZ3V5ZW4gQ2hpIER1bmciDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICAjIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICAjIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6ICJmbGF0bHkiDQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KIVtdKEM6XFxVc2Vyc1xcQWRtaW5cXERvY3VtZW50c1xcaG9jYm9uZy5qcGcpDQoNCiMgUiBDb2Rlcw0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCg0KDQojIERvd25sb2FkIGRhdGEgZnJvbSBodHRwczovL2N0dC5odXN0LmVkdS52bi9EaXNwbGF5V2ViL0Rpc3BsYXlCYWlWaWV0P2JhaXZpZXQ9NDEzNDYmZmJjbGlkPUl3QVIzbmVteWs2UFFoSzM2TkNUSUF2czFLd2RYTzNCMXMwWmVsT3o4SWRsd0hvNVU0WTNTMzVaYnpoWjANCg0KbGlicmFyeShwZGZ0b29scykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQp0eHQgPC0gcGRmX3RleHQoIkRTIFNWIMSRxrDhu6NjIEhCIEtLSFQgxJHEg25nIHdlYi5wZGYiKSAlPiUgcmVhZHI6OnJlYWRfbGluZXMoKSANCg0KdHh0Wy1jKDE6NildIC0+IGhvY2JvbmcNCg0KaG9jYm9uZyAlPiUgDQogIHN0cl9zcGxpdChwYXR0ZXJuID0gIiAgKyIsIHNpbXBsaWZ5ID0gVFJVRSkgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgLT4gZGZfaG9jYm9uZw0KDQpuYW1lcyhkZl9ob2Nib25nKSA8LSBjKCJjb2RlIiwgImZpZWxkIiwgImRlcGFydG1lbnQiLCAia2hvYSIsICJncGEiLCAicmwiLCAidHlwZSIpDQoNCmRmX2hvY2JvbmcgJT4lIG11dGF0ZShraG9hID0gc3RyX2MoIksiLCBraG9hKSwgDQogICAgICAgICAgICAgICAgICAgICAgZ3BhID0gYXMubnVtZXJpYyhncGEpLCANCiAgICAgICAgICAgICAgICAgICAgICBybCA9IGFzLm51bWVyaWMocmwpKSAtPiBkZl9ob2Nib25nDQoNCg0KZGZfaG9jYm9uZyAlPiUgbXV0YXRlKGRlcGFydG1lbnQgPSBjYXNlX3doZW4oZGVwYXJ0bWVudCA9PSAiVHLGsOG7nW5nIEPDtG5nIG5naOG7hyB0aMO0bmcgdGluIHbDoCBUcnV54buBbiB0aMO0bmciIH4gIlRyxrDhu51uZyBDTlRULVRUIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBhcnRtZW50ID09ICJWaeG7h24gVG/DoW4g4bupbmcgZOG7pW5nIHbDoCBUaW4gaOG7jWMiIH4gIlZp4buHbiBUb8OhbiAtIFRpbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVwYXJ0bWVudCA9PSAiVmnhu4duIEThu4d0IG1heSwgRGEgZ2nhuqd5IHbDoCB0aOG7nWkgdHJhbmciIH4gIlZp4buHbiBE4buHdCBNYXkgLSBUVCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGRlcGFydG1lbnQpKSAtPiBkZl9ob2Nib25nDQoNCmRmX2hvY2JvbmcgJT4lIA0KICBmaWx0ZXIoZGVwYXJ0bWVudCAhPSAiIikgJT4lIA0KICBncm91cF9ieShkZXBhcnRtZW50LCB0eXBlKSAlPiUgDQogIGNvdW50KCkgLT4gbmhvbWhvY2JvbmdfYnlLaG9hDQoNCm5ob21ob2Nib25nX2J5S2hvYSAlPiUgDQogIGdyb3VwX2J5KGRlcGFydG1lbnQpICU+JSANCiAgbXV0YXRlKHJhdGVBID0gY2FzZV93aGVuKHR5cGUgPT0gIkEiIH4gbiAvIHN1bShuKSkpICU+JSANCiAgZmlsdGVyKCFpcy5uYShyYXRlQSkpIC0+IGRmX3JhdGVBDQoNCmRmX3JhdGVBICU+JSANCiAgYXJyYW5nZShyYXRlQSkgJT4lIA0KICBwdWxsKGRlcGFydG1lbnQpIC0+IGRlcGFydG1lbnRfb3JkZXJlZEENCg0KDQpuaG9taG9jYm9uZ19ieUtob2EgJT4lIA0KICBtdXRhdGUodHlwZSA9IGZhY3Rvcih0eXBlLCBsZXZlbHMgPSBjKCJDIiwgIkIiLCAiQSIpKSkgJT4lIA0KICBtdXRhdGUoZGVwYXJ0bWVudCA9IGZhY3RvcihkZXBhcnRtZW50LCBsZXZlbHMgPSBkZXBhcnRtZW50X29yZGVyZWRBKSkgLT4gbmhvbWhvY2JvbmdfYnlLaG9hDQoNCm5ob21ob2Nib25nX2J5S2hvYSAlPiUgZmlsdGVyKHR5cGUgPT0gIkEiKSAtPiBob2Nib25nbG9haUENCg0KbmhvbWhvY2JvbmdfYnlLaG9hICU+JSBmaWx0ZXIodHlwZSA9PSAiQyIpIC0+IGhvY2Jvbmdsb2FpQw0KDQpuaG9taG9jYm9uZ19ieUtob2EgJT4lIA0KICBncm91cF9ieShkZXBhcnRtZW50KSAlPiUgDQogIG11dGF0ZShyYXRlQiA9IGNhc2Vfd2hlbih0eXBlID09ICJCIiB+IG4gLyBzdW0obikpKSAlPiUgDQogIGZpbHRlcighaXMubmEocmF0ZUIpKSAtPiBkZl9yYXRlQg0KDQpmdWxsX2pvaW4oZGZfcmF0ZUEsIGRmX3JhdGVCICU+JSBzZWxlY3QoLXR5cGUpLCBieSA9ICJkZXBhcnRtZW50IikgLT4gZGZfcmF0ZUFCDQoNCmRmX3JhdGVBQiAlPiUgDQogIG11dGF0ZSh4X3BvcyA9IHJhdGVBICsgMC41KnJhdGVCKSAtPiBkZl9wb3NpdGlvbkINCg0KbXlfZm9udCA8LSAiUm9ib3RvIENvbmRlbnNlZCINCg0KbGlicmFyeShzaG93dGV4dCkNCg0KZm9udF9hZGRfZ29vZ2xlKG5hbWUgPSBteV9mb250LCBmYW1pbHkgPSBteV9mb250KQ0KDQpzaG93dGV4dF9hdXRvKCkNCg0KbXlfY29scyA8LSBjKCcjMWI5ZTc3JywnI2Q5NWYwMicsJyM3NTcwYjMnKQ0KDQpuaG9taG9jYm9uZ19ieUtob2EgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBkZXBhcnRtZW50LCB4ID0gbiwgZmlsbCA9IHR5cGUpKSArIA0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbXlfY29scykgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsgDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gbXlfZm9udCkpICsgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFLCB0aXRsZSA9ICJMb+G6oWkgaOG7jWMgYuG7lW5nIikpICsNCiAgbGFicyh0aXRsZSA9ICJT4buRIGzGsOG7o25nIHbDoCB04buJIGzhu4cgY8OhYyBsb+G6oWkgaOG7jWMgYuG7lW5nIC0gaOG7jWMga8OsIDIgbsSDbSBo4buNYyAyMDIyLTIwMjMiLCANCiAgICAgICBzdWJ0aXRsZSA9ICJDw7MgdOG6pXQgY+G6oyAxNjIxIHNpbmggdmnDqm4gxJHGsOG7o2MgaOG7jWMgYuG7lW5nLiBWaeG7h24gQ05UVC1UVCBjw7MgMTkzIHNpbmggdmnDqm4gxJHhuqF0IGjhu41jIGLhu5VuZyBsb+G6oWkgQSAoNzclKSxcblZp4buHbiBLSCZDTiBNw7RpIHRyxrDhu51uZyBjw7MgdOG7iSBs4buHIHNpbmggdmnDqm4gxJHhuqF0IGjhu41jIGLhu5VuZyBsb+G6oWkgQSBsw6AgdGjhuqVwIG5o4bqldCB24bubaSAyNCUuIiwgDQogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IGh0dHBzOi8vY3R0Lmh1c3QuZWR1LnZuIHwgR3JhcGhpYzogTmd1eWVuIENoaSBEdW5nIikgKyANCiAgZ2VvbV90ZXh0KGRhdGEgPSBob2Nib25nbG9haUEsIGFlcyh4ID0gMC4wMTUsIGxhYmVsID0gbiksIGhqdXN0ID0gMCwgY29sb3IgPSAid2hpdGUiLCBmYW1pbHkgPSBteV9mb250LCBzaXplID0gNSkgKyANCiAgZ2VvbV90ZXh0KGRhdGEgPSBob2Nib25nbG9haUMgJT4lIGZpbHRlcihkZXBhcnRtZW50ICE9ICJWaeG7h24gTmdv4bqhaSBuZ+G7ryIpLCBhZXMoeCA9IDAuOTg1LCBsYWJlbCA9IG4pLCBoanVzdCA9IDEsIGNvbG9yID0gIndoaXRlIiwgZmFtaWx5ID0gbXlfZm9udCwgc2l6ZSA9IDUpICsgDQogIGdlb21fdGV4dChkYXRhID0gZGZfcG9zaXRpb25CLCBhZXMoeCA9IHhfcG9zLCBsYWJlbCA9IG4ueSksIGhqdXN0ID0gMSwgY29sb3IgPSAid2hpdGUiLCBmYW1pbHkgPSBteV9mb250LCBzaXplID0gNSkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxhYmVscyA9IGMoIjAlIiwgIjI1JSIsICI1MCUiLCAiNzUlIiwgIjEwMCUiKSkgKyANCiAgdGhlbWUobGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuMzUsICJjbSIpKSArICANCiAgdGhlbWUobGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC4zNSwgImNtIikpICsgDQogIHRoZW1lKHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSkgKyANCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGNvbG9yID0gImdyZXkyMCIpKSArIA0KICB0aGVtZShwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvciA9ICJncmV5NDAiKSkgKyANCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMC41LCAxLCAwLjUsIDAuNSwgImNtIikpICsgDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICArIA0KICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5MzAiLCBmYW1pbHkgPSBteV9mb250KSkgKyANCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkzMCIsIGZhbWlseSA9IG15X2ZvbnQpKSArIA0KICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSArIA0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JleTYwIiwgc2l6ZSA9IDAuOCkpDQogIA0KDQoNCg0KDQpgYGANCg0K