过去说complexheatmap太复杂,是我太菜了

写在前面

之前曾抱怨过complexheatmap太复杂了,现在我想说是我太菜了。折腾了一圈complexheatmap后,发现complexheatmap真的是极致全面的一个热图包了。

TidyTuesday

如果你想入门R或者python,但是没有数据给你折腾而发愁。那么我推荐你去看看TidyTueday。点这里

TT

每周二一个新的数据包,覆盖各种类型。比如今天我们折腾的数据就是来自TidyTuesday。想要获取数据非常简单,只需要安装TidyTuesday的包。

install.packages("tidytuesdayR")

首先读入需要的包。

#Loading necessary packages
library(tidytuesdayR)
library(tidyverse)
library(DataExplorer) # easy way for data exploring

然后

# Import data from tidytuesday
tuesdata <- tidytuesdayR::tt_load('2020-09-01')
# or
tuesdata <- tidytuesdayR::tt_load(2020, week = 36)
--- Compiling #TidyTuesday Information for 2020-09-01 ----
--- There are 5 files available ---
--- Starting Download ---

    Downloading file 1 of 5: `arable_land_pin.csv`
    Downloading file 2 of 5: `cereal_crop_yield_vs_fertilizer_application.csv`
    Downloading file 3 of 5: `cereal_yields_vs_tractor_inputs_in_agriculture.csv`
    Downloading file 4 of 5: `key_crop_yields.csv`
    Downloading file 5 of 5: `land_use_vs_yield_change_in_cereal_production.csv`

--- Download complete ---

当然,具体请考虑自己的网速。因为数据保存在github上……

数据可视化

key_crop_yields <- tuesdata$key_crop_yields

key_crop_yields %>%
  filter(Code != ""& Entity != "World") %>% 
  select(-(2)) %>% 
  create_report(
    config = configure_report(
      add_plot_bar = FALSE
    )
  )

这次使用DataExplorer自动生成报告,当然你可以通过函数查看更具体的内容。

key_crop_yields %>%
  filter(
    Entity %in% c(
      "Japan",
      "China",
      "United States",
      "Brazil",
      "Indonesia",
      "India",
      "Pakistan",
      "Nigeria",
      "Bangladesh",
      "Russia",
      "Mexico"
    )
  ) %>%
  select(-(2)) %>%
  mutate(Year = as.factor(Year),
         Entity = as.factor(Entity)) %>% plot_boxplot(by = c("Year"))
  

可可的产量很有意思啊。
或者

key_crop_yields %>%
  drop_na() %>% 
  filter(Code != "" & Entity != "World" & Year == 2018) %>%
  select(-(1:3)) %>% 
  plot_correlation(type = "c")

当然,也能用ggplot2

key_crop_yields %>%
  filter(
    Entity %in% c(
      "Japan",
      "China",
      "United States",
      "Brazil",
      "Indonesia",
      "India",
      "Pakistan",
      "Nigeria",
      "Bangladesh",
      "Russia",
      "Mexico"
    )
  ) %>%
  ggplot(., aes(x = Year, y = `Wheat (tonnes per hectare)`, color = Entity)) +
  geom_point(size = .1) +
  geom_smooth(method = 'lm') +
  theme_bw()

尼日利亚的小麦产量居然是下降的,听说他们主粮是一种豆子。中国小麦公顷产增长超级快,那么中国小麦公顷产达到世界前列了么?一张热图告诉你。
注:这里选择的是人口前11的国家。

世界小麦公顷产量热图

hmmm 看来不是…… 什么你问热图怎么做的?complexheatmap 啊!
代码具体参考kevinblighe/E-MTAB-6141: Data from Lewis, Barnes, Blighe et al., Cell Rep. 2019 Aug 27; 28(9): 2455–2470.e5. (github.com)

#载入包
require(RColorBrewer)
require(ComplexHeatmap)
require(circlize)
require(cluster)
require(countrycode)

然后整理一下数据

set.seed(2021)
yield_heatmap <- key_crop_yields %>%
  filter(!is.na(Code)) %>%
  select(Entity, Year, `Wheat (tonnes per hectare)`) %>%
  spread(Year, `Wheat (tonnes per hectare)`) %>% 
  filter(Entity != "World") %>% 
  column_to_rownames(var = "Entity") %>% 
  drop_na()

key_crop_yields %>% 
  filter(str_detect(Entity,"Sudan")) %>% 
  select(Entity, Year, `Wheat (tonnes per hectare)`) %>% 
  drop_na() %>% 
  mutate(Entity = "Sudan") %>% 
  arrange(Year) %>% 
  spread(Year, `Wheat (tonnes per hectare)`) %>% 
  column_to_rownames(var = "Entity") %>% 
  bind_rows(yield_heatmap) -> heat

上面做了两件事,一个是把数据里各种大洲和世界数据去掉了,另一个就是把苏丹数据跟前苏丹的数据合并了。
注:这里指的是Entity不是Country,防杠还是去掉了一些有争议的地区。

然后joint一下地理信息,后来发现起始直接通过Code就能获得准确信息了……以后说吧。

rownames(heat) %>% data.frame(country = .) -> df
df$Continent <-  countrycode(sourcevar = df[, "country"],
                             origin = "country.name",
                             destination = "continent")

接下来是定义五大洲板块的色块注释。

ann <- data.frame(Continent = df$Continent,
                  row.names = df$country,
                  stringsAsFactors =  FALSE)
colours <- list(
  Continent = c('Africa' = '#2171B5', 'Asia' = '#6A51A3', 'Europe' = 'red2', 'Americas' = 'green3', 'Oceania' = 'orange')
)

colAnn <- HeatmapAnnotation(
  df = ann,
  which = 'row', # 'col' (samples) or 'row' (gene) annotation?
  col = colours,
  annotation_height = 0.6,
  annotation_width = unit(1, 'cm'),
  gap = unit(1, 'mm'),
  annotation_legend_param = list(
    Continent = list(
      nrow = 5,
      title = 'Continent',
      title_position = 'topcenter',
      legend_direction = 'vertical',
      title_gp = gpar(fontsize = 12, fontface = 'bold'),
      labels_gp = gpar(fontsize = 12, fontface = 'bold'))
  )
)

顶部的箱线图注释

pick.col <- brewer.pal(5, 'Greens')
boxplotCol <- HeatmapAnnotation(
    Average = anno_boxplot(
      heat,
      border = FALSE,
      gp = gpar(fill = colorRampPalette(pick.col)(length(1:58))),
      pch = '.',
      size = unit(2, 'mm'),
      axis = TRUE,
      axis_param = list(
        gp = gpar(fontsize = 12),
        side = 'left')),
      annotation_width = unit(c(2.0), 'cm'),
      which = 'col')

然后是顶部线图的注释

heat_anno <- HeatmapAnnotation(
    Average = anno_lines(
      apply(heat, 2, mean),
      border = TRUE,
      gp = gpar(col = "red2"),
      size = unit(2, 'mm'),
      axis = TRUE,
      axis_param = list(
        gp = gpar(fontsize = 10),
        side = 'left')),
    Distribution = anno_boxplot(
      heat,
      border = FALSE,
      gp = gpar(fill = colorRampPalette(pick.col)(length(1:58))),
      pch = '.',
      size = unit(2, 'mm'),
      axis = TRUE,
      axis_param = list(
        gp = gpar(fontsize = 12),
        side = 'left')),
      annotation_width = unit(c(2.0), 'cm'),
      which = 'col')

当然你也可以换成柱状图

barplotCol <- HeatmapAnnotation(
    Average = anno_barplot(
      apply(heat, 2, mean),
      border = TRUE,
      gp = gpar(fill = colorRampPalette(pick.col)(length(1:58))),
      size = unit(2, 'mm'),
      axis = TRUE,
      axis_param = list(
        gp = gpar(fontsize = 12),
        side = 'left')),
      annotation_width = unit(c(2.0), 'cm'),
      which = 'col')

然后开始画图热图吧
说个题外话,如果你对魔改complexheatmap有兴趣,强烈建议看看这儿
ComplexHeatmap Complete Reference (jokergoo.github.io)
虽然看的人想喊师傅别念了别念了……

myCol <- colorRampPalette(c('dodgerblue', 'black', 'yellow'))(100) #三色
myBreaks <- seq(1, 8, length.out = 100)  #设置色彩范围
pamClusters <- cluster::pam(heat, k = 5) #设置聚类数

Heatmap(
  heat,
  name = 'Wheat
  (tonnes per hectare)', 
  col = colorRamp2(myBreaks, myCol), #这个颜色设定值得学习,做出来很高级
  row_split = factor(pamClusters$clustering, levels = c(5,4,3,1,2)),  #聚类排序,
  cluster_row_slices = FALSE, #不解释,自己看manual
  heatmap_legend_param = list( #设置标签
    color_bar = 'continuous',
    legend_direction = 'vertical',
    legend_width = unit(8, 'cm'),
    legend_height = unit(5.0, 'cm'),
    title_position = 'topcenter',
    title_gp = gpar(fontsize = 12, fontface = 'bold'),
    labels_gp = gpar(fontsize = 12, fontface = 'bold')
  ),
  # row parameters
  cluster_rows = TRUE, #聚类
  show_row_dend = TRUE, #显示聚类
  row_title = "Cluster",
  row_title_gp = gpar(fontsize = 10,  fontface = 'bold'), #字号,粗体
  row_title_rot = 90, 
  show_row_names = TRUE,
  row_names_gp = gpar(fontsize = 10, fontface = 'bold'),
  row_names_side = 'right',
  row_dend_width = unit(25, 'mm'),
  
  # column parameters
  cluster_columns = FALSE,
  column_title = 'Year',
  column_title_side = 'bottom',
  column_title_gp = gpar(fontsize = 10, fontface = 'bold'),
  column_title_rot = 0,
  show_column_names = TRUE,
  column_names_gp = gpar(fontsize = 10, fontface = 'bold'),
  column_names_max_height = unit(10, 'cm'),
  column_dend_height = unit(25, 'mm'),
  # cluster methods for rows and columns
  clustering_distance_rows = function(m) dist(m),
  row_dend_reorder = T,
  clustering_method_rows = 'ward.D2',
  top_annotation = heat_anno,
  right_annotation = colAnn
) -> heat_map
heat_map

是不是很简单呢!做完我都不记得那些参数是干嘛的了……
那么有没有简单的办法呢!有个低配版,效果嘛……

yield_mean <- apply(heat, 2, mean) %>% data.frame(average = .) %>% mutate(year = rownames(.))

heat %>%
  mutate(country = rownames(.)) %>%
  left_join(., df, by = "country") %>%
  gather(year, yield, -country, -Continent ) %>%
  left_join(., yield_mean, by = "year") %>%
  as.tibble() %>%
  tidyHeatmap::heatmap(country, year, yield,
                       cluster_columns = FALSE,
                       .scale = "none",
                       transform = NULL) %>%
  tidyHeatmap::add_tile(Continent) %>%
  tidyHeatmap::add_bar(average)

怎么说呢,又不是不能用!


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容