云计算百科
云计算领域专业知识百科平台

有趣的绘图 R 包:ggsketch 手绘风

平时使用 ggplot2 绘图时,我们通常会追求线条整齐、布局规范和风格统一。但有些场景下,过于工整的图形反而显得严肃:比如课程演示、科普文章、创意报告、手账风海报,或者需要突出“草图”“讨论稿”感觉的展示材料。

最近发现了一个很有意思的 R 包——ggsketch。它可以把常见的 ggplot2 图形变成带有抖动线条、重复描边和排线填充效果的手绘图。

更重要的是,ggsketch 并不是先生成普通图形,再把图片转换成手绘效果,而是直接提供了一套原生的 ggplot2 图层函数。因此,它仍然能够正常配合 aes()、统计变换、坐标系统、分面和颜色标度使用。生成的结果也可以直接输出为 PNG、PDF 或 SVG,不依赖浏览器和 JavaScript。

github:https://github.com/orijitghosh/ggsketch

1. 安装 ggsketch

ggsketch 可以直接从 CRAN 安装:

install.packages("ggsketch")

也可以通过 pak 安装 GitHub 上的开发版本:

install.packages("pak")
pak::pak("orijitghosh/ggsketch")

加载绘图需要的包:

library(ggplot2)
library(ggsketch)

ggsketch 使用纯 R 实现,不需要编译,也不需要安装额外的 JavaScript 环境。

2. 第一个手绘柱状图

先创建一个简单的数据集:

df <- data.frame(
product = c("Alpha", "Bravo", "Charlie", "Delta"),
units = c(34, 51, 22, 47)
)

使用普通 ggplot2 绘制柱状图时,一般会使用 geom_col()。在 ggsketch 中,只需要将它替换成 geom_sketch_col():

ggplot(df, aes(product, units)) +
geom_sketch_col(
fill = "#7BAFD4",
seed = 1L
) +
labs(
title = "Units sold",
x = NULL,
y = "销量"
) +
theme_sketch()

这里有两个值得注意的地方。

第一个是 geom_sketch_col()。它对应 ggplot2 中的 geom_col(),但柱子的边框会变成略带抖动的双重描边,填充区域也可以呈现排线、涂鸦或者水彩效果。

第二个是 theme_sketch()。这个主题会对坐标轴、背景和文字等元素进行整体调整,让图形风格更加统一。

3. 手绘效果也可以复现

手绘图形通常带有随机扰动。如果每次运行代码后,线条形状都发生变化,会给论文排版、报告更新和自动化绘图带来麻烦。

ggsketch 为随机绘制过程提供了 seed 参数。相同的种子会生成相同的抖动线条,因此图形结果是可以复现的。

例如:

ggplot(df, aes(product, units)) +
geom_sketch_col(
fill = "#7BAFD4",
seed = 123
) +
theme_sketch()

也可以设置整个 R 会话的默认随机种子:

options(ggsketch.seed = 123L)

这样就不需要在每一个图层中重复设置 seed。

4. 常见图形基本都有手绘版本

ggsketch 提供的不只是柱状图。目前,它已经覆盖了大量常见的 ggplot2 图层。

折线图和散点图

geom_sketch_line()
geom_sketch_path()
geom_sketch_point()

例如:

ggplot(mtcars, aes(wt, mpg)) +
geom_sketch_point(
size = 3,
seed = 1
) +
geom_sketch_smooth(
method = "lm",
se = FALSE,
seed = 2
) +
theme_sketch()

由于这些图层仍然遵循 ggplot2 的图层语法,因此可以像普通散点图一样叠加回归线、颜色映射和分组变量。

柱状图、矩形图和棒棒糖图

geom_sketch_col()
geom_sketch_bar()
geom_sketch_rect()
geom_sketch_tile()
geom_sketch_lollipop()

分布类图形

geom_sketch_histogram()
geom_sketch_density()
geom_sketch_violin()
geom_sketch_boxplot()
geom_sketch_beeswarm()
geom_sketch_ridgeline()
geom_sketch_dotplot()
geom_sketch_ecdf()

例如,将箱线图改为手绘风格:

ggplot(mpg, aes(class, hwy)) +
geom_sketch_boxplot(
fill = "#F2C14E",
fill_style = "hachure",
seed = 1
) +
coord_flip() +
theme_sketch()

面积和区间类图形

geom_sketch_polygon()
geom_sketch_ribbon()
geom_sketch_area()
geom_sketch_smooth()

对比和变化类图形

geom_sketch_dumbbell()
geom_sketch_slope()
geom_sketch_bump()
geom_sketch_waterfall()
geom_sketch_funnel()
geom_sketch_pyramid()

此外,包中还提供了饼图、华夫饼图、树状矩形图、旭日图、雷达图、弦图、桑基类图形、甘特图、日历图、树状图以及简单的网络图和地图图层。








5. 多种手绘填充效果

手绘图的趣味性很大程度上来自填充纹理。ggsketch 的 fill_style 参数提供了多种填充方式,包括:

"hachure"
"cross_hatch"
"zigzag"
"zigzag_line"
"scribble"
"dots"
"dashed"
"stipple"
"pencil_shade"
"solid"
"watercolor"

其中:

  • hachure 是单方向排线;
  • cross_hatch 是交叉排线;
  • scribble 类似随手涂鸦;
  • dots 使用点状纹理;
  • pencil_shade 模拟铅笔阴影;
  • watercolor 模拟半透明水彩颜料。

例如,可以比较几种不同的填充方式:

