R에서 객체 지향을 구현하는 방법
R6 패키지를 통해서 파이썬과 유사한 객체지향을 구현할 수 있다.
적용할 코드
진짜 코드 뭣도 모르고 공부도 제대로 안 해봤을 때 막일 100%로 작성한 코드이다.
너어어무 지저분한데 고칠 엄두가 나지 않았다.
적용 이후
예제 데이터
사람의 손 양바닥, 혀, 장의 마이크로바이옴 데이터를 담고 있다 (Qiime2 moving-pictures data). Genus-level에서 Top 10에 해당하는 결과를 관찰해 보자.
객체 지향을 고려한 코드
# 필요한 라이브러리 로드
library(phyloseq)
library(dplyr)
library(ggplot2)
library(R6)
library(RColorBrewer)
library(rlang)
TaxProcess <- R6Class("TaxProcess",
public = list(
# 필요한 변수(field) 선언
melt = NULL,
taxa = NULL,
top = NULL,
color_list = NULL,
final_color = NULL,
processed_data = NULL,
# class 안의 객체를 만들때 사용되는 initialize
initialize = function(melt, taxa, top) {
self$melt <- melt
self$taxa <- taxa
self$top <- top
},
# 데이터 전 처리
process_data = function() {
# Abundance 순으로 정렬
Order <- tapply(self$melt$Abundance, self$melt[, self$taxa], sum) %>% sort(decreasing = TRUE)
# Top N만 추출
Names <- names(Order[1:self$top])
# Phylum 처리
Top_p <- self$melt[self$melt[, self$taxa] %in% Names, "Phylum"] %>% unique()
p_tax_table <- self$melt[ self$melt[, self$taxa] %in% Names, c("Phylum", self$taxa)] %>%
.[!duplicated(.[ , self$taxa]),]
# Top N 을 제외한 taxa는 모두 etc 로 치환
self$processed_data <- self$melt
# Phylum 레벨에서 Other 처리
self$processed_data[!self$processed_data[, "Phylum"] %in% Top_p, "Phylum" ] <- "Other"
self$processed_data[!self$processed_data[, "Phylum"] %in% Top_p, self$taxa] <- "Other"
# Genus 와 Phylum정렬
if (self$taxa != "Species") {
for (i in Top_p) {
G <-p_tax_table[p_tax_table[, "Phylum"] == i, self$taxa]
self$processed_data[self$processed_data[, "Phylum"] == i, self$taxa]
self$processed_data[self$processed_data[, "Phylum"] == i & !self$processed_data[, self$taxa] %in% G, self$taxa] <- paste0(i, "_Other")
}
for (i in Top_p) {
G <- p_tax_table[p_tax_table[, "Phylum"] == i, self$taxa]
for (g in G) {
self$processed_data[self$processed_data[, self$taxa] == g, self$taxa] <- paste0(i, "_", g)
}
}
} else {
for (i in Top_p) {
G <- p_tax_table[p_tax_table[, "Phylum"] == i, self$taxa]
self$processed_data[self$processed_data[, "Phylum"] == i & !self$processed_data[, self$taxa] %in% G, self$taxa] <- "Other"
self$processed_data[self$processed_data[, "Phylum"] == i & !self$processed_data[, self$taxa] %in% G, "Phylum"] <- "Other"
}
}
},
Order_data = function(){
# phylum level
table <- self$processed_data[self$processed_data[, "Phylum" ] %in% Top_p, c("Abundance", "Phylum", self$taxa)]
p_order <- table %>% .[,"Phylum" ]%>% unique
self$processed_data[,"Phylum"] <- factor(self$processed_data[,"Phylum" ], levels = c(sort(p_order), "Other"))
# Genus order
table_2 <- table %>% dplyr::group_by_(.dots = "Phylum", self$taxa) %>%
dplyr::summarise(sum.Abundance=sum(Abundance), .groups = 'drop') %>%
as.data.frame() %>%
dplyr::arrange( -sum.Abundance)
g_order <- table_2 %>% dplyr::arrange_("Phylum") %>% .[, self$taxa ]
self$processed_data[ ,self$taxa] <- factor(self$processed_data[,self$taxa], levels = c(g_order, "Other"))
self$processed_data[ ,self$taxa] %>% levels()
return()
},
generate_colors = function() {
table <- self$processed_data[c("Abundance", "Phylum", self$taxa)]
table_3 <- table_2 %>%
dplyr::arrange(-sum.Abundance) %>%
dplyr::arrange_("Phylum") %>%
dplyr::select_("Phylum", self$taxa)
categories <- aggregate(as.formula(paste(self$taxa, "Phylum", sep = "~")), table_3, function(x) length(unique(x)))
P_levels <- c("Firmicutes", as.vector(p_order[p_order != "Firmicutes"]), "Others")
color_list.names <- categories[, "Phylum"]
self$color_list <- vector("list", length(color_list.names))
names(self$color_list) <- color_list.names
##
phylum_color_map <- list(
Actinobacteria = "Reds",
Firmicutes = "Blues",
Bacteroidetes = "Purples",
Proteobacteria = "Greens",
Fusobacteria = "YlOrBr"
)
basic_p <- names(phylum_color_map)
other_colors <- c("RdPu", "YlOrBr", "Spectral", "BrBG", "PuOr")
other_p <- categories$Phylum[!categories$Phylum %in% basic_p]
other_color_map <- setNames(other_colors[1:length(other_p)], other_p)
phylum_color_map <- c(phylum_color_map, other_color_map)
for (phylum in names(phylum_color_map)) {
num_taxa <- categories[categories$Phylum == phylum, self$taxa]
palette_name <- phylum_color_map[[phylum]]
if (length(num_taxa) > 0) {
self$color_list[[phylum]] <- get_palette_colors(palette_name, num_taxa)
}
}
##
self$color_list
color_vector <- unlist(self$color_list, use.names = FALSE)
self$final_color <- c(color_vector, "#D3D3D3")
return(self$final_color)
},
get_palette_colors = function(palette_name, num_taxa) {
if (num_taxa == 1) {
colors <- rev(brewer.pal(9, palette_name)[5])
} else if (num_taxa == 2) {
colors <- rev(brewer.pal(9, palette_name)[c(3, 7)])
} else if (num_taxa >= 3 & num_taxa <= 9) {
colors <- rev(brewer.pal(num_taxa, palette_name))
} else {
if (palette_name == "RdPu") {
colors <- terrain.colors(num_taxa)
} else if (palette_name == "Blues") {
colors <- heat.colors(num_taxa)
} else if (palette_name == "Purples") {
colors <- cm.colors(num_taxa)
} else if (palette_name == "Greens") {
colors <- topo.colors(num_taxa)
} else if (palette_name == "YlOrBr") {
colors <- colorRampPalette(c("skyblue", "orange"))(num_taxa)
} else {
colors <- rainbow(num_taxa)
}
}
return(colors)
},
# 샘플 순서 정렬
sampleID_order_by_phylum = function(tax_level,tax, x_axis = "SampleID") {
Order <- self$processed_data %>%
data.frame() %>%
dplyr::group_by(!!rlang::sym(x_axis)) %>%
mutate(Abundance = Abundance / sum(Abundance)) %>%
filter(!!rlang::sym(tax_level) == tax) %>%
dplyr::group_by(!!rlang::sym(x_axis)) %>%
dplyr::summarise(Abundance = sum(Abundance)) %>%
dplyr::arrange(Abundance) %>%
pull(!!rlang::sym(x_axis)) %>%
as.character()
self$processed_data[, x_axis] <- factor(self$processed_data[, x_axis], levels = Order)
return(self)
},
# 출력
get_result = function() {
list(Final_color = self$final_color, data = self$processed_data)
}
)
)
실행
# Example usage:
melt_data <- psmelt(ps.gn.rel) # Replace with your actual melt data
taxa_level <- "Genus" # Replace with your actual taxa level
top_n <- 20 # Replace with your actual top N value
# Create an object of the TaxProcess class
tax_process_obj <- TaxProcess$new(melt = melt_data,
taxa = taxa_level,
top = top_n)
# Process data and generate colors
tax_process_obj$process_data()
tax_process_obj$Order_data()
tax_process_obj$generate_colors()
# Optionally order sample IDs by a specific Phylum
tax_process_obj$sampleID_order_by_phylum("Phylum", "Actinobacteria", "Sample")
# Get the result
result <- tax_process_obj$get_result()
print(result$Final_color)
print(result$data)
# Barplot 생성 및 커스터마이징
p <- ggplot(result$data, aes(x = Sample, y = Abundance, fill = Genus)) +
geom_bar(stat = "identity", position = "stack") +
theme_minimal() +
labs(title = "Phylum'",
x = "Sample", y = "Relative Abundance") +
theme(axis.text.x = element_text(angle = 30, hjust = 1), # x축 라벨 각도 조정
plot.title = element_text(hjust = 0.5), # 제목 가운데 정렬
legend.position = "right", # 범례를 하단에 위치
legend.title = element_blank()) + # 범례 제목 제거
scale_fill_manual(values = result$Final_color) # 색상 팔레트 변경
print(p)
참고
- https://www.youtube.com/watch?v=HK4JkUN_Vhk
- 코드 수정은 ChatGPT 사용
이번 학기에 들었던 파이썬 스터디를 통해 배웠던 객체 지향을 써먹어 보았다.
에러확인이 어려울 것 같긴 한데, 생각보다 사용이 너어어어무 편하다.
역시 쓰는 이유가 있었고낳
반응형