บทที่ 2 การสร้างกราฟและแดชบอร์ดด้วย R

# สำหรับสร้างกราฟ
# ใน R มีระบบกราฟิกพื้นฐาน (base graphics) อยู่แล้ว และเราได้ติดตั้งไลบรารีเสริม ggplot2 และ readxl
# install.packages("ggplot2", repos="https://cloud.r-project.org")
# install.packages("readxl", repos="https://cloud.r-project.org")
#Config ฟอนต์
# ใน Windows สามารถใช้ windowsFonts() เพื่อลงทะเบียนฟอนต์ภาษาไทยได้
if (.Platform$OS.type == "windows") {
    windowsFonts(Sarabun = windowsFont("TH Sarabun New"))
    # ตั้งค่ากราฟิกพื้นฐานให้ใช้ฟอนต์ Sarabun
    par(family = "Sarabun", cex.main = 1.5, cex.lab = 1.2, cex.axis = 1.1)
}
#อ่านข้อมูลจากไฟล์ csv
x <- read.csv('data/customer.csv', stringsAsFactors = FALSE)
x
##    item age sex education_level occupation total_spend
## 1     1  25 หญิง         ปริญญาตรี  พนักงานขาย        4500
## 2     2  27 ชาย         ปริญญาโท  พนักงานขาย        6200
## 3     3  23 ชาย         ปริญญาตรี  พนักงานขาย        5000
## 4     4  35 หญิง        ปริญญาเอก  พนักงานขาย        8000
## 5     5  41 ชาย         ปริญญาโท  พนักงานขาย      120000
## 6     6  32 หญิง         ปริญญาตรี  พนักงานขาย        3500
## 7     7  26 หญิง         ปริญญาโท  พนักงานขาย       11000
## 8     8  22 ชาย         ปริญญาตรี  พนักงานขาย        8750
## 9     9  28 ชาย                  พนักงานขาย       15000
## 10   10  34 ชาย         ปริญญาตรี  พนักงานขาย       12000
#การสร้างกราฟแท่ง (Bar Chart)
x <- read.csv('data/customer.csv', stringsAsFactors = FALSE)

# นับจำนวนของแต่ละเพศ
sex_counts <- table(x$sex)
data <- data.frame(จำนวน = as.vector(sex_counts), row.names = names(sex_counts))

# วาดกราฟแท่ง
barplot(data$จำนวน, 
        names.arg = rownames(data), 
        main = 'เปรียบเทียบจำนวนเพศชายกับเพศหญิง', 
        ylab = 'จำนวน', 
        col = 'skyblue')

data
##     จำนวน
## ชาย     6
## หญิง     4
#การสร้างกราฟวงกลม (Pie Chart)
edu_counts <- table(x$education_level)
data <- data.frame(จำนวน = as.vector(edu_counts), row.names = names(edu_counts))

# คำนวณเปอร์เซ็นต์สำหรับป้ายกำกับของวงกลม
pct <- round(100 * data$จำนวน / sum(data$จำนวน), 2)
lbls <- paste0(rownames(data), "\n", pct, "%")

pie(data$จำนวน, 
    labels = lbls, 
    col = rainbow(length(edu_counts)))

data
##          จำนวน
##              1
## ปริญญาตรี      5
## ปริญญาโท      3
## ปริญญาเอก     1
#การสร้างกราฟเส้น (Line Chart)
data <- data.frame(age = x$age)

plot(data$age, 
     type = 'l', # Line only
     main = 'เปรียบเทียบอายุของลูกค้า', 
     xlab = 'คนที่', 
     ylab = 'อายุ', 
     col = 'blue')

#การสร้างฮิสโทแกรม (Histogram)
data <- data.frame(age = x$age)

hist(data$age, 
     breaks = 5, 
     main = 'ฮิสโทแกรมของอายุลูกค้า', 
     xlab = 'อายุ', 
     ylab = 'จำนวนคน', 
     col = 'lightgreen')

#การสร้างบ๊อกพล็อต (Boxplot)
#ขอบล่าง ค่า Min หรือ Q1−1.5×IQR | IQR = Q3 - Q1
#ขอบบน ค่า Max หรือ Q3+1.5×IQR | IQR = Q3 - Q1

data <- data.frame(age = x$age)
boxplot(data$age, 
        main = 'บ๊อกพล๊อตของอายุลูกค้า', 
        names = c('age'), 
        col = 'gold')

#แสดงสถิติเบื้องต้นของข้อมูล
summary(data)
##       age       
##  Min.   :22.00  
##  1st Qu.:25.25  
##  Median :27.50  
##  Mean   :29.30  
##  3rd Qu.:33.50  
##  Max.   :41.00
#การสร้างสแคทเทอร์ (Scatter)
data <- x[, c('age', 'total_spend')]

