R语言原生管道绘图
前言
最近写论文的时候又一次用到了R。这次我是对Java有一定程度了解后再次转向R,才真正认识到R这门语言在统计编程和数据可视化领域的优雅和快速。
首先可以看一段Java的stream代码:
redisUtils.opsForHashValues(Const.COOP_PREFIX.getInfo() + msg.getBlogId(), msg.getFromId().toString()).stream().
map(userStr -> redisUtils.readValue(userStr, UserEntityVo.class)).
filter(user -> !fromId.equals(user.getId())).
forEach(user -> {
msg.setToOne(user.getId());
rabbitTemplate.convertAndSend(
CoopRabbitConfig.WS_TOPIC_EXCHANGE,
CoopRabbitConfig.WS_BINDING_KEY + user.getServerMark(),
msg);
});
这段代码大概就是将缓存的数据读取出来,反序列化成Java的对象,然后进行筛选,然后把筛选出的每个对象做一次消息的发送。在这里"->"这个箭头就是Java的lambda表达式,它支持了Java的函数式编程。这和R有什么关系呢?
函数式编程往往是和链式调用结合的,能让代码可读性得到增强。在些R的画图案例之前,先执行这段R代码:
c('tidyverse', 'stargazer', 'plm', 'sandwich', 'lmtest', 'ggpubr', 'showtext', 'rticles',
'maps', 'see','bookdown') |>
lapply(\(pkg) {
if (system.file(package = pkg) == '') {
install.packages(pkg)
}
library(pkg, character.only = TRUE)
})
这里把lapply()这个base R的函数换成purrr::map()也是可以的(我发现Hadley Wickham似乎有某种代码洁癖喜欢重写很多本来可以将就用的api)。这段逻辑也很简单,构造一个数组,数组里是一些R的常用包,对于这些包依次迭代(依次就是lapply函数的作用),对于已经安装的就加载,没有安装的就安装后加载。这里的"|>"就是R官方native的管道符号,是最近R 4.1.0更新加入的。通过"|>"可以将数组传入到lapply函数的第一个参数位置,第一个参数由此就可以省略了。lapply函数第二个参数是一个FUN,也就是一个函数,这里直接传入了一个匿名函数,去判断系统安装这个包没。从这里也能看出R和Java的异同:Java不管是任何方法都不可能直接将一个方法作为方法的参数,只能通过匿名实现类这种方式模拟出函数式编程的效果,而R这种函数式语言当然是可以的,现在的新语言比如Golang也是可以直接往函数里传一个函数的。尽管在R4.1.0以前,"|>"一般是被magrittr这个第三方库使用"%>%"去实现,但是我相信大多数人写这段代码时都会写成:
lapply(c('tidyverse', 'stargazer', 'plm', 'sandwich', 'lmtest', 'ggpubr', 'showtext', 'rticles', 'maps', 'see','bookdown'), function(pkg) {
if (system.file(package = pkg) == '') {
install.packages(pkg)
}
library(pkg, character.only = TRUE)
showtext_auto()
})
从上面这段代码看不到任何函数式编程的感觉,或者说没有了管道符号的加持代码显得不美。不过这也是没办法的事情,因为R原生就不支持lambda风格的管道符,但是为了写一些基于base R的代码就把magrittr这个包导进来显得很狼狈。可以说R 4.1.0推出的"|>"符号会大幅度优美化这个语言。
绘图代码
使用R绘图,如果不出意外应该还是基于ggplot2去作图,除了初学者以外现在国际主流应该是不推荐使用诸如plot(data, x, y)这种函数了。在绘图前一般需要对数据进行处理,基于函数式编程当然是使用dplyr。
直接画图
例如我需要画一幅折线图,其中这张图有三条折线,三条折线都是来源与这张表的三个变量,需要三个变量随时间的变化趋势:
表格类似于这个样子:
Year | HighTech | HighLab | HighCap |
---|---|---|---|
1998 | 48.37 | 32.96 | 29.26 |
1999 | 51.84 | 31.74 | 32.06 |
2000 | 55.57 | 29.61 | 36.55 |
2001 | 55.82 | 30.59 | 36.91 |
代码为:
read_csv("data/tech-lab.csv") |>
ggplot() +
geom_line(aes(Year, HighTech / 100, col = "高技术人力密集度")) +
geom_line(aes(Year, HighLab / 100, col = "高劳力密集度")) +
geom_line(aes(Year, HighCap / 100, col = "高资本密集度")) +
ylab("百分位点") +
xlab("年份") +
scale_y_continuous(labels = scales::percent) +
scale_x_continuous(breaks = seq(1998, 2021, 3)) +
labs(col = "类型")
这里我将"%>%"替换成了"|>",这两者当然是有区别的,但是现在不推荐写"%>%"了。实际上purrr官网已经不推荐写"%>%"管道符,它注定会逐渐退出历史舞台。首先通过read_csv()将磁盘的文件读入内存,然后用"|>"传递给ggplot()的第一个参数,所以ggplot()也就可以空参了。每一个geom_line()函数其实就是一个图层,熟悉ps应该了解这个概念。三个geom_line()其实就是三个图层叠加在一起。aes()中需要指定x轴和y轴放什么变量,col其实是colour的缩写(也可以是color的缩写),ylab和xlab指定了横坐标和纵坐标,scale_y_continuous和scale_x_continuous指定y轴和x轴显示规则,最终生成的图片如下:
数据处理后画图
当然很多时候我们可能希望玩的更优雅一些,能不能先加工一波数据然后再画图,其实也是一样的道理:
State | Export | Inport | FDI | Year |
---|---|---|---|---|
A国 | 48.37 | 32.96 | 29.26 | 1999 |
B国 | 51.84 | 31.74 | 32.06 | 2000 |
C国 | 55.57 | 29.61 | 36.55 | 2001 |
D国 | 55.82 | 30.59 | 36.91 | 2002 |
data |>
filter(State %in% ASEAN, !is.na(Export), !is.na(Inport), !is.na(FDI)) |>
select(State, Export, Inport, FDI, Year) |>
group_by(Year) |>
mutate(expSum = sum(Export), inpSum = sum(Inport), fdiSum = sum(FDI)) |>
ggplot() +
geom_line(aes(Year, expSum, col = '进口')) +
geom_line(aes(Year, inpSum, col = '出口')) +
geom_line(aes(Year, fdiSum, col = '投资')) +
ylab("数额(千美元)") +
xlab("年份") +
scale_x_continuous(breaks = seq(1981, 2019, 3)) +
labs(col = "地区")
这里希望画一幅东协国家进口、出口和投资的数额随年份变化的时间序列图。于是首先将数据data使用"|>"传入到filter()的第一个参数,后面的参数就指定筛选规则:国家在东协且三个核心变量不为缺失值。然后选取State, Export, Inport, FDI, Year这几列,其他列在这幅图不考虑,然后根据年份group_by()分组,然后使用mutate()将每年的总进口、出口、和投资生成三个新的变量列。这一步做完,其实新列每个国家都是相同的,理论上我们只需要挑选出东协任意国再进行绘图。但是ggplot不需要显式处理这步,它自己会帮你做了。接下来将数据传下去让ggplot()绘图。这里看出每一步都使用"|>"的效果就是每一个函数的第一个参数都不需要写,非常的优雅。图片如下:
画个地图
有时候也希望玩一些高级操作,比如画个地图。画地图有个坑就是地图本质是依赖经纬度数据,一定要注意这个地图的经纬度数据有没有问题(一些众所周知的担忧)。
world <- map_data("world") |>
filter(region != "Antarctica")
data1993 <- data |>
filter(Year == 1993, !is.na(Export)) |>
select(State, Export, Year) |>
mutate(百分比 = (Export / sum(Export)) * 100)
data2016 <- data |>
filter(Year == 2016, !is.na(Export)) |>
select(State, Export, Year) |>
mutate(百分比 = (Export / sum(Export)) * 100)
data2016 <- data2016 |>
filter(data2016$State %in% data1993$State)
data1993 <- data1993 |>
filter(data1993$State %in% data2016$State)
suppressMessages(bind_cols(data1993$State, data2016$百分比 - data1993$百分比)) |>
rename(地区 = ...1, 百分比变动 = ...2) |>
ggplot(aes(map_id = 地区)) +
geom_map(aes(fill = 百分比变动), map = world) +
scale_fill_distiller(palette = "Set2",direction= 1) +
expand_limits(x = world$long, y = world$lat) +
xlab("经度") +
ylab("纬度")
这里做的并不像之前的图那么优雅,因为这个图的数据复杂一些。map_data("world")这个数据对于中国边界的经纬度数据是由一些问题的,如果要出版的话要尤为注意:
总结
由此,在R 4.1.0推出原生管道符以后,R的语法实际上已经无懈可击了。正如GraalVM也支持R一样可以看出顶级开发者对R的重视。R若仅仅是画图功能也不显得出众,结合R Markdown以后才是极大提升了生产力。我比较喜欢这种布局,将各个章节分散在不同的.rmd文件中:
---
title: ''
author:
- C
header-includes:
- \usepackage{lscape}
- \usepackage{ctex}
papersize: 'a4'
geometry: 'margin=1.75in'
keywords:
- A
- B
indent: true
output:
bookdown::pdf_document2:
latex_engine: xelatex
fig_caption: yes
number_sections: yes
toc_depth: 2
toc: yes
bibliography: bibliography.bib
---
```{r, include=FALSE}
c('tidyverse',
'stargazer',
'plm',
'sandwich',
'lmtest',
'ggpubr',
'showtext',
'rticles',
'maps',
'see',
'bookdown') |>
lapply(\(pkg) {
if (system.file(package = pkg) == '') {
install.packages(pkg)
}
library(pkg, character.only = TRUE)
})
showtext_auto()
data <- read_csv('data/data.csv')
ASEAN <- c('Malaysia', 'Indonesia', 'Thailand', 'Philippines', 'Singapore', 'Vietnam', 'Brunei', 'Laos', 'Myanmar', 'Cambodia')
\```
```{r child = ' 00-abstract.Rmd '}
\```
\newpage
```{r child = ' 01-intro.Rmd '}
\```
\newpage
```{r child = ' 02-review.Rmd '}
\```
\newpage
# 参考文献
R语言原生管道绘图的更多相关文章
- R语言基础画图/绘图/作图
R语言基础画图/绘图/作图 R语言基础画图 R语言免费且开源,其强大和自由的画图功能,深受广大学生和可视化工作人员喜爱,这篇文章对如何使用R语言作基本的图形,如直方图,点图,饼状图以及箱线图进行简单介 ...
- 吴裕雄--天生自然 R语言数据可视化绘图(3)
par(ask=TRUE) opar <- par(no.readonly=TRUE) # record current settings # Listing 11.1 - A scatter ...
- 吴裕雄--天生自然 R语言数据可视化绘图(4)
par(ask=TRUE) # Basic scatterplot library(ggplot2) ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_poin ...
- 吴裕雄--天生自然 R语言数据可视化绘图(2)
par(ask=TRUE) opar <- par(no.readonly=TRUE) # save original parameter settings library(vcd) count ...
- 吴裕雄--天生自然 R语言数据可视化绘图(1)
par(ask=TRUE) opar <- par(no.readonly=TRUE) # make a copy of current settings attach(mtcars) # be ...
- R语言学习笔记(五)绘图(1)
R是一个惊艳的图形构建平台,这也是R语言的强大之处.本文将分享R语言简单的绘图命令. 本文所使用的数据或者来自R语言自带的数据(mtcars)或者自行创建. 首先,让我们来看一个简单例子: ...
- R语言学习笔记2——绘图
R语言提供了非常强大的图形绘制功能.下面来看一个例子: > dose <- c(20, 30, 40, 45, 60)> drugA <- c(16, 20, 27, 40, ...
- R语言笔记4--可视化
接R语言笔记3--实例1 R语言中的可视化函数分为两大类,探索性可视化(陌生数据集,不了解,需要探索里面的信息:偏重于快速,方便的工具)和解释性可视化(完全了解数据集,里面的故事需要讲解别人:偏重全面 ...
- R语言入门(一)简介安装
数据挖掘常用的语言有R语言,python,SQL等,其中R语言最受欢迎.(注:SQL Server包含微软研究院开发的两种数据挖掘算法:Microsoft决策树和Microsoft聚集,此外还支持第三 ...
- R语言putty中直接使用X11(Xming)绘图
1.下载Xming地址 http://pan.baidu.com/s/1o6ilisU,安装,推荐默认安装在C盘,推荐快捷方式放在与putty快捷方式同一个文件夹: 2.打开putty,在SSH的X1 ...
随机推荐
- exp1-Password engine-加密API实现与测试
加密API实现与测试 181210 1.准备工作 下载并查找GMT 0018-2012密码设备应用接口规范原始文档进行学习. 2.实现GMT 0018-2012接口函数 实现GMT 0018-2012 ...
- jupyter notebook 切换环境
jupyter-notebook 中切换 conda 虚拟环境 介绍 jupyter notebook是anaconda中root目录中默认的python环境,如果要使拥创建的其他环境,则需要安装 ...
- 语法——包、权限修饰符、final
一.包 1.什么是包? 包是用来分门别类的管理各种不同的类的,类似于文件夹,建包有利于程序的管理和维护. 建包的语法格式: package 公司域名倒写.技术名称.包名建议全部英文小写,且具备意义. ...
- (原创)odoo one2many字段以子列表形式显示
模块详情
- 【Pr】如何裁剪视频得页面?
[Pr]如何裁剪视频得页面? 选择视频轨道 | 效果 | 裁剪(可以搜索) | 调整上下左右需要裁剪的大小 | 选择缩放,去掉黑边
- webrtc windows编译记录
//cmd set path=D:\zzh\depot_tools;%path% set DEPOT_TOOLS_WIN_TOOLCHAIN 0 set vs2022_install=C:\Progr ...
- [Oracle19C ASM管理] ASM服务的启停
自动方式启停 crsctl stat res -t 查看ASM服务的状态,it's ok that ora.ons和ora.diskmon是OFFLINE [grid@centos7-19c.loca ...
- yaml 文件的读取写
yaml 是一种数据格式, 它可以和json数据相互转化 . 自动化测试中一般用于做配置文件或是测试用例. 数据的组成, 两种格式: 1. 字典 2. 列表 Eg. config.yaml serve ...
- 原创分享 HubbleDotNet 最新绿色版,服务端免安装,基于eaglet 最后V1.2.8.9版本开发,bug修正,支持一键生成同步表
HubbleDotNet 是一个基于.net framework 的开源免费的全文搜索数据库组件.开源协议是 Apache 2.0.HubbleDotNet提供了基于SQL的全文检索接口,使用者只需会 ...
- P标签内容过长以省略号代替
p { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }