← 返回 Tessera
构成2 张图economy_countries(Tessera Toy,2023 年 GDP 最高的 10 个经济体)2026-04-13

treemap

总量由哪些类别构成,而且这些类别还分属哪些上层分组?

需要的输入
1 个分类变量 + 1 个非负数值变量(可选:再加 1 个分组变量)
示例数据
economy_countries(Tessera Toy,2023 年 GDP 最高的 10 个经济体)
依赖
treemapify · ggplot2 · dplyr · biopalette
配色
babel#1688A7 #7673AE #B3DE69 #D195F6 #FF9E81 #EF5276 #FD7915 #FEC718 #E43EC1 #FFE4B5
成图预览另有 1 张在配方里
treemap

什么时候用它

条形图更适合精确比较,因为人对长度的判断远比对面积准。treemap 的价值不在于替代条形图,而在于把部分—整体关系塞进一个紧凑矩形,并且可以再用空间嵌套表达一层分组。

因此它最适合回答:“总量主要由谁构成?这些成员又归在哪几个组里?”如果问题只是“第一名比第二名多多少”,请用排序条形图。

怎么读

  1. 先找最大的几块。 它们通常已经解释了大部分总量。
  2. 只比较明显的面积差。 两块接近时,读标签里的数值,不要靠眼睛硬判。
  3. 再看颜色和分组边界。 扁平版中每个国家有自己的颜色;分层版中同一区域统一颜色,细外框进一步说明空间层级。
  4. 最后看小块。 标签消失不是数据消失,而是那块空间不足以容纳可读文字。

常见陷阱

  • 面积不适合精确比较。 这是视觉编码本身的限制,调布局算法也不能解决。
  • 数据必须能相加。 比率、均值和可能为负的数通常不该直接拿来切面积;这里用 GDP 总量,而不是人均 GDP。
  • 不要让颜色重复编码大小。 面积已经表示 GDP;这里的颜色只保持国家身份,不再附带连续数值含义。
  • 分组标题很容易压住叶节点标签。 地区名应该小而克制,不能像旧式 treemap 那样自动长到塞满整组。
  • 矩形位置不是稳定编码。 数据、排序或画布比例一变,布局就会重排;不要在正文里写“左上角那块”。
  • 标签依赖最终画布尺寸。 min.size 以 pt 为单位,导出尺寸缩小后,一些标签会被自动省略。

配色

两张图回答的问题不同,因此不强行共用一种颜色逻辑。

  • 扁平版把国家当作阅读单位,使用能容纳较多类别的 babel,十个国家各有一种颜色。
  • 分层版把地区当作阅读单位,改用 walter_white2;同一区域统一颜色,再由细外框强化层级。

两套填充都降低透明度,让颜色与纸白背景混合,避免大矩形过于刺激。国家名已经直接标在块内,因此不再重复放十项图例;分层版的地区名也直接写在区域角落。

配方

方法绘图系统什么时候选它
A扁平 treemapggplot2(treemapify 扩展)主要比较类别份额,分组只是辅助识别
B分层 treemapggplot2(treemapify 扩展)要先看组与组,再看组内由谁构成

数据准备

不手写“看起来像真的”数字。直接读取 Tessera 的 economy_countries Toy,取 2023 年 GDP 最高的 10 个经济体;标签统一换算成万亿美元。Top 10 也给每个标签留下足够空间,不为了多塞两块而牺牲可读性。

library(dplyr)
library(ggplot2)
library(treemapify)
library(biopalette)

economy <- read.csv(
  "content/tessera/data/csv/economy_countries.csv",
  check.names = FALSE
)

plot_data <- economy |>
  filter(year == 2023, !is.na(gdp_usd), gdp_usd > 0) |>
  slice_max(gdp_usd, n = 10, with_ties = FALSE) |>
  mutate(
    country_label = recode(
      country,
      "Russian Federation" = "Russia",
      "Korea" = "South Korea",
      .default = country
    ),
    label = paste0(country_label, "\n", sprintf("$%.1fT", gdp_usd / 1e12))
  )

# 显式固定地区顺序,保证分层版的空间组织可复现。
region_levels <- c(
  "North America",
  "East Asia & Pacific",
  "Europe & Central Asia",
  "South Asia",
  "Latin America & Caribbean"
)

plot_data <- plot_data |>
  mutate(region = factor(region, levels = region_levels)) |>
  arrange(desc(gdp_usd))

# 每个国家固定一种颜色;命名映射不受后续排序和分组影响。
country_colors <- setNames(
  get_palette("babel", type = "qualitative")[c(1, 2, 3, 4, 8, 9, 11, 12, 13, 20)],
  plot_data$country_label
)

region_colors <- setNames(
  get_palette("walter_white2", type = "qualitative"),
  region_levels
)