plot(data$age, data$total_spend, 
     main = 'สแคทเทอร์แสดงความสัมพันธ์ระหว่างอายุกับยอดการใช้จ่าย', 
     xlab = 'age', 
     ylab = 'total_spend', 
     col = 'darkred', 
     pch = 19)

#อ่านข้อมูลอัตราการยกเลิกการเป็นสมาชิกจากไฟล์ excel
library(readxl)
df <- read_excel('data/churn_rate.xlsx')
df
## # A tibble: 10 × 6
##     item age   sex   education_level occupation churn  
##    <dbl> <chr> <chr> <chr>           <chr>      <chr>  
##  1     1 22-25 หญิง   ปริญญาตรี         พนักงานขาย  ยกเลิก  
##  2     2 26-31 ชาย   ปริญญาโท         พนักงานบัญชี  ไม่ยกเลิก
##  3     3 22-25 ชาย   ปริญญาตรี         พนักงานขาย  ยกเลิก  
##  4     4 32-41 หญิง   ปริญญาเอก        พนักงานบุคคล ไม่ยกเลิก
##  5     5 32-41 ชาย   ปริญญาโท         พนักงานบัญชี  ไม่ยกเลิก
##  6     6 32-41 หญิง   ปริญญาตรี         พนักงานบัญชี  ยกเลิก  
##  7     7 26-31 หญิง   ปริญญาโท         พนักงานขาย  ไม่ยกเลิก
##  8     8 22-25 ชาย   ปริญญาตรี         พนักงานบุคคล ยกเลิก  
##  9     9 26-31 ชาย   ปริญญาตรี         พนักงานบุคคล ไม่ยกเลิก
## 10    10 32-41 ชาย   ปริญญาตรี         พนักงานขาย  ไม่ยกเลิก
library(readxl)

# อ่านข้อมูลจากไฟล์ xlsx
df <- read_excel('data/churn_rate.xlsx')

# เตรียม Layout 2x2
par(mfrow=c(2, 2), mar=c(5, 6, 4, 2) + 0.1)

# กราฟที่ 1: Churn by Age Group (Stacked Bar)
age_churn_table <- table(df$churn, df$age)
barplot(age_churn_table, horiz = TRUE, 
        col = c('#ef4444', '#22c55e'), main = 'Churn by Age Group',
        xlab = 'จำนวนลูกค้า', las = 1, legend = rownames(age_churn_table))

# กราฟที่ 2: Churn by Education Level (Stacked Bar)
edu_churn_table <- table(df$churn, df$education_level)
barplot(edu_churn_table, horiz = TRUE, 
        col = c("#f76868", "#22c55e"), main = 'Churn by Education Level',
        xlab = 'จำนวนลูกค้า', las = 1, legend = rownames(edu_churn_table))

# ฟังก์ชันผู้ช่วยสำหรับสร้าง Heatmap สวยๆ ด้วย base R
plot_heatmap <- function(tab, main_title) {
  mat <- as.matrix(tab)
  # กลับลำดับแถวเพื่อให้แสดงผลจากบนลงล่าง
  mat <- mat[nrow(mat):1, , drop=FALSE]
  
  cols <- colorRampPalette(c("#fff5f0", "#fc9272", "#cb181d"))(100)
  image(1:ncol(mat), 1:nrow(mat), t(mat), 
        col = cols, axes = FALSE, xlab = "", ylab = "", main = main_title)
        
  axis(1, at = 1:ncol(mat), labels = colnames(mat))
  axis(2, at = 1:nrow(mat), labels = rownames(mat), las = 1)
  
  # ใส่ตัวเลขแสดงจำนวนในแต่ละช่อง
  for (x_val in 1:ncol(mat)) {
    for (y_val in 1:nrow(mat)) {
      text(x_val, y_val, labels = mat[y_val, x_val], 
           col = ifelse(mat[y_val, x_val] > mean(mat), "white", "black"), cex = 1.2)
    }
  }
  box()
}

# กราฟที่ 3: Age Group vs Churn Status (Heatmap)
age_churn_crosstab <- table(df$age, df$churn)
plot_heatmap(age_churn_crosstab, 'Age Group vs Churn Status')

# กราฟที่ 4: Education Level vs Churn Status (Heatmap)
edu_churn_crosstab <- table(df$education_level, df$churn)
plot_heatmap(edu_churn_crosstab, 'Education Level vs Churn Status')

