今天的推文是个 ggplot2 案例,不过也是一个动态图表,在开始敲今天的代码之前我们先了解一下什么是“赫罗图”?
赫罗图(Hertzsprung-Russell diagram,简写为 H-R diagram 或 HRD)是丹麦天文学家赫茨普龙及由美国天文学家罗素分别于 1911 年和 1913 年各自独立提出的。后来的研究发现,这张图是研究恒星演化的重要工具,因此把这样一张图以当时两位天文学家的名字来命名,称为赫罗图。赫罗图是恒星的光谱类型与光度之关系图,赫罗图的纵轴是光度与绝对星等,而横轴则是光谱类型及恒星的表面温度,从左向右递减。恒星的光谱型通常可大致分为 O.B.A.F.G.K.M 七种,要记住这七个类型有一个简单的英文口诀 "Oh be A Fine Girl/Guy. Kiss Me!"
上面一段是我百度的。。。
这篇文章的核心代码来源于 zonination/h-r-diagram 当然我不是直接 Ctrl + C / V 把代码直接复制过了,我在作者的代码基础上进行了更正和改进。
首先可以从知识星球下载附件,附件中有本文需要的两个数据:
-
hygdata_v3-1.csv
-
hygdata_v3-2.csv
我们使用 readr 包把这两个数据集读入 R 中并使用 rbind 函数进行行连接:
setwd("~/Desktop/赫罗图")
library(tidyverse)
library(ggplot2)
# 读入数据
# 发现这个数据使用 read_csv 读取的时候有点问题,ci 和 x 变量错位了,absmag 和 spect 也错位了,所以这里我们选择 spect 和 x,然后把 x 重命名为 ci,spect 重命名为 absmag
catalog <- rbind(
read_csv("hygdata_v3-1.csv"),
read_csv("hygdata_v3-2.csv")
) %>%
select(spect, x) %>%
rename(ci = x,
absmag = spect)
通过绘制一系列带有不同透明度的静态图合成动图就可以产生星星闪耀的效果。为此,我们先生成一列随机数:
catalog$randomseed <- runif(nrow(catalog), min = 0, max = 2 * pi)

我们先绘制一幅静态图:
ggplot(catalog, aes(ci, absmag)) +
geom_point(
shape = 16,
size = 0.001,
alpha = (sin(randomseed + pi / 180)),
colour = ci
scale_x_continuous(limits = c(-0.5, 2.5)) +
scale_y_reverse() +
guides(colour = F, alpha = F) +
scale_alpha_continuous(range = c(0, 1)) +
scale_color_gradientn(
colours = c("blue", "skyblue", "white", "orange", "red"),
limits = c(-0.5, 2.5)
labs(
title = "图:赫罗图",
subtitle = "恒星的类别",
y = "绝对星等",
x = "光谱类型(B-V)"
annotate("text",
x = 0, y = 15,
label = "白矮星", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
annotate("text",
x = 1.75, y = 12,
label = "主序带", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
annotate("text",
x = 1.75, y = 0,
label = "巨星", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
annotate("text",
x = 1.75, y = -10,
label = "超巨星", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
theme_modern_rc(base_family = cnfont, grid = "") +
theme(panel.background = element_rect(fill = '#000000',
color = 'white',
size = 0.2),
plot.background = element_rect(fill = '#000000',
color = '#000000'))

突然发现我们甚至可以把这幅图制作成一幅艺术品,为此我们可以把文本、轴线等删除了:
ggplot(catalog, aes(ci, absmag)) +
geom_point(
shape = 16,
size = 0.001,
alpha = (sin(randomseed + pi / 180)),
colour = ci
scale_x_continuous(limits = c(-0.5, 2.5)) +
scale_y_reverse() +
guides(colour = F, alpha = F) +
scale_alpha_continuous(range = c(0, 1)) +
scale_color_gradientn(
colours = c("blue", "skyblue", "white", "orange", "red"),
limits = c(-0.5, 2.5)
labs(
caption = "赫罗图",
x = "", y = ""
theme_modern_rc(caption_family = cnfont, grid = "") +
theme(panel.background = element_rect(fill = '#000000',
color = '#000000',
size = 0.2),
plot.background = element_rect(fill = '#000000',
color = '#000000'),
axis.text = element_blank(),
plot.caption = element_text(hjust = 0, size = 14))
ggsave("赫罗图.png", height = 9, width = 6)

最后使用 for 循环是生成 37 张透明度不同的图片然后再合并为 GIF 图:
for (n in seq(0, 360, 10)) {
ggplot(catalog, aes(ci, absmag)) +
geom_point(
shape = 16,
size = 0.001,
alpha = (sin(randomseed + n * pi / 180)),
colour = ci
scale_x_continuous(limits = c(-0.5, 2.5)) +
scale_y_reverse() +
guides(colour = F, alpha = F) +
scale_alpha_continuous(range = c(0, 1)) +
scale_color_gradientn(
colours = c("blue", "skyblue", "white", "orange", "red"),
limits = c(-0.5, 2.5)
labs(
title = "赫罗图",
subtitle = "恒星的类别",
y = "绝对星等",
x = "光谱类型(B-V)"
annotate("text",
x = 0, y = 15,
label = "白矮星", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
annotate("text",
x = 1.75, y = 12,
label = "主序带", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
annotate("text",
x = 1.75, y = 0,
label = "巨星", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
annotate("text",
x = 1.75, y = -10,
label = "超巨星", size = 4,
hjust = 0, vjust = 0, color = "white", family = cnfont
theme_modern_rc(base_family = cnfont, grid = "") +
theme(panel.background = element_rect(fill = '#000000',
color = 'white',
size = 0.5),
plot.background = element_rect(fill = '#000000',
color = '#000000'))
ggsave(paste("star_anim", formatC(n, width = 3, flag = "0"), ".png", sep = ""), height = 9, width = 6)
print(paste(n, "of", 360, "degrees completed."))
rm(n)