2016-04-21 3 views
10

J'essaie d'extraire les couleurs utilisées dans le clustering de circlize_dendrogram. Voici un des exemples de code:Extraire la couleur du cluster à partir de la sortie de dendextend :: circlize_dendrogram()

library(magrittr) 
library(dendextend) 

cols <- c("#009000", "#FF033E", "#CB410B", "#3B444B", "#007FFF") 
dend <- iris[1:40,-5] %>% dist %>% hclust %>% as.dendrogram  

dend <- color_branches(dend, k = 5, col = cols) 
dend %<>% set("labels_col", value = cols, k= 5) 
dend %<>% set("labels_cex", .8) 
dend %<>% set("branches_lwd", 2) 

circlize_dendrogram(dend) 

enter image description here

Alors que les grappes sous forme de tableaux sont extraits à l'aide cutree(dend, k = 5). Y at-il un moyen d'extraire les couleurs des grappes dans le dendrogramme basé sur le cols donné? J'en ai besoin pour insérer une légende dans l'intrigue en utilisant le paquet grid.

Exemple, Légende: Groupe 1 - #009000; Groupe 2 - #FF033E; Groupe 3 - #CB410B; Groupe 4 - #3B444B; Groupe 5 - #007FFF. Le problème avec le circlize_dendrogram est l'ordre des couleurs utilisées pour le cluster est différent.

Bien que je puisse le faire manuellement, il serait efficace si je peux le faire automatiquement. Et c'est possible si je peux extraire les couleurs des grappes.

Répondre

8

Ok, voici une solution très hacky. Je suis convaincu qu'il y en a de meilleurs, mais c'est un premier coup de poignard, alors supportez-moi. L'idée est de rechercher l'objet dend (qui est une liste interne) pour les noms d'éléments respectifs (dans ce cas seulement les chiffres) et extraire la couleur correspondante, l'enregistrer dans un bloc de données et l'utiliser pour une légende .

# First we'll extract the elements and corresponding categories... 
categories <- cutree(dend, k = 5) 

# ... and save them in a data frame 
categories_df <- data.frame(elements = as.numeric(names(categories)), 
     categories = categories, 
     color = NA) 

# now here's a little function that extracts the color for each element 
# from the 'dend' object. It uses the list.search() function from the 
# 'rlist' package 

library(rlist) 

extract_color <- function(element_no, dend_obj) { 
    dend.search <- list.search(dend_obj, all(. == element_no)) 
    color <- attr(dend.search[[1]], "edgePar")$col 
    return(color) 
} 

# I use 'dplyr' to manipulate the data 
library(dplyr) 

categories_df <- categories_df %>% 
    group_by(elements) %>% 
    mutate(color = extract_color(elements, dend)) 

Maintenant, cela nous donne la trame de données suivantes:

> categories_df 
Source: local data frame [40 x 3] 
Groups: elements [40] 

    elements categories color 
     (dbl)  (int) (chr) 
1   1   1 #CB410B 
2   2   1 #CB410B 
3   3   1 #CB410B 
4   4   1 #CB410B 
5   5   1 #CB410B 
6   6   2 #009000 
7   7   1 #CB410B 
8   8   1 #CB410B 
9   9   3 #007FFF 
10  10   1 #CB410B 
..  ...  ...  ... 

Nous pouvons le résumer à un cadre de données uniquement avec les couleurs pour les catégories, par exemple

legend_data <- categories_df %>% 
    group_by(categories) %>% 
    summarise(color = unique(color)) 

> legend_data 
Source: local data frame [5 x 2] 

    categories color 
     (int) (chr) 
1   1 #CB410B 
2   2 #009000 
3   3 #007FFF 
4   4 #FF033E 
5   5 #3B444B 

Maintenant, il est facile de générer la légende:

circlize_dendrogram(dend) 
legend(-1.05, 1.05, legend = legend_data$categories, fill = legend_data$color, cex = 0.7) 

Ce qui vous donne:

enter image description here

Vous pouvez utiliser cutree(dend, k = 5) pour confirmer que les chiffres pour les couleurs de catégorie correspondent à la catégorie de chaque élément.

+0

Clever! J'ai été capable de le résoudre hier. Mais je suis intéressé par d'autres solutions possibles. –

5

En plus de la solution de Felix, je voudrais poster ma réponse:

library(magrittr) 
library(grid) 
library(gridExtra) 
library(dendextend) 

cols <- c("#009000", "#FF033E", "#CB410B", "#3B444B", "#007FFF") 
dend <- iris[1:40,-5] %>% dist %>% hclust %>% as.dendrogram  

dend <- color_branches(dend, k = 5, col = cols) 
dend %<>% set("labels_col", value = cols, k= 5) 
dend %<>% set("labels_cex", .8) 
dend %<>% set("branches_lwd", 2) 

clust <- cutree(dend, k = 5) 
colors <- labels_colors(dend)[clust %>% sort %>% names] 
clust_labs <- colors %>% unique 

circlize_dendrogram(dend) 
grid.circle(x = .95, y = .9, r = .02, gp = gpar(fill = clust_labs[1])) 
grid.circle(x = .95, y = .85, r = .02, gp = gpar(fill = clust_labs[2])) 
grid.circle(x = .95, y = .8, r = .02, gp = gpar(fill = clust_labs[3])) 
grid.circle(x = .95, y = .75, r = .02, gp = gpar(fill = clust_labs[4])) 
grid.circle(x = .95, y = .7, r = .02, gp = gpar(fill = clust_labs[5])) 

grid.text(x = .95, y = .9, label = expression(bold(1)), gp = gpar(fontsize = 9, col = "white")) 
grid.text(x = .95, y = .85, label = expression(bold(2)), gp = gpar(fontsize = 9, col = "white")) 
grid.text(x = .95, y = .8, label = expression(bold(3)), gp = gpar(fontsize = 9, col = "white")) 
grid.text(x = .95, y = .75, label = expression(bold(4)), gp = gpar(fontsize = 9, col = "white")) 
grid.text(x = .95, y = .7, label = expression(bold(5)), gp = gpar(fontsize = 9, col = "white")) 
grid.text(x = .91, y = .8, label = "CLUSTERS", rot = 90, gp = gpar(fontsize = 9)) 

enter image description here