#อ่านข้อมูล pm2.5 จากไฟล์ excel
library(readxl)
df <- read_excel('data/pm2.5.xlsx')
df
## # A tibble: 10 × 4
##    Date                Temperature Rainfall PM2.5
##    <dttm>                    <dbl>    <dbl> <dbl>
##  1 2568-08-16 00:00:00          35     18      22
##  2 2568-08-17 00:00:00          34     15.2    25
##  3 2568-08-18 00:00:00          33      8.5    28
##  4 2568-08-19 00:00:00          34      2      26
##  5 2568-08-20 00:00:00          35      0      24
##  6 2568-08-21 00:00:00          32     12.3    30
##  7 2568-08-22 00:00:00          31     10.4    33
##  8 2568-08-23 00:00:00          29      0.5    39
##  9 2568-08-24 00:00:00          30      0      38
## 10 2568-08-25 00:00:00          28     10.7    34
library(readxl)

# อ่านข้อมูลจากไฟล์ xlsx
df <- read_excel('data/pm2.5.xlsx')

# ตั้งค่า Layout 2x2
par(mfrow=c(2, 2), mar=c(5, 5, 4, 2) + 0.1)

# กราฟที่ 1: PM2.5 Trend (Line + Markers + Threshold Lines)
plot(df$Date, df$PM2.5, type = 'o', col = '#e74c3c', pch = 19,
     main = 'PM2.5 Trend', xlab = 'Date', ylab = 'PM2.5 (µg/m³)')
abline(h = 25, col = 'orange', lty = 2, lwd = 2)
abline(h = 37.5, col = 'red', lty = 2, lwd = 2)
legend('topright', legend = c('Standard (25 µg/m³)', 'Unhealthy (37.5 µg/m³)'),
       col = c('orange', 'red'), lty = 2, lwd = 2)
grid(nx = NULL, ny = NULL, col = "lightgray", lty = "dotted")

# คำนวณสีตามระดับ PM2.5 (เขียว -> เหลือง -> แดง)
color_palette <- colorRampPalette(c("#2ca02c", "#ffbb78", "#d62728"))(100)
pm_min <- min(df$PM2.5)
pm_max <- max(df$PM2.5)
pm_scaled <- round(1 + 99 * (df$PM2.5 - pm_min) / (pm_max - pm_min))
mapped_colors <- color_palette[pm_scaled]

# กราฟที่ 2: PM2.5 vs Temperature (Scatter + Trend Line)
plot(df$Temperature, df$PM2.5, col = "black", bg = mapped_colors, 
     pch = 21, cex = 2, main = 'PM2.5 vs Temperature', 
     xlab = 'Temperature', ylab = 'PM2.5')
fit1 <- lm(PM2.5 ~ Temperature, data = df)
abline(fit1, col = "#ff8080", lty = 2, lwd = 2)
legend("topright", legend=c("High PM2.5", "Low PM2.5"), fill=c("#d62728", "#2ca02c"))
grid(nx = NULL, ny = NULL, col = "lightgray", lty = "dotted")

# กราฟที่ 3: PM2.5 vs Rainfall (Scatter + Trend Line)
plot(df$Rainfall, df$PM2.5, col = "black", bg = mapped_colors, 
     pch = 21, cex = 2, main = 'PM2.5 vs Rainfall', 
     xlab = 'Rainfall', ylab = 'PM2.5')
fit2 <- lm(PM2.5 ~ Rainfall, data = df)
abline(fit2, col = "#ff8080", lty = 2, lwd = 2)
legend("topright", legend=c("High PM2.5", "Low PM2.5"), fill=c("#d62728", "#2ca02c"))
grid(nx = NULL, ny = NULL, col = "lightgray", lty = "dotted")

# กราฟที่ 4: All Parameters Comparison (Multi-line)
ylim_range <- range(c(df$Temperature, df$Rainfall, df$PM2.5), na.rm = TRUE)
plot(df$Date, df$Temperature, type = 'o', col = 'blue', pch = 19, cex = 0.8,
     ylim = ylim_range, main = 'All Parameters Comparison', xlab = 'Date', ylab = 'Value')
lines(df$Date, df$Rainfall, type = 'o', col = 'green', pch = 15, cex = 0.8)
lines(df$Date, df$PM2.5, type = 'o', col = 'red', pch = 17, cex = 0.8)
legend('topright', legend = c('Temperature (°C)', 'Rainfall (mm)', 'PM2.5 (µg/m³)'),
       col = c('blue', 'green', 'red'), pch = c(19, 15, 17), lty = 1)
grid(nx = NULL, ny = NULL, col = "lightgray", lty = "dotted")