PAPER <- "#F4F3EE"
INK   <- "#353531"

方法 A · 扁平 treemap

这一版不建立空间层级。所有国家在同一层比较,每个国家使用不同颜色;国家名已经直接标在矩形中,因此不再重复放置图例。

#| fig: basic
#| fig-width: 8
#| fig-height: 6
ggplot(plot_data, aes(area = gdp_usd, fill = country_label, label = label)) +
  geom_treemap(
    colour = PAPER,
    linewidth = 1.1,
    alpha = 0.62,
    start = "topleft"
  ) +
  geom_treemap_text(
    colour = INK,
    place = "centre",
    grow = FALSE,
    reflow = TRUE,
    size = 9,
    min.size = 5.5,
    padding.x = grid::unit(2.4, "mm"),
    padding.y = grid::unit(2.4, "mm"),
    start = "topleft"
  ) +
  scale_fill_manual(values = country_colors, guide = "none") +
  labs(
    title = "The world’s largest economies",
    subtitle = "Area shows 2023 GDP; each country keeps its own color",
    caption = "Source: Tessera economy_countries toy · current US$"
  ) +
  theme_void(base_size = 12) +
  theme(
    plot.title = element_text(
      colour = INK, size = 17, face = "bold", hjust = 0,
      margin = margin(b = 4)
    ),
    plot.subtitle = element_text(
      colour = INK, size = 10.5, hjust = 0,
      margin = margin(b = 12)
    ),
    plot.caption = element_text(colour = INK, size = 8.5, hjust = 1),
    plot.margin = margin(16, 18, 12, 18),
    plot.background = element_rect(fill = PAPER, colour = NA),
    panel.background = element_rect(fill = PAPER, colour = NA)
  )
treemap — basic
treemap-basic

方法 B · 分层 treemap

把地区同时映射到 fillsubgroup:同地区国家会先被装进同一个大矩形,并共享 walter_white2 中的一种颜色。细灰框和角落小标题只补充层级,不压过面积与国家标签。

#| fig: grouped
#| fig-width: 8
#| fig-height: 6
ggplot(
  plot_data,
  aes(
    area = gdp_usd,
    fill = region,
    label = label,
    subgroup = region
  )
) +
  geom_treemap(
    colour = PAPER,
    linewidth = 0.8,
    alpha = 0.72,
    start = "topleft"
  ) +
  geom_treemap_subgroup_border(
    colour = "#77776F",
    size = 0.35,
    start = "topleft"
  ) +
  geom_treemap_text(
    aes(angle = if_else(country_label == "Canada", 90, 0)),
    colour = INK,
    place = "centre",
    grow = FALSE,
    reflow = TRUE,
    size = 8.4,
    min.size = 5.2,
    padding.x = grid::unit(1.1, "mm"),
    padding.y = grid::unit(2.4, "mm"),
    start = "topleft"
  ) +
  geom_treemap_subgroup_text(
    aes(label = region),
    colour = INK,
    place = "topleft",
    grow = FALSE,
    reflow = TRUE,
    size = 6,
    min.size = 4.8,
    fontface = "bold",
    padding.x = grid::unit(2.2, "mm"),
    padding.y = grid::unit(1.8, "mm"),
    start = "topleft"
  ) +
  scale_fill_manual(values = region_colors, guide = "none") +
  labs(
    title = "The same economies, nested by region",
    subtitle = "Fine outlines group countries by World Bank region",
    caption = "Source: Tessera economy_countries toy · current US$"
  ) +
  theme_void(base_size = 12) +
  theme(
    plot.title = element_text(
      colour = INK, size = 17, face = "bold", hjust = 0,
      margin = margin(b = 4)
    ),
    plot.subtitle = element_text(
      colour = INK, size = 10.5, hjust = 0,
      margin = margin(b = 12)
    ),
    plot.caption = element_text(colour = INK, size = 8.5, hjust = 1),
    plot.margin = margin(16, 18, 12, 18),
    plot.background = element_rect(fill = PAPER, colour = NA),
    panel.background = element_rect(fill = PAPER, colour = NA)
  )
treemap — grouped
treemap-grouped

两种方法怎么选

  1. 要快速比较国家份额 → A。它只保留一层面积关系,空间最干净。
  2. 地区总量本身也是结论 → B。先形成地区容器,再在容器内切国家,层级才是数据结构而不是装饰。
  3. 需要精确排序或比较接近值 → 两种都不要选,改用排序条形图。
运行环境5 个包 · 2026-08-12T13:43:58.454+0800

R version 4.5.1 (2025-06-13 ucrt) · x86_64-w64-mingw32

  • biopalette 0.1.0
  • dplyr 1.2.1
  • ggplot2 4.0.3
  • grid 4.5.1
  • treemapify 2.5.6