ggplot(df, aes(product, units)) +
geom_sketch_col(
aes(fill = product),
fill_style = "cross_hatch",
seed = 1
) +
guides(fill = "none") +
theme_sketch()

还可以通过下面几个参数继续控制排线:

hachure_angle
hachure_gap
fill_weight

例如:

ggplot(df, aes(product, units)) +
geom_sketch_col(
fill = "#80B1D3",
fill_style = "hachure",
hachure_angle = 45,
hachure_gap = 5,
fill_weight = 1,
seed = 1
) +
theme_sketch()

6. 调整线条的“潦草程度”

ggsketch 提供了几个通用参数,用来控制手绘线条的外观。

roughness

roughness 控制线条抖动的幅度。

roughness = 0

接近用尺子画出的直线。

roughness = 1

是比较自然的默认手绘效果。

roughness = 3

会产生更加松散和夸张的草图效果。

bowing

bowing 控制线段向外弯曲的程度。数值越大,线条越不像严格的直线。

n_passes

n_passes 控制一条边被重复描绘多少次。

n_passes = 2

通常会形成经典的手绘双线效果。

综合起来,可以写成:

ggplot(df, aes(product, units)) +
geom_sketch_col(
fill = "#B3DE69",
roughness = 2,
bowing = 1.5,
n_passes = 2,
seed = 1
) +
theme_sketch()

7. 配合颜色映射和分面使用

因为 ggsketch 是按照 ggplot2 扩展机制实现的,所以仍然可以使用熟悉的美学映射:

ggplot(mpg, aes(class, fill = drv)) +
geom_sketch_bar(
position = "dodge",
seed = 1
) +
scale_fill_brewer(palette = "Set2") +
theme_sketch()

也可以进行分面:

ggplot(mpg, aes(displ, hwy, colour = drv)) +
geom_sketch_point(seed = 1) +
facet_wrap(~ year) +
theme_sketch()

这也是 ggsketch 与一些后期图片处理方案的重要区别:它生成的并不是一个无法继续修改的图片特效,而是真正参与 ggplot2 图形语法的绘图图层。

8. 添加手绘标注

除了数据图层,ggsketch 还提供了多种手绘标注函数,例如:

annotate_sketch()
geom_sketch_bracket()
annotate_sketch_arrow()
annotate_sketch_callout()
annotate_sketch_highlight()
annotate_sketch_underline()
geom_sketch_text_repel()

这些元素比较适合课程讲解、数据故事和演示文稿,因为它们能够引导读者关注图中的重点信息。

9. 不只是“抖动线条”

ggsketch 还有一个比较特别的功能:通过排线密度表现连续的明暗变化。

例如,geom_sketch_engrave() 可以根据数值大小改变线条密度,产生类似蚀刻画、版画或者纸币纹理的效果。普通的图案填充包通常是在区域内重复铺设某个固定图案,而这种方法会真正根据数值计算排线密度。

相关函数包括:

geom_sketch_engrave()
geom_sketch_shade()
scale_engrave()

对于地形表面、二维密度或需要表现连续色调的图形,这种效果会很有辨识度。

10. 保存图形

由于 ggsketch 使用 R 的原生图形系统实现,普通的 ggsave() 就可以保存结果:

p <- ggplot(df, aes(product, units)) +
geom_sketch_col(
fill = "#7BAFD4",
seed = 1
) +
theme_sketch()

ggsave(
"ggsketch_plot.png",
plot = p,
width = 8,
height = 5,
dpi = 300
)

也可以输出 PDF 或 SVG:

ggsave("ggsketch_plot.pdf", p)
ggsave("ggsketch_plot.svg", p)

包中还提供了专用的 ggsketch_save() 辅助函数。由于图形最终是原生的 grid grob,它可以在屏幕、PNG、PDF 和 SVG 等不同设备上正常绘制。

11. 哪些场景适合使用 ggsketch?

ggsketch 并不一定适合所有数据可视化场景。

在正式论文、审计报告或者强调测量精度的图表中,传统的简洁风格通常更加稳妥。但在下面这些场景中,手绘风格可能会带来不错的效果:

  • 数据分析课程和教学演示;
  • 科普文章和公众号推文;
  • 创意数据故事;
  • 工作坊或头脑风暴材料;
  • 项目早期方案和概念草图;
  • 儿童教育和轻松主题展示;
  • 希望弱化“机器生成感”的信息图。

手绘图形的价值不只是“好看”。它还可以向读者传达一种语气:这张图可能是在帮助大家理解概念、探索思路,而不是在展示一个不可质疑的最终结论。

12. 小结

ggsketch 可以看作是 ggplot2 的一套手绘图层扩展。

它的主要特点包括:

  • 直接提供原生的手绘版 geom;
  • 支持 aes()、分面、标度、统计变换和坐标系统;
  • 不依赖 JavaScript 或浏览器;
  • 可以输出 PNG、PDF 和 SVG;
  • 支持排线、交叉线、涂鸦、点状、铅笔和水彩等填充效果;
  • 可以通过随机种子保证绘图结果可复现;
  • 覆盖柱状图、折线图、散点图、分布图、地图、网络图和多种高级图表。
  • 如果已经熟悉 ggplot2,使用 ggsketch 的学习成本并不高。很多时候,只需要把:

    geom_col()

    替换为:

    geom_sketch_col()

    再加上:

    theme_sketch()

    一张普通的数据图,就能立即变成更轻松、更有故事感的手绘图。

    官方文档中还提供了各类图层的完整示例和效果展示,感兴趣的读者可以继续探索。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 有趣的绘图 R 包:ggsketch 手绘风
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!