黄昏随想

黄昏,太阳很快就要下山。刚刚下过小雨,云彩仍然铺满天际。一片连一片,你中有我,我有中有你,每一片都水汪汪的。

太阳努力散发着一天里最后的光辉,整个天空都涂上了淡淡的橘红色。

底层的云彩,走得最快,也最柔软,阳光正好投射到上面,于是就披上了橘红色的盛装。上层的云彩厚些,阳光很难穿透,就有意无意变成了深蓝色的幕布。橘红的云彩就在这幕布前翩翩起舞,如蝴蝶,如燕子……一霎时,又飘散得无影无踪。

我赶忙拿起手机拍摄,可效果却总是差强人意:不是曝光过度,云彩由橙色变成白色,白得平平淡淡;要么就是曝光严重不足,仿佛云彩已经变成深蓝;要么偏色严重,鲜亮的橘红色变成了柿子黄。也许,此情此景,真的只能亲眼见到才能留在心中,再没有其他方式可以挽留。

这样的光景不过几分钟,云彩忽然变得黯淡无光。

东边的天空升起来一道彩虹。这是一道不完美的彩虹:她很短,很宽,比平常的宽一倍还多,颜色也很淡,不留意的话,根本不能发现。也许,是太阳的余晖不足以把她点亮;也许,黄昏的云彩再也不能给它足够的活力。等待她的,只是深沉的夜色。

确实,来去匆匆的人们,除了我,仿佛谁也没有发现这道彩虹。

或许,彩虹对于人,人对于彩虹,都不重要,也许这就是“相濡以沫,不如相忘于江湖”。对啊,相忘于江湖,彩虹对于人,也正如天空之于人,人之于天空:彩虹也本来只是天空中的一种物件而已,互相之间都不重要,也根本没有什么关系。

在这座城,高耸入云的大厦已经把天空蚕食殆尽;污浊的空气,总是模糊了双眼;智能手机让人低头;电脑,更是把人捆绑在屏幕前……仰望天空,这种最原始的存在,居然让人既熟悉,又陌生。

我停下来,凝望着彩虹,转过头来,呆呆看着天上的云彩。路人不断回头看我。

一只白鹭飞过,展开的翅膀划出完美的弧线。黄昏,它回家了,飞行的踪迹也成了天空的一部分。

我停下了脚步,云彩也停下了。也许,我想说的,就都留在心里;云彩想说的,就都留在天上……或许,云彩有时候会不小心,会让想说的话落在大地上,以安抚我们受伤的心,也滋润太阳炙烤许久的大地。

此时此刻,我不应该在香港,而应该躺在大草原上,抬头看那彩云起舞,欣赏着哪怕是最不完美的彩虹。仰望着天空,小雨滴轻轻打在脸上,云彩渐渐消逝,也许之后是繁星满天……

唉,雨过并不总是天晴,雨过总该天晴。

2019年6月20日凌晨

herblabel 0.9.2 整合《中国生物物种名录2019》的植物接受名

用于打印植物标本标签的herblabel程序包(张金龙等(2016))已经升级到0.9.2,以下是一些新特性:

  1. 整合了《中国生物物种名录2019》(http://www.sp2000.org.cn/2019)中植物的接受名及对应的中文名,放入新增的数据集colcn2019中。该数据集中大约有100个左右的中文名对应两个接受的学名,使用时请注意。

  2. 加入了数据集genera_cn,该数据集包括目前所有有中文名的高等植物属名。该数据集主要参考刘冰等(2015)的被子植物科属名称以及多识植物百科(2019)的苔藓、蕨类、裸子植物属名。

  3. fill_dwc函数,现可以依据colcn2019数据库中的中文匹配出学名,并将属、种、命名人等信息自动填写到herblabel自带的darwin code模版中,使用时,设定fill_dwc的参数为 namedb=”colcn2019”即可。

  4. fill_dwc在匹配任何一个数据库时,如spfoc, spfrps, colcn2019, 都加入genera_cn一起匹配,这是因为有些种类打印标签时可能只能鉴定到属。

  5. herbarium-label和annotation-label在核对接受名时,除了用原有的plantlist1.1的接受名检查之外,还加入了foc(Flora of China)、frps(《中国植物志》)、colcn2019(《中国生物物种名录》2019)的接受名,若输入的拉丁文在上述库中都找不到,会在输出为RTF文件时提示。

  6. run-herblabel脚本(https://github.com/helixcn/run_herblabel),建议使用colcn2019数据框填写标签模版,以colcn2019中的中文名提取拉丁名。

  7. 请使用 devtools::install_github(“helixcn/herblabel”) ,以更新到新版本0.9.2。

参考:

  1. 张金龙, 朱慧玲, 刘金刚, Gunter A. Fischer (2016) 植物标本标签设计的原则及R程序包herblabel. 生物多样性, 24(12), 1345-1352.

  2. 刘冰, 叶建飞, 刘夙, 汪远, 杨永, 赖阳均, 曾刚, 林秦文 (2015) 中国被子植物科属概览: 依据APG III系统. 生物多样性, 23(2), 225-231.

孤独的清洁车


一部小小的清洁车

缓缓前行

清扫着尘世上所有的污浊

也消耗着清洁工宝贵的时间


两千五百年的古城

车水马龙的马路上

一架孤独的清洁车

还有孤独的清洁工

正在孤独行走


这一瞬

也许并不是偶然


一年里最热的一天

站在街头

汗水流到眼里

就成了泪水


2018年7月21日,广州

在人间:小学时的流光碎影

刚刚看了一个旧课本的微信文章 《张张老课本,让你梦回校园》,主要是九十年代小学初中语文课的插图。看这些老课本插图,我好像只能想起:

1.秋天到,天气凉,菊花开,树叶黄。
2.弯弯的月亮,小小的船。小小的船儿两头尖。我在小小的船里坐,只见到闪闪的星星,蓝蓝的天。
3.黑云翻墨未遮山,白雨跳珠乱入船。卷地风来忽吹散,望湖楼下水如天。
4.昨日入城市,归来泪满巾。遍身罗绮者,不是养蚕人。

其他的能想起来的很少了。别看长在红旗下,戴着红领巾,各方面没少受熏陶,但是某些课文怎么就记不住呢?当然,看着老课本的插图,记忆确实又回到了从前,特别是小学时候。小学二年级的时候,我的第三册语文课本弄丢了,我就跟村东头的百松老叔去借,最终还没还也不记得了,这一切仿佛还在昨天。是不是都没有走远?百松的奶奶,我的老太,什么时候就不在了?那么多人,那么多事,怎么说过去就过去了呢?时间也是过得太快。

1982年,我出生在天津市宝坻县潮白河畔的一个小村庄。

小学一年级,在村里的旧罐头厂车间上课,下课后就是跟同学去玩儿”砸铁盖”,也就是罐头瓶盖。学校门口有一个很大的养鱼坑,周围的垃圾堆上还有从无数摔碎的罐头瓶。我和小伙伴们找那些瓶底有聚光功能的,用来在在阳光底下照蚂蚁,一般都是先照自己手背,试试疼不疼。

有一天晚上,刮了大风,下了一点小雨儿,第二天去上学,忽然发现教室,也就是村里的旧罐头厂车间塌了……不幸之中的万幸,如果是白天塌了的话,我就不一定能在这儿打字了。

还是一年级,有一次我的自动铅笔最前面夹铅芯儿的小铁管不见了,我怀疑有人给偷走了,就去偷别人的,最后被教我们班的李老师给揪出来了,一顿管教。当时辛亏是没叫家长,只是在同学面前向红松、红柳同学承认了错误,赔礼道歉。也幸亏被李老师管教及时,自打那以后,就再也没有偷过别人的东西,这世间应该少了一个小偷。最后一次见到李老师是在高中时回到村里,在村南头。她知道我在初中学习成绩不错,考上了县一中,看到我时特别激动,不住地说,“长大了,变了样了……”,之后不久,她就因乳腺癌去世了。那时候没能多去看看教过自己四年的小学老师,老师的那份关爱也再也无从报答,想到此处不由得让人伤心流泪。

上小学二年级的时候,学校就整个搬到新校舍了。新学校在村南边的引水渠以南。渠北面还没到村里是一个大养鱼坑,是村里一个绰号“麻回子”的人找链轨车(履带式推土机)铲出来的(其实他并不麻,而且我感觉他还很有派头,人也很帅)。

铲坑的时候我还记得。深挖三四米,甚至五六米,直到出水,从地下挖出的都是黏黏的黑土,放到路边会慢慢风化成小块。那时候流行玩儿弹弓打家雀儿,于是我用那黑土搓了很多泥球。黑土里偶尔能见到了埋了几百年,也许上千年的莲蓬子,保存地很好。砸开之后,里面的仁儿还都可以吃。坑挖好之后,路边生了很多很多摔盆儿摔碗儿(紫草科 砂引草),一放学经过就仿佛能闻到臭味。

小学流行的游戏也是一阵一阵,有时候流行“方宝”(一种纸叠的玩具),过一阵子可能就是跳皮筋,然后是跳绳,揰(chong4)球儿(投布球,球里放绿豆或玉米粒),摔(shuai2)破锅,跑城,欻(chua3)老么和(he2),踢毽(qian4)儿,玩儿鸡毛蒜皮(又称天下太平),钓骆驼(用莎草的葶秆去喂土里一种小虫,小虫咬着不放,就可以将其拉出来,因虫子后背有凸起,故名骆驼),一直到四年级时才见过足球,五年级才见过乒乓球。

放学了就去抓蚂蛉(蜻蜓),抓马嘎(黑蚱蝉),叫狗儿(蒙古寒蝉),一般是用铁弹(粗铁丝)围(wei1)个圈,然后找新鲜的蛛蛛(蜘蛛)网,绕到铁圈上,最后密密麻麻,绕了一层又一层。卷蜘蛛网的时候蜘蛛只能落荒而逃,肯定恨死我们了。后来有人将塑料袋子缝在铁圈上,罩各种昆虫,效果也还不错。铁圈都是插或者绑在高粱秸上,很轻,一般来说也都很应手。

最有意思的也许是暑假去看瓜。

家里种的是菜瓜,有稍(shao2)瓜,又叫青皮瓜,面瓜,甜瓜,醋丛瓜(长相类似甜瓜,但是长很多,微酸),都是种在潮白河的河滩里面,那里地势低洼,虽然是沙土,但地里水分充足,排水也好,瓜长得好。

瓜当然是刚下来的时候好吃,一开始的时候雨水少,瓜又香又甜。怎么知道瓜熟没熟呢?面瓜就靠颜色,由青黑色转成黄色就是熟了。青皮瓜和甜瓜都是看最前面长花的地方,如果开始笼罩一层淡淡的银灰色,一般就是要熟了。瓜熟透了,瓜脑袋就透出沁人心脾的香味,让人一听(宝坻话中“听”就是闻,闻为书面语,听为口语)到就忍不住咬一口。

还记得坐着老妈赶的驴车,去十几里外的双王寺村卖瓜,车厢里都是摆好的青皮瓜。瓜香四溢,沁人心脾。当然,大热天的,瓜又在驴车里晃荡一天,也都熟透了。那次天公也不作美。下午两三点钟,一块黑云彩跟黑锅底一样扑上来了,风来雨就到啊,好像还下了点儿冰雹,当时没有雨衣,身上披着大塑料袋,但是还是湿透了,然后浑身发冷,牲口也浇成了落汤鸡。

潮白河来水了,也就是发洪水。因为是雨季,潮白河上游的密云水库随时肯能开闸放水,不过经过了一百多公里,洪水涨落一般比较缓慢。遭殃的就是河里的瓜,还有我们几个月的心血,从种到摆弄(打理),到收成,全都要被洪水冲走了,一切都要付之东流,也许明年要还能重来。

为了把瓜捞回来,家家户户都准备了皮轱辘,也就是充好气的汽车轮胎,大人小孩儿全家出动去捞瓜。瓜也无论大小,甜的、面的,黑的,白的,无论高矮胖瘦,全都尽快捞上来。瓜秧在水里泡两天就死了,这时候再捞的瓜就很难吃,而且随着时间的推迟,水越来越深,所以捞瓜也要趁早。

捞回来的瓜,最好的那部分除了卖到县城里,大部分还很生,于是只能腌咸菜了。甜瓜生的时候虽苦,腌好之后再晒干,苦味就消失了,吃起来还很脆。那时候上顿下顿,都是吃腌的瓜,就这样直到八月十五,才能改善一下,吃到一次肉。

生活本是各种无奈,人又很难改变自己的出身和命运,能做出改变的,都多少让人敬佩吧。

小学的时光再也不会回来了,改变了和没有改变了命运的人,都要面对人世间的困苦。

最近有朋友转了帖子,说高考完,有些人洒脱一下,认为自己离开了地狱,进入天堂,殊不知,大学以前的生活,就是在天堂。我想说,考上了九八五大学的学生,也许一开始觉得自己进入了天堂,然后才知道,其实是跌落在了人间,而有些人,一直在人间,从未离开。

谈谈信息时代的分类学家与植物名录的编纂

内容提要

近年来,智能手机逐渐普及,人们得以用手机快速拍摄并通过人工智能识别植物;智能手机和数码相机的普及导致植物照片数量迅速增加。不过,植物学家仍然需要很长时间的专业训练,才能成为田野植物学家或者类群专家。类群专家的研究更为专门化,大量使用分子系统学证据用于分类学研究。植物名录是植物志与植物检索表的重要补充,植物名录本身可能以专著的形式出版也可能是某本论文或者考察集的附录,但是已经出版的植物名录在质量上参差不齐。

在上述背景下,本文对植物名录的编纂提出了一些新的建议,包括:1. 内容准确,有标本和文献引证;2. 资料翔实;3. 结构完整、顺序合理;4.反映最新进展;5. 注意濒危种保护;6. 注意排版以方便阅读;7. 充分发挥互联网优势,充分与读者互动等。

1. 信息时代植物分类学研究的新特征

1.1 从手机App到植物形态特征

近几年,智能手机逐渐普及,用手机不仅能用来拍照,其内置GPS功能更能为照片提供准确地理坐标。大部分手机都能通过3G或者4G方式访问互联网,极大方便了信息的传播。一些公司或者研究机构开发了植物识别的手机软件,用户只需要拍摄植物照片,软件就直接将照片上传到后台网站。而网站的服务器上的软件在网站开放之前,就已经通过人工智能学习,具备了识别植物的能力,这样,用户上传的照片就可以通过后台软件快速识别,最后通过手机程序告知用户照片中植物的名称、分布、用途等。用手机识别植物的软件,常见有:形色、花伴侣、微软识花等。

无论你身处海南岛还是黑龙江,甚至远在新疆、云南,只要手机有网络,照片比较清晰,手机软件一般都能给出鉴定结果。不过在专业人士看来,软件的鉴定结果存在很大的不确定性:对于识别常见的花卉,手机软件一般问题不大,但如果将手机软件鉴定的结果直接用于生物多样性调查,甚至编纂植物名录等就存在很多问题。目前来看,植物的准确鉴定仍然需要专业人员进一步核对。

实际上,这些手机软件识别植物的能力,都是以卷积神经网络为基础,用几十万、几百万张已经鉴定的植物照片训练出来的。因此,训练模型用的照片不仅仅要清晰展示植物在不同时期的特征,而且要求对数据库中的照片有准确鉴定。

然而植物鉴定的技能并不是每个人都能轻易掌握的。要准确鉴定植物,要学习的知识和技能很多。首先是植物形态解剖学的知识,先要了解植物各部分的名称以及各种形态的描述方法,以便在看到植物的时候能够准确描述。了解各种形态学术语是检索和鉴定植物的基础。一般情况下,鉴定植物有三种较为可靠的参考:(1)经过专家鉴定过的标本,特别是模式标本;(2)植物志、检索表、植物名录;(3)经过专家鉴定的图库。在信息社会,虽然获得相应的参考资料一般不太困难,但如果不了解能够准确描述植物的形态术语,就很难从以上资料中提取有效信息,导致最后鉴定结果模棱两可。

描述植物的专业词汇有多细致?举例来说,植物的毛被可以分成多种类型,如:绒毛、柔毛、绵毛、星状毛、丁字毛、伏毛、糙毛、硬毛、长柔毛等,叶片也有多种形状,叶缘、叶基、叶尖等都有相应的专业词汇描述,花序、花的各部分、果实类型、胚珠类型也都有相应的专业术语。甚至每个类群,如每个科甚至是属,都有一定的专业名词。由于这些名词往往用途很窄或者很抽象,一般人要理解有一定的难度。但是没有这些专业术语,就难以准确描述植物,难以描述近缘种之间的细微差别。植物描述如此复杂,如果没有受过系统培训是很难掌握的。

学生经过相当长一段时间的训练,理解各名词术语之后,见到某种植物,如果能够直接用形态术语去描述它,才是真正对相应的专业名词术语做到了理解,然而这只是刚刚开始,仅仅能够认识到各植物之间的区别而已。一个地区的植物,少则几百种,多则几千种上万种,从全世界范围内来讲,更是超过三十万种,一万多个属,要想全部记住是不可能的。

这就需要系统学习科学命名的原则,也就是《国际藻类、菌物和植物命名法规》,弄清植物命名的来龙去脉。植物的学名,均为拉丁文拼写,而原始文献,要么是拉丁文,要么是英文。对于普通人来说,又是一个学习的门槛。

在掌握了描述植物的技能和命名法规之后,学生还需要在自身兴趣的驱使下,不断认识新的植物,并通过观察、思考和总结,巩固和完善自身的知识系统。这样,经过几年的努力加天分,普通的大学生才能成为对某地区植物区系较为熟悉的“专家”。能鉴定植物的专家,又粗略分为“田野植物学家”和类群专家两种,后者才是真正意义上上的植物分类学家。

1.2 田野植物学家与植物分类学家

“田野植物学家”一般对某一地区的植物非常熟悉,往往能识别几百甚至几千种植物。但是,他们当中的很多人是不做植物分类学研究的。一般来说,“田野植物学家”可以根据植物志、检索表或者植物名录等准确鉴定植物。田野植物学家在植物采集、生态调查等项目中作用很大,很多是各保护区、林业局以及高校、科研院所的业务骨干。

与“田野植物学家”相比,真正意义上的植物分类学家的研究领域都已经非常“专门化”了,也就是只研究某一个专门的类群。这是因为,绝大部分植物分类学家没有足够精力将一个地区内所有植物都搞清楚,而只能针对某一个类群进行深入研究,例如木兰科、清风藤科、凤仙花科、毛茛科、樟科、番荔枝科等都有相应的类群专家。这些分类专家往往用毕生的时间,研究某一个目、科、属植物的分类、系统发育与进化关系、地理分布等。植物分类学要求每一个种的描述都要有对应的标本,但是植物分类学家本身可能并不怎么到野外去采集标本,因为他们主要的工作是看标本,纠正前人鉴定中的错误,同时考证和梳理相关文献等。

曾经有人讲了一个故事,一学生说听说某科的一位植物分类学权威来讲座,就拿了些新鲜植物样品,准备向分类权威咨询是哪个种。分类学家说:不认识,因为他只认识压干的植物标本,要求把新鲜材料做成标本再鉴定。这当然是一个极端的例子,但是植物分类学的一线学者,大部分时间都是在标本馆、实验室和图书馆度过的。在如此看重科研成果的今天,他们的主要在忙于读文献、看标本、获得研究数据、分析数据、写论文等。

从工作内容看,现代植物分类学家的工作可能包括以下方面:

  1. 发现和描述新分类群,也就是描述新种、新属等
  2. 通过形态和分子证据重建类群内部和类群之间的系统发育关系
  3. 梳理研究脉络,纠正旧文献的错误记录
  4. 编纂某地区的植物志和植物名录等
  5. 修订现有的命名体系,如《国际植物命名法规》
  6. 报道物种新分布,包括入侵种
  7. 探讨植物资源的利用和保护,如参与IUCN红色名录的编纂和评估、参与野外考察等

1.3 标本、论文、检索表、植物志与植物名录

名称的修订等相关工作,在不熟悉植物学的人看来,常常是十分枯燥的,然而名不正则言不顺,植物分类学是植物相关学科体系的基础。如果没有对植物系统、科学的命名,人们对自然界的认知马上会陷入一团糟。不同地区的人们对同一种植物很可能使用不同的名称,因此,不同地区、不同文化的人们在交流时候就会遇到困难。

提供最准确、最新的植物鉴定参考资料,就是植物标本馆、植物志和植物名录、植物检索表的意义,只有物种鉴定准确,才能进一步谈合理利用和保护,这也是植物分类学家工作的重要意义。

植物特征或者相关记录主要来源于植物标本。植物标本上记录了采集人、采集日期、地点、生境等信息,将这些信息汇总起来,人们就可以了解一个种的分布范围,了解不同地区、不同生境下同一个种的形态以及适应性的变化。随着数码相机和智能手机的普及,人们可以通过拍摄照片更快了解植物在鲜活时的形态特征,也能够更方便地整理物种分布信息。

将某一个地点拍摄的所有植物照片上传到网站上,通过人工智能鉴定,经过人工核验,再结合用户上传照片时填写的采集日期、采集地点,或者照片Exif信息中的GPS经纬度海拔等,可以快速生成某地的植物名录,iNaturalist网站和CFH网站等就已经实现相应的功能。将网站收集的各个种的记录汇总,也很容易获得某种植物的分布范围,花果期等各种信息。经过准确鉴定的植物照片如果同时有采集人、采集地点、采集日期等,在某种程度上可以看做是数字植物标本,是植物标本相关资料的重要补充。如果某区域内植物照片收集的足够多,鉴定足够准确,相关照片可以用作编写植物名录的参考资料。

1.4 什么是植物名录?

植物名录是记录某一个区域内全部植物,或者某一种类群或者具有某一种功能植物的图书或者图书的某一个章节。我国各自然保护区或者国家公园在评审之前,一般会邀请专家编纂植物名录,作为保护区申报的重要材料。植物名录覆盖的范围,可以是一个国家,一个地区,一个省、县、乡、村,也可能是自然保护区、国家公园等,也可能是某一个将会受影响或者有特别生态价值的区域或生境等。在上述不同等级的区域中,植物名录可包括野生植物、药用植物、经济植物、保护植物、入侵植物、外来植物、早春植物、高山植物、耐盐碱植物、沙漠植物、水生植物等等,或者某一类群的植物,如梧桐科、番荔枝科、木兰科、兰科等。上述植物名录,由于受到调查采集的完整程度,图书的编排体例,物种鉴定的准确程度,内容的翔实程度等,在质量上有很大差异,有些内容未必可信,在阅读时应仔细甄别。

1.5 为什么要编纂植物名录?

虽然不同植物名录质量参差不齐,但是,绝大部分植物名录都是对某地区物种多样性很好的记录,其植物名称,特别是俗名等还承载着当地的文化,在植物资源的可持续利用、保护当中起着重要作用。而且相对编纂植物志,植物名录的编写要相对容易一些,再版修订也更方便。

在没有编写植物志的地区,为了解植物的种类和分布,不妨先编纂植物名录。而已经有植物志的地区,如果植物志出版的年代过于久远,短期之内又难以修订,则应该考虑出版植物名录反映最新进展。如果某地区已经有省级植物志,对于地级市或者县级市来说只建议编纂植物名录,而不要再重复立项编纂市县级植物志,从而避免人力物力的进一步浪费。

虽然植物名录是非常重要的参考资料,但是在业界仍然缺乏统一的标准,也缺乏相应的指导原则,因此这里列出编纂植物名录需要注意的问题,以期在信息时代编纂出的植物名录能够更准确,内容更翔实,更有参考价值,也更容易阅读,从而提高植物名录的质量。这里要指出,本文列出的建议只是笔者一时间的思考,不妥之处应该仍然很多,所以也希望同行能够批评指正。

2. 编纂植物名录的一些建议

2.1 第一 内容准确,有标本和文献引证

植物名录中最重要的标准,就是记载的植物名称要准确,这是植物名录的最重要的参考价值。名称准确的前提是对植物进行准确鉴定,这就要求名录所收录的物种必须以植物标本为基础,有准确的标本引证信息。

为了便于进一步核实与修订,植物名录除了应该收录中文名和学名之外,还必须有详细的标本引证。如果所引证标本的鉴定发生了变化或者名称的分类地位发生了改变,如出现归并或者独立为新的分类单元等,植物名录就可以做相应的修订。如果没有引证植物标本,植物鉴定是否准确将无法查考。例如,某地区旧版植物名录收录的一些种无法找到凭证标本,在后续修订植物名录时,这些种是否在该地区有分布就成了疑问。在编写植物志时,就只能写某植物仅见于文献报道,难以查证。

除了有准确的标本引证外,参考文献也应该列入该种的条目下,对任何不是直接来自植物标本的信息,都需要给出参考文献的来源。做到任何引用的相关信息全都有凭有据。

2.2 第二 资料翔实

植物名录作为一个地区植物的重要参考,仅仅记录植物名称仍然不够,当然更不能照抄植物志或者其他资料,将其他书籍内的用途、分布、花果期、生境等照搬到本地。实际上,植物名录中的信息可以做到非常有地方特色,除了记载植物的中文名和学名之外,还可以考虑记录植物在当地的俗名,所查阅标本的记录的生境以及编写者所了解到的用途,如在当地的入侵情况等。有些植物名录,如朱华教授主编的《云南西双版纳野生种子植物》提供了植物分布的小地点和海拔;中国科学院华南植物园与香港植物标本室共同主编的《香港植物名录》(2001)提供了每个种的花、果期和分布到村镇一级小地点名称,这些都是很好的例子。国外有一些植物名录还提供了每个种的分布地图等。

此外,植物名录可以记载某种植物的分布范围,但是分布范围要体现最新的研究进展,不宜照抄多年前的资料,例如出现“苏联”、“前苏联”、“南朝鲜”等字样,描述地点时要对地名或者行政区划等做出相应的调整,对旧地名做出相应考证。

2.3 第三 结构完整、顺序合理

2.3.1各类群的排列顺序

完整的植物名录可以以附录的形式出现,也可能在保护区考察集中以独立的章节出现,当然,如果足够重要,可能是以独立的著作形式出现的。而作为一本独立的著作,结构合理、内容翔实、版式顺序符合人们的阅读习惯都是非常重要的。

无论是以什么形式呈现的植物名录,按照类群来说,可以参考以下顺序编排:

  1. 苔藓植物;
  2. 蕨类植物;
  3. 裸子植物;
  4. 被子植物;

上述高等植物四个类群是按照系统发育关系顺序排列的。不仅是在大类群的排列顺序上应该考虑系统发育顺序,在每个类群内部,即科和属等级,笔者也建议应该尽量按照系统发育顺序排列。这就需要参考各类群科的系统发育线性编号。苔藓植物虽然已经有最新的科等级分子系统树,但目前仍然缺乏科等级顺序号;蕨类植物可参考PPG系统;裸子植物有Christenhusz系统;被子植物有PPG系统。中国科学院植物研究所刘冰博士等在《生物多样性》上发表的提供的中国被子植物科属概览APG III系统排列表,是中文植物科名和属排列顺序的重要参考文献。该论文的附录中,不但有每个科的顺序号,还提供了每个科下等级,属的排列方式。另一个非常有价值的网站是多识植物百科(http://duocet.ibiodiversity.net/),该网站由国内一些植物学青年学者共同维护,列出了各科的最新进展,特别是各类群的顺序号异名等,内容十分丰富。

无论是大类群,还是目、科以及科以下等级,在有条件的情况下,名录作者应尽量考虑采用系统发育顺序排列。不过,在科以下等级,不同的分类学家可能有不同的观点,导致科以下各属之间系统发育顺序发生变化,甚至各系统之间有严重的冲突。此时,如果植物名录的作者不能确定采用哪种系统,可能就要考虑将科下各属都按照字母顺序排列,属下等级也按照拉丁字母顺序排列。这种处理的不足之处,就是一些大科,如禾本科、菊科、豆科等各亚科、各族等的系统发育顺序被打乱,导致有系统分类背景的读者难以查到系统位置相近的属、种。

因此,在编纂植物名录时,如果是较大区域且物种数很多,应该尽量考虑使用系统发育顺序。如果是较为通俗的读物,就可直接考虑用字母顺序排列。

2.3.2 植物名录的完整结构

如果植物名录是以一本书的形式出现,则应该考虑按照顺序包括以下结构:

(1)序言

也就是请本领域著名的专家学者为本书作的序,一般介绍成书背景,研究成果的重要意义或者相关轶事等。

(2)目录

目录是读者快速了解全书的结构的最重要途径,对于植物名录来说,目录一般要提供各科的页码,以方便读者快速查找。

2.3.2.3 三、前言

前言部分一般可介绍本书的概况,如收录多少种,调查了哪些区域,查阅了多少标本,调查的时间和方式,调查人都有谁等,还有在编纂过程中查阅了哪些标本馆的标本,做了什么修改,有什么新的分布记录,与之前的文献相比,本名录有哪些特色,有谁帮审稿等。同时,还可以介绍本书使用时的注意事项和使用方法,并告知读者书中各种图标、缩写的含义,以免读者在阅读正文时出现困难。最后还要说明作者的联系方式,以便读者能够及时反馈相应的修改意见。前言部分还应该并对该书有贡献的人表示感谢。

2.3.2.4 四、引论/绪论

植物名录的编纂的背景资料,有时可以放在前言部分,有时也可以放在引论/绪论中,独立为一章,特别是对研究区域较大的情况。这部分可以介绍研究地区的气候、地质历史、植被变迁,采集史以及本书的调查方法,查阅的标本数量,并对本书的新发现以及相应的意义做相应的介绍。

2.3.2.5 五、正文

植物名录正文,即按照上述“资料翔实”一节的要求,按照本节所述排列顺序,依次记录各种植物。根据图书体例需要,可以考虑是否单独列出属名。从格式上,植物名录的拉丁学名应该用正体,而异名才用斜体。这一点与一般论文撰写不同,需要注意。

形式统一的植物名录正文部分,可以通过计算机语言,如SQL,R,Python,Javascript等基于数据库自动生成。笔者编写的plantlist程序包(http://blog.sciencenet.cn/blog-255662-846673.html)就内置了生成植物名录Markdown模版的相应函数,生成的Markdown文件可以很方便转换为word、Latex、html、pdf等多种格式的文件,作为植物名录的主体。

2.3.2.6 六、参考文献

过去,很多图书的参考文献一般都不在正文中列出,但是这样一来,图书中部分信息的出处就有了疑问,因此,对于前言、引论甚至植物名录正文中,如果有引用其他文献的内容,建议直接给出参考文献。这样将提高名录的可信度,也方便之后的修订。

2.3.2.7 七、索引

一般要分为中文索引和拉丁文索引,而中文索引又分为拼音索引、笔画索引以及部首索引等。当代汉语拼音已经非常普及,因此按照拼音给出科、属、种索引已经能满足绝大多数读者的要求。拉丁文索引能让读者快速查找学名和异名,也是非常重要的。在设定索引时,科、属、种可以混排,但是种不独立成条,而是附在属名之后,后退两格。科名和属名都顶格书写,但是科名用黑体或者大写,以示区别。有时候,为了让读者能快速找到对应的科,可以在索引之外,分别增加中文科名、拉丁名页码对照表,以便快速查找。

2.3.2.8 八、其他

可包括彩色图版、名词解释、地名对照表、行政区划变迁、人名对照表、采集人简介等。有些书籍还包括后记,介绍编纂该书的心得等。

2.4 第四 反映最新研究进展

植物名录是学术专著的一种,是作者学术水平的重要体现,因此将各部分内容按照最新的研究进展及时更新就非常重要。

植物名录不但要考证和收录旧名录或旧的植物名录出版以来,所有新种、新分布记录,还应纠正旧文献记录中的错误。而相关的信息,应尽量直接来自于植物标本,引证了凭证标本的植物名录,不但修订起来更为方便,其参考价值也更高。植物名录要反映植物名称最新的分类地位的变化,包括系统发育关系的最新研究进展等,特别是要处理好为学术界接受的最新学名。

关于植物的中文名,近年来有一些争论,有人强调现有植物中文名不够系统,会导致很多误解,所以建议应该撇开现有的植物中文名,另起一套“中文植物学名”。笔者认为,任何在已有名称上再继续增加新的中文名,都应该十分谨慎,需要认真考虑学术界以及广大读者是否能够接受。实现标准化中文名,愿景是好的,但是结果往往事与愿违。最新版的《中国生物物种名录》所采用的中文名已经是为学界和广大中文读者都接受的植物中文名系统,此时就不宜再另外再增加其他中文名,以免造成混乱。《中国生物物种名录》广泛采用了《中国植物志》和《Floraof China》的中文名,若《中国植物志》和《Flora of China》的名称有冲突,在编写植物名录时,应该在审慎的基础上,尽量采用Flora of China的名称。对于新记录的种,或者发表的新种,应按照相应类群现有的中文名命名习惯,拟定新的名称。

2.5 第五 注意保护

按照中国科学院植物研究所公布的《中国红色物种名录》(http://www.chinaplantredlist.org/)中国记录到的34450种高等植物中,有27 种已经绝灭,野外绝灭 10 种,极度濒危583 种,濒危1297 种,易危1887种,近危2723 种,这些数字是相当可观的。除了将森林转换为农田,或者将次生林转换为经济林等生境破坏等因素之外,对中药材的不合理采集和收购、对珍稀花卉的盗挖、非法贸易等,让很多植物成为进一步采集或者破坏的目标,从而威胁到植物物种的生存。而很多种原本已经到达濒危的程度,距离绝灭仅仅一步之遥。

GBIF、CFH等网站上,一般对于濒危等级较高的种类,或者特殊类群的标本记录,都做模糊化处理。曾经有分类学家描述了新种,该种的受威胁程度应该是极度濒危,分布区很小,野外种群十分脆弱,但由于论文透露了该珍稀种的分布地点,很快被偷猎者盯上,导致该物种遭遇灭顶之灾。

因此,在公开出版物,包括植物名录中,濒危种类的地理坐标或者分布小地点是不宜透露的。

2.6 第六 容易阅读

如果植物名录作为图书出版,排版印刷就非常重要。读者对于图书质量是十分挑剔的,特别是愿意阅读植物名录的读者,由于往往是相关领域的专业人士,对于书籍的纸张、页面、排版、装帧、印刷以及美观程度等要求就更高。当然,出版社有专业的排版人员和美术编辑,经过耐心沟通后,一般都能将植物名录制作成高质量的图书。

图书中出现错别字有时候是难免的,但在印刷之前,应该认真咨询业内专家的审稿意见,并请专人多次校对,尽量减少错误。

2.7 第七 动态植物名录

每年修订的中国生物物种名录(www.sp2000.org.cn),就是名录开放很好的例子。在这个网站,所有内容都可以免费下载。在网络版植物名录中,读者可以更好与作者互动,对旧版的植物名录提出修改意见,以便在再版时及时更正或者增补。

3. 结论

信息时代的生物多样性编目,植物学家的可用资源等发生了很多变化,这就要求植物学家采取一定的策略,推动相应的研究。植物名录是生物多样性编目的重要组成部分,是分类学和生物多样性编目成果的重要体现形式。信息时代的植物分类学研究,应参考最新分子系统学研究进展,以合理的方式编排,提供地区准确、翔实的植物分布记录,并保证每一条记录都有标本引证信息。植物名录编纂过程中,应充分考虑到互联网与智能软件的优势,将植物信息以网站的形式整合和呈现,从而实现植物多样性信息的进一步整合。

致谢:

感谢深圳国家基因库杨拓博士,浙江大学刘军老师,中国科学院上海辰山植物园王正伟老师、刘夙老师提出修改意见。

参考文献

从略

What are we doing in a herbarium? A talk at ISF

A Talk at the ISF | Independent Schools Foundation (https://www.isf.edu.hk/)

Download the slides: why_plant_biodiversity.pdf

Why plant biodiversity is important and what we are doing in a herbarium?

Here is the working flow:

  1. Collecting in the field: pay attention not to collect from small populations, fill in the field book
  2. Pressing the specimens
  3. Drying the specimens: 55℃ for 24hrs
  4. Mounting: Follow the Herbarium Handbook
  5. Printing labels: using the herblabel package
  6. Freezing: -18℃ for 14days
  7. Barcoding: Encoded in ISO128
  8. Scanning: 600dpi
  9. Filing: according to the APG III classification system

Computing the time of sunrise, sunset and transit (skycalc)

Note this is the translation of http://blog.sciencenet.cn/blog-255662-756136.html

This document describes how to compute the time of sunrise, sunset and transit for any place on earth using the skycalc package.

If the longitude and latitude for a place are known, to compute the time of sunrise, sunset and transit, these are the factors considered by the skycalc package:

  1. The Right ascension and the Declination of the sun on the day before and after the day. Then the time of sunrise, sunset, transit is interpolated for a specific place (Please refer to the source code of the CAAElliptical_Calculate_Sun function).
  2. In astronomy, conventionally, the longitude in the eastern hemisphere is negative (<0), and in the western hemisphere positive (>0).
  3. Time zone and daylight saving time also need to be considered during computation so the time could be converted into local time.

R code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
library(skycalc)
## Loading required package: Rcpp
### Convert the julian day into year, month, day, YYYY-MM-DD

Julian2Date <- function(jd){
int2 <- function(v){ return(floor(v))}

r =list()
D = int2(jd+0.5) F= jd+0.5-D
if(D >=2299161){
c= int2((D-1867216.25)/36524.25)
D= D +1+c- int2(c/4)
}
D = D +1524
r$Y = int2((D -122.1)/365.25)# Year
D = D - int2(365.25*r$Y)
r$M = int2(D/30.601) #Month
D = D - int2(30.601*r$M)
r$D = D #Day
if(r$M>13){
r$M = r$M -13
r$Y = r$Y -4715
}else{
r$M = r$M - 1
r$Y = r$Y -4716
} F = F *24
r$h=int2(F) # Hour
F = F - r$h F = F *60
r$m=int2(F) # Minute
F = F -r$m F = F *60
r$s=F # Second
return(r)
}
# A wrapper function for CAARiseTransitSet_Calculate()
sunRTScalc <-function(year, month, day, longitude, latitude, zone,
bGregorianCalendar =TRUE,
type =c("rise", "transit", "set")){
type <- match.arg(type)
JD = CAADate_DateToJD(year, month, day, bGregorianCalendar)

SunDetails1 = CAAElliptical_Calculate_Sun(JD -1)
Alpha1 = SunDetails1$ApparentGeocentricRA
Delta1 = SunDetails1$ApparentGeocentricDeclination;
SunDetails2 = CAAElliptical_Calculate_Sun(JD)
Alpha2 = SunDetails2$ApparentGeocentricRA
Delta2 = SunDetails2$ApparentGeocentricDeclination;
SunDetails3 = CAAElliptical_Calculate_Sun(JD +1)
Alpha3 = SunDetails3$ApparentGeocentricRA
Delta3 = SunDetails3$ApparentGeocentricDeclination
RiseTransitSetTime =CAARiseTransitSet_Calculate(JD,
Alpha1, Delta1, Alpha2, Delta2, Alpha3,Delta3,
longitude, latitude, -0.8333)
if(type =="rise"){
rtsJD =(JD +(RiseTransitSetTime$details.Rise/24.00))
} if(type =="set"){
rtsJD =(JD +(RiseTransitSetTime$details.Set/24.00))
} if(type =="transit"){
rtsJD =(JD +(RiseTransitSetTime$details.Transit/24.00))
}

lclJD = rtsJD -(zone/24.00)
return(Julian2Date(lclJD))
}

Example 1

Compute the time for sunrise, sunset for Boston (Longitude:74.73057W, Latitude: 39.275787N), USA on 2009-08-09

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2009, month =8, day =9, 
longitude =74.73057, latitude =39.275787,
zone =4, bGregorianCalendar=TRUE, type ="rise")
## $Y
## [1] 2009
##
## $M
## [1] 8
##
## $D
## [1] 9
##
## $h
## [1] 6
##
## $m
## [1] 6
##
## $s
## [1] 27.4320968985558

Explanation: As sunset at Boston happens at (local time: 2009-8-9 20h01m39m (UT:2009-8-10: 00h01m39m), of course, you do not know the precise time before calling sunRTScalc, but as soon as you get the result, you need to realise this), therefore you need to call the function as `sunRTScalc(year =2009, month =8, day =10,…)```, because the inputs (year, month, day) are actually converted from Julian Day.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2009, month =8, day =10, 
longitude =74.73057, latitude =39.275787,
zone = 4, bGregorianCalendar = TRUE, type ="set")
## $Y
## [1] 2009
##
## $M
## [1] 8
##
## $D
## [1] 9
##
## $h
## [1] 20
##
## $m
## [1] 1
##
## $s
## [1] 40.2297654747963

Example 2

Calculate the time of sunrise and sunset at the Tian’anmen Square in Beijing (Longitude: 116.391325E, Latitude: 39.907356N) on 2014-01-05.

Explanation: As the sun rises at 7h36m15.2s on 2014-01-05 (local time), the UT is actually 2014-01-04 23h36m15.2s. We, therefore, will use 2014-01-04 as inputs. Note the Time zone of Beijing is 8 hours ahead of UT.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2014, month =1, day =4, 
longitude =-116.391325, latitude =39.907356,
zone =-8, bGregorianCalendar =TRUE, type ="rise")
## $Y
## [1] 2014
##
## $M
## [1] 1
##
## $D
## [1] 5
##
## $h
## [1] 7
##
## $m
## [1] 36
##
## $s
## [1] 15.2419799566269

Sunset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2014, month =1, day =5, 
longitude =-116.391325, latitude =39.907356,
zone =-8, bGregorianCalendar =TRUE, type ="set")
## $Y
## [1] 2014
##
## $M
## [1] 1
##
## $D
## [1] 5
##
## $h
## [1] 17
##
## $m
## [1] 3
##
## $s
## [1] 16.8268677592278

Transit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2014, month =1, day =5, 
longitude =-116.391325, latitude =39.907356,
zone =-8, bGregorianCalendar =TRUE, type ="transit")
## $Y
## [1] 2014
##
## $M
## [1] 1
##
## $D
## [1] 5
##
## $h
## [1] 12
##
## $m
## [1] 19
##
## $s
## [1] 40.6033730506897

Example 3

Calculate the time of sunset, sunrise for Tian’anmen Square, Beijing (+8hrs) (Longitude: 116.391325E, Latitude: 39.907356N) on 2014-06-20

Sunrise

Explanation: As the time of sunrise at the site is (Local time 2014-06-20, 4h45m45.14s, UT 2014-06-19 22h45m45.14s), we should use 2014-06-19.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2014, month =6, day =19, 
longitude =-116.391325, latitude =39.907356,
zone =-8, bGregorianCalendar =TRUE, type ="rise")
## $Y
## [1] 2014
##
## $M
## [1] 6
##
## $D
## [1] 20
##
## $h
## [1] 4
##
## $m
## [1] 45
##
## $s
## [1] 45.1418057084084

Sunset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2014, month =6, day =20, 
longitude =-116.391325, latitude =39.907356,
zone =-8, bGregorianCalendar =TRUE, type ="set")
## $Y
## [1] 2014
##
## $M
## [1] 6
##
## $D
## [1] 20
##
## $h
## [1] 19
##
## $m
## [1] 46
##
## $s
## [1] 5.37074446678162

Transit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2014, month =6, day =20, 
longitude =-116.391325, latitude =39.907356,
zone =-8, bGregorianCalendar =TRUE, type ="transit")
## $Y
## [1] 2014
##
## $M
## [1] 6
##
## $D
## [1] 20
##
## $h
## [1] 12
##
## $m
## [1] 15
##
## $s
## [1] 54.5454159379005

Example 4

Compute the time of sunrise, sunset for Melbourn, Australia (Longitude: -144.963171E, Latitude: -37.814247S) on 2020-1-15.

Explanation: The Sunlight saving date starts from the first Sunday of October the year before (herein, 2019), and ends at the first Sunday in April (2020). On January 15th, Australia is in Sunlight saving time, therefore during computation, the time zone is 11 hours ahead of UT. When the sun rises on 2020-14-15 in Melbourn (local time), UT is still on 2020-1-14, we, therefore, need to use sunRTScalc(year =2020, month =1, day =14,...)

Sunrise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2020, month =1, day =14, 
longitude =-144.963171, latitude =-37.814247,
zone =-11, bGregorianCalendar =TRUE, type ="rise")
## $Y
## [1] 2020
##
## $M
## [1] 1
##
## $D
## [1] 15
##
## $h
## [1] 6
##
## $m
## [1] 13
##
## $s
## [1] 55.4257643222809

Sunset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2020, month =1, day =15, 
longitude =-144.963171, latitude =-37.814247,
zone =-11, bGregorianCalendar =TRUE, type ="set")
## $Y
## [1] 2020
##
## $M
## [1] 1
##
## $D
## [1] 15
##
## $h
## [1] 20
##
## $m
## [1] 44
##
## $s
## [1] 6.54912650585175

Transit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sunRTScalc(year =2020, month =1, day =15, 
longitude =-144.963171, latitude =-37.814247,
zone =-11, bGregorianCalendar =TRUE, type ="transit")
## $Y
## [1] 2020
##
## $M
## [1] 1
##
## $D
## [1] 15
##
## $h
## [1] 13
##
## $m
## [1] 29
##
## $s
## [1] 13.399246931076

Session Information

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sessionInfo()
## R version 3.5.3 (2019-03-11)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS Mojave 10.14.4
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/C/en_US.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] skycalc_1.62 Rcpp_1.0.1
##
## loaded via a namespace (and not attached):
## [1] compiler_3.5.3 magrittr_1.5 tools_3.5.3 htmltools_0.3.6
## [5] yaml_2.2.0 stringi_1.4.3 rmarkdown_1.12 knitr_1.22
## [9] stringr_1.4.0 xfun_0.6 digest_0.6.18 evaluate_0.13

Further reading

Please note that skycalc is just a wrapper package for the AA+ library. The following examples are mainly derived from the documents of the AA+ CPP library written by PJ Naughter. For more information, please refer to http://www.naughter.com/aa.html

天津宝坻童谣选

记录地点:天津市宝坻区郝各庄镇十四户村

记录时间:2019年4月23日

张丽萍(65岁)口述

童谣

  1. 小小子儿,坐门墩,哭着喊着要媳妇儿。
  2. 哧(chi3)啦哧啦拉大锯,姥爷门口儿唱大戏,接闺妞,叫女婿,小外甥不嫌你也去。
  3. 点,点,点牛眼,牛眼花,一担芝麻两担瓜。有钱的,买着吃;没钱的,滚出去。
  4. 点,点,点牛眼,牛眼花,炒芝麻,芝麻粒,放狗屁。
  5. 狼来了,虎来了,小猫背着个鼓来了。 狼抱柴,虎烧火,小猫上炕贴饽饽。 贴多少,贴一大簸箕。 不给小猫一个吃,馋得小猫舔簸箕。 簸箕舔倒了,把小猫也吓跑了。
  6. 哦,哦,睡觉了,大人小孩儿别闹了。
  7. 落(lao4)下?怪害臊的。 门口等着?怪冷的。 你嘎着窝夹着啥(sha4)呢?夹着大皮袄(nao3)呢。 你咋不穿呢?我怕虱子咬啊。 你咋不拿啊?我眼儿麻啊。 你咋不叫你媳妇儿拿啊?我媳妇儿死了。 你咋不哭啊?……盆儿啊,罐儿啊,我老伴儿啊……
  8. 小耗子,上灯台,偷油吃,下不来。吱扭吱扭叫奶奶,奶奶也不来,叽里咕噜滚下来。
  9. 二十三,糖瓜粘; 二十四, 写大字; 二十五, 扫房土; 二十六,蒸馒头; 二十七,宰公鸡; 二十八,把面发; 二十九,蒸豆篓; 三十儿黑下扭一扭。
  10. 三十儿,流油;初一,磕头。
  11. 拉钩,上吊,一百年,不许变。
  12. 一个毽(qian4),踢两半儿,山里(le)红,果子馅儿,里踢,外拐,八仙,过海,九十九,一百。
  13. 从南京,到北京,没见过馅儿饼打补丁。
  14. 马兰开花二十一,二五六,二五七,二八二九三十一;三五六,三五七,三八三九四十一;四五六,四五七,四八四九五十一;五五六,五五七,五八五九六十一;六五六,六五七,六八六九七十一;七五六,七五七,七八七九八十一;八五六,八五七,八八八九九十一;九五六,九五七,九八九九一百一!

附录

绕口令三首

  1. 出西门,走七步,拾块鸡皮补皮裤,是鸡皮,补皮裤,不是鸡皮,不必补我的破皮裤。
  2. 山前有个崔粗腿,山后有个崔腿粗,他们两个来比腿,看看是崔粗腿的腿粗还是崔腿粗的腿粗。
  3. 扁担长,板凳宽,扁担要绑在板凳上,板凳不要扁担绑在板凳上,扁担偏要绑在板凳上。

谜语二首

  1. 麻屋子,红帐子,里面住着个白胖子。
  2. 竹皮墙,铁皮墙,里面住着玻璃房。玻璃房,亮堂堂,房里热,房外凉。

数学题一首

一帮老头儿去赶集,半(man4)道上碰到一堆梨,一个一个多一个,一人两个少两个。问有多少个老头儿,多少个梨?

QGIS3 创建包含多边形的shape文件

QGIS是非常优秀的GIS软件。因为是开源软件,程序包中所有的工具都可以免费使用。下面简要介绍用QGIS怎样创建一个ESRI shape文件。

Shape文件是GIS的通用格式,各种空间处理软件,包括R、Python等的空间处理以及绘图都会用到它。

QGIS的下载和安装,参见 https://www.qgis.org/en/site/。

要创建包含多边形的shape文件,按照以下步骤操作即可:

  1. 在Windows左下角放大镜图标,输入QGIS,找到QGIS3

  2. 右键选择run as administrator。

  3. 添加一个免费图层作为参考。菜单Web > Quick Map Service> OSM > OSM standard或其他图层。这里加载OSM Open Street Map。

  4. 菜单Layer>Create Layer>New Shapefile layer。

  5. 在新弹出的窗口中,指定文件名File Name为test, 类型Geometry Type为Polygon。

  6. 在New Field指定field的名称和类型,并添加到add to Fields List中,点击OK。

  7. 此时可见左下角的Layers窗口出现test图层,但是还没有任何内容。

  8. 右键点击test图层,选择toggle editing,进入编辑模型。

  9. 菜单Edit,选择 Add Polygon Feature添加多边形。

  10. 进入地图窗口,依据现有地图描绘多边形。要结束编辑,点击右键,输入该多边形的唯一识别编号id。要删除上一步添加的点,按delete键。 如果要添加环状的多边形,必须要先选择已有的多边形。

  11. 在Layers导航栏右键点击test图层,选择Export>Save Feature As,在弹出的窗口指定File Name和保存路径即可。

默认的投影是WGS84。这是最常见的地图投影。如果要做投影变换,可将该shape文件读取到R中,用sf或者sp程序包进行转换,再绘图即可。

要下载更多免费shape文件,可参考:

如果你要绘制的地图包含中国国界线,请一定仔细阅读姜大伟的《使用中国地图的正确姿势》一文(https://zhuanlan.zhihu.com/p/25634886)。

一文读懂ggplot2数据可视化

1.前言

ggplot2是数据可视化的重要程序包,用于绘制各种高级统计图形。该程序包是新西兰统计学家Hadley Wickham在2005年左右开发的,那时候作者还是美国Iowa大学的博士生。

1.1 ggplot2的命令是一种用R实现的绘图语言

ggplot2的代码相对容易理解,设定各种参数较为方便,图形也十分美观,能用相对简单的代码在图形中呈现出非常丰富的信息。不过,ggplot2的语法与传统R函数的调用方式有很大差别,所以不少人反映学起来有些困难。

在ggplot2出现以前,R绘图都是调用函数,再通过改变函数的参数实现的。ggplot2将所绘制图形的各部分独立出来,如xy坐标,基本组件的颜色、图标大小、填充类型、堆叠方式、坐标轴、地图投影、数据分组、图形分面等等信息划归为一些基本类型,每一部分分别用一段代码表示。每段代码内部有相应的参数控制,各代码段再通过“+”运算符连接。这里的“+”并非四则运算的加法,而是表示图形各要素/组件之间的叠加。“+”运算符所连接的代码片段,有任何一部分做出更改,整个图形就做出相应调整。因此,本质上,ggplot2代码是用R语言实现的一种绘图语言。

ggplot2所用的绘图语言,主要是按照Wilkinson(2005)的设想实现的。Wilkinson(2005)将一幅统计图形看做由以下几个主要部分:

  1.  数据;
    
  2.  表现数据的点、线、多边形、栅格、颜色等;
    
  3.  坐标系
    

1.2 ggplot2命令的基本组成

具体来讲,在ggplot2程序包中,每一副图都是由若干组件组成的,这些组件包括:

  •  `data`:     数据,必须为data.frame。
    
  •  `coordinate     system`:     数据可视化,主要是在二维平面上表示数据的关系,所用坐标系一般为平面直角坐标,有时会用到极坐标、地图投影等。ggplot2软件默认使用平面直角坐标。
    
  •  `geoms`:     包括geoms_开头的各种对象,用来绘制各种基本组件,包括点、线、面、多边形、柱状图、箱线图等。
    
  •  `aesthetics`:     图形的美学特征,如颜色、形状、透明度、大小、分组等。
    
  •  `scales`:     坐标轴的属性
    
  •  `stats`:     统计变换。用于设定数据要进行的统计转换,例如平均值、中位数、记录数等。
    
  •  `facets`:     描述如何将图形按照某一个或者几个因子(factors)不同水平(levels)用多个图形分开展示。
    

1.3 ggplot2要求输入数据为data.frame

ggplot2要求输入的数据为data.frame。为了将R中的各种数据转换为ggplot2能够读取和操作的data.frame格式,H. Wickham还开发了reshape2以及dplyr等程序包,专门用于数据转换。

1.4 ggplot2中的aes函数

完整的ggplot2绘图命令, 总是以ggplot() 开始。ggplot()及其参数奠定整个ggplot2图形的基础,最重要的两个参数为data和mapping。其中data必须为data.frame格式。mapping参数要求数据通过aes函数进一步转换。aes是aesthetic的缩写。在aes函数中,要输入的参数有x, y, group, color, size等。aes可以直接访问data参数所输入数据框的各列,从而直接控制图形的横坐标、纵坐标、分组以及各组的颜色、大小、透明度等等。

注意:在ggplot()代码部分设置的aes参数对于整个图形都有效。在某个geom组件内部设置的aes参数,如颜色、分组、字体大小、线段类型等,只对该geom组件有效。若要设定所有geom组件的形状、大小、颜色等,相应的参数如size, color等,不要放入aes函数转换,而是作为ggplot()函数的普通参数即可。

1.5 ggplot2的geom组件

ggplot()代码段只定义数据展示的逻辑关系,并不直接绘图。要用ggplot2绘图,还必须为其添加各种基本图形组件。要添加的图形组件根据变量的数目以及要绘制的图形有所不同,包括:点geom_point、线geom_line、多边形geom_polygon、箱线图geom_boxplot、柱状图geom_bar、六角形图geom_hex、栅格图geom_tile、阶梯线geom_step、拟合的趋势线geom_smooth等等。

为了对图形进行进一步修饰,还可能要更改图形的横坐标、纵坐标、标题等等。

1.6 ggplot2图形的显示

ggplot2所生成的对象,同时具有gg和ggplot两种属性。如果要显示图形,需要将其print到屏幕上,而不是像plot()函数一样直接调用函数就可以调用绘图设备(屏幕也是绘图设备)。与此同时,ggplot2的图形也不接受par()设定的各种参数。

本文就ggplot2的常用绘图组件做简要介绍。

2 快速绘图

2.1 qplot (不建议使用)

为了让只熟悉R基础绘图的用户也能使用ggplot2,H. Wickham编写了qplot函数,调用方式类似plot()。在qplot()中,所有控制图形的信息都封装为参数。但是qplot()在一定程度上降低了绘图的灵活性,难以体现ggplot2的优势,因此不太建议使用。

1
2
3
4
#### 载入数据
library(maps)
library(ggthemes)
library(ggplot2)

2.1.1 普通绘图

1
plot(hwy ~ cty, data = mpg)

2.1.2 qplot绘图

1
qplot(x = cty, y = hwy, color = cyl, data = mpg, geom = "point")

2.1.3 ggplot2绘图

1
2
3
4
5
6
7
8
9
10
ggplot(data = mpg, aes(x = cty, y = hwy)) + ### 设置x, y以及数据
geom_point(aes(color = cyl)) + ### 添加 点, 以及 设置 点 的颜色
geom_smooth(method = "lm") + ### 添加拟合曲线/曲线以及置信区间
coord_cartesian() + ### 笛卡尔坐标系, 即平面直角坐标系
scale_color_gradient() + ### 图例的颜色
theme_base() + ### 主题为base风格
scale_shape(solid = FALSE) + ### 点的类型为中空。
ggtitle("New Plot Title") + ### 标题
xlab("New X label") + ### 横轴
ylab("New Y label") ### 纵轴

3 基本绘图组件及其属性

3.1 多边形

1
2
3
thismap = map_data("world")
c <- ggplot(thismap, aes(long, lat, group=group))
c + geom_polygon(fill="white", colour="gray")

3.2 折线图

1
2
ggplot(economics, aes(date, unemploy)) +
geom_path(lineend = "butt", linejoin = "round", linemitre = 1)

3.3 带状图

1
2
ggplot(economics, aes(date, unemploy)) + 
geom_ribbon(aes(ymin = unemploy - 900, ymax = unemploy + 900))

3.4 线段

1
2
ggplot(seals, aes(x = long, y = lat)) + 
geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat))

3.5 长方形

1
2
3
ggplot(seals, aes(x = long, y = lat)) + 
geom_rect(aes(xmin = long, ymin = lat,
xmax = long + delta_long, ymax = lat + delta_lat))

4 一维连续数据(向量)绘图

4.1 一维连续数据

1
a <- ggplot(mpg, aes(hwy))

4.2 频度阴影图

1
2
a + geom_area(stat = "bin")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

4.3 核密度图

1
a + geom_density(kernel = "gaussian")

4.4 点状频度图

1
2
a + geom_dotplot()
## `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

4.5 频度折线图

1
2
a + geom_freqpoly()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

4.6 单变量离散数据

1
2
b <- ggplot(mpg, aes(fl))
b + geom_bar()

5 二维连续变量绘图

5.1 x和y均为连续变量

5.1.1 空白图形,只生成坐标

1
2
f <- ggplot(mpg, aes(cty, hwy))
f + geom_blank()

5.1.2 带随机扩散的散点图

1
f + geom_jitter()

5.1.3 散点图

1
f + geom_point()

5.1.4 分位数回归线

1
2
3
4
5
6
7
8
f + geom_quantile()
## Loading required package: SparseM
##
## Attaching package: 'SparseM'
## The following object is masked from 'package:base':
##
## backsolve
## Smoothing formula not specified. Using: y ~ x

5.1.5 xy轴投影

1
f + geom_rug(sides = "bl")

5.1.6 线性模型拟合以及置信区间

1
f + geom_smooth(method = "lm")

5.1.7 Loess拟合趋势线以及置信区间

1
2
f + geom_smooth(method = "auto")
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

5.2 x为离散变量,y为连续变量

5.2.1 柱状图

1
2
g <- ggplot(mpg, aes(class, hwy))
g + geom_bar(stat = "identity")

5.2.2 箱线图

1
g + geom_boxplot()

5.2.3 点图

1
2
g + geom_dotplot(binaxis = "y", stackdir = "center")
## `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

5.2.4 小提琴图

1
g + geom_violin(scale = "area")

5.3 x为离散变量, y为离散变量

1
2
h <- ggplot(diamonds, aes(cut, color))
h + geom_jitter()

5.4 二维密度分布图

5.4.1 栅格图

1
2
3
data(iris)
i <- ggplot(iris, aes(Sepal.Length, Sepal.Width))
i + geom_bin2d(binwidth = c(5, 0.5))

5.4.2 等高线密度图

1
i + geom_density2d()

5.4.3 六角形密度图

1
i + geom_hex()

5.5 x轴为时间序列的连续变量

5.5.1 阴影图

1
2
j <- ggplot(economics, aes(date, unemploy))
j + geom_area()

5.5.2 折线图

1
j + geom_line()

5.5.3 阶梯图

1
j + geom_step(direction = "hv")

5.6 添加误差线

1
2
df <- data.frame(grp = c("A", "B"), fit = 4:5, se = 1:2)
k <- ggplot(df, aes(grp, fit, ymin = fit-se, ymax = fit+se))

5.6.1 误差箱图

1
k + geom_crossbar(fatten = 2)

5.6.2 误差线图(带横线)

1
k + geom_errorbar()

5.6.3 误差线图(不带横线)

1
k + geom_linerange()

5.6.4 带误差线的点图

1
k + geom_pointrange()

6 三维数据的可视化

1
2
seals$z <- with(seals, sqrt(delta_long^2 + delta_lat^2))
m <- ggplot(seals, aes(long, lat))

6.1 等高线图

1
m + geom_contour(aes(z = z))

6.2 栅格图

1
m + geom_raster(aes(fill = z), hjust=0.5, vjust=0.5, interpolate=FALSE)

6.3 瓦片图

1
m + geom_tile(aes(fill = z))

7 统计变换

1
2
a + geom_bar(stat = "bin")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

说明:stat_bin(geom = "bar")geom_bar(stat = "bin") 两者等价

7.1 一维概率密度统计变换参数的设定

1
a + stat_bin(binwidth = 1, boundary = 10)
1
a + stat_density(adjust = 1, kernel = "gaussian")

7.2 二维概率密度统计变换参数的设定

1
f + stat_bin2d(bins = 30, drop = TRUE)
1
f + stat_binhex(bins = 30)
1
f + stat_density2d(contour = TRUE, n = 100)

7.3 三维数据的统计变换参数设定

7.3.1 等高线图

1
m + stat_contour(aes(z = z))

7.3.2 线段图

1
m+ geom_spoke(aes(radius= z, angle = z))

7.3.3 六角形图

1
m + stat_summary_hex(aes(z = z), bins = 30, fun = mean)

7.3.4 栅格图

1
m + stat_summary_2d(aes(z = z), bins = 30, fun = mean)

7.4 组间比较

7.4.1 箱线图

1
g + stat_boxplot(coef = 1.5)

7.4.2 提琴图参数设定

1
g + stat_ydensity(adjust = 1, kernel = "gaussian", scale = "area")

7.4.3 累积曲线

1
f + stat_ecdf(n = 40)

7.4.4 分位数曲线图

1
f + geom_quantile(quantiles = c(0.25, 0.5, 0.75), formula = y ~ log(x), method = "rq")

7.4.5 Loess回归以及置信区间统计变换的参数设定

1
2
f + geom_smooth(method = "auto", formula = y ~ x, se = TRUE, n = 80, fullrange = FALSE, level = 0.95)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

7.4.6 绘制dnorm的概率密度分布

1
ggplot() + stat_function(aes(x = -3:3), fun = dnorm, n = 101, args = list(sd=0.5))

7.4.7 绘制散点图

1
f + stat_identity()

7.4.8 绘制qq图

1
ggplot() + stat_qq(aes(sample=1:100), distribution = qt, dparams = list(df=5))

7.4.9 绘制散点图, 点的大小为该点数据出现的次数

1
f + stat_sum()

7.4.10 带误差线的点图

1
2
f + stat_summary(fun.data = "mean_cl_boot")
## Warning: Removed 3 rows containing missing values (geom_pointrange).

7.4.11 无重复散点图

1
f + stat_unique()

8 图例

ggplot2 的图例与图形是一个整体, 设定图例的参数, 图例会更改, 设定图形的参数, 图例会自动更改。scale 控制图形中的颜色,文字显示, 图例中的图形。

1
2
n <- b + geom_bar(aes(fill = fl))
n
1
2
3
4
5
6
##### 柱状图设定颜色, 各组名称, 图例中各组名, 类别划分
n + scale_fill_manual(
values = c("skyblue", "royalblue", "blue", "navy"),
limits = c("d", "e", "p", "r"),
breaks =c("d", "e", "p", "r"),
name = "fuel", labels = c("D", "E", "P", "R"))

8.1 坐标轴的控制

按照数据的类别, 分为

1
2
3
4
5
6
7
8
scale_x_continuous()
scale_x_discrete()
scale_x_identity()
scale_x_manual(values = c())
scale_y_continuous()
scale_y_discrete()
scale_y_identity()
scale_y_manual(values = c())

这几个函数的参数主要为:

  •  alpha,     透明度
    
  •  color,     颜色序列
    
  •  fill,     颜色序列
    
  •  linetype,     线段类型
    
  •  shape,     点的形状
    
  •  size,     点的大小
    

8.1.1 x轴显示日期

1
2
library(scales)
scale_x_date(labels = date_format("%m/%d"), breaks = date_breaks("2 weeks"))

8.1.2 x轴显示为日期和时间

1
scale_x_datetime()

8.1.3 x轴转换为以10为底的对数

1
scale_x_log10()

8.1.4 x轴逆向显示

1
scale_x_reverse()

8.1.5 x轴平方根变换

1
scale_x_sqrt()

9 颜色

颜色主要用来显示分组,或者数据的连续梯度变化。

9.1 颜色设定

在ggplot2中,可以通过scale_fill_brewer(palette = “”)函数,可以将色系调整为以下任何一种。

9.1.1 最大差异色系 Diverging

BrBG, PiYG, PRGn, PuOr, RdBu, RdGy, RdYlBu, RdYlGn, Spectral

9.1.2 离散色系 Qualitative

Accent, Dark2, Paired, Pastel1, Pastel2, Set1, Set2, Set3

9.1.3 序列色系 Sequential

Blues, BuGn, BuPu, GnBu, Greens, Greys, Oranges, OrRd, PuBu, PuBuGn, PuRd, Purples, RdPu, Reds, YlGn, YlGnBu, YlOrBr, YlOrRd

通过aes设定分组之后,如fill, color, group等,ggplot会自动设定颜色。点图、栅格图等连续变量,默认为深蓝色色系(“Diamond\nclarity”)。

调整图形颜色的函数还包括:

  •  `scale_colour_brewer`
    
  •  `scale_fill_brewer`
    
  •  `scale_colour_distiller`
    
  •  `scale_fill_distiller`
    
  •  `scale_colour_gradient`
    
  •  `scale_fill_gradient`
    
  •  `scale_colour_gradient2`
    
  •  `scale_fill_gradient2`
    
  •  `scale_colour_gradientn`
    
  •  `scale_fill_gradientn`
    
  •  `scale_colour_grey`
    
  •  `scale_fill_grey`
    
  •  `scale_colour_hue`
    
  •  `scale_fill_hue`
    

等多种,分别用来对画布中的点线面进行不同的填充设色等。

1
n <- b + geom_bar(aes(fill = fl))

9.1.4 R中调色板设置

1
n + scale_fill_brewer(palette = "Blues")
1
n + scale_fill_brewer(palette = "BrBG")

9.1.4.1 R中的灰色梯度显示柱状图

1
n + scale_fill_grey( start = 0.2, end = 0.8, na.value = "red")

9.1.4.2 通过 scale_fill_gradient显示颜色过渡

1
2
3
o <- a + geom_dotplot(aes(fill = ..x..)) 
o + scale_fill_gradient( low = "red", high = "yellow")
## `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

9.1.4.3 通过scale_fill_gradient2显示颜色过渡

1
2
o + scale_fill_gradient2( low = "red", high = "blue", mid = "white", midpoint = 25 )
## `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

9.1.4.4 选择颜色序列

1
2
o + scale_fill_gradientn(colours = terrain.colors(6) )
## `stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.

其他可以选择的颜色: rainbow(), heat.colors(), topo.colors(), cm.colors(), RColorBrewer::brewer.pal()

10 形状

绘制散点图时,不同形状的点表示分组,ggplot2已经尽可能做了最优化处理。以保证各组点的形状都能做较好区分。如果要表示的分组数量太多,ggplot2会给出相应警告。

10.1 按照形状分组

10.1.1 点图标的选择

1
p <- f + geom_point(aes(shape = fl))

10.1.2 显示空心图标

1
p + scale_shape(solid = FALSE)

10.1.3 指定点图标

1
p + scale_shape_manual(values = c(3:7))

10.2 更改图标大小

1
2
#### 设定图标大小与变量的关系q <- f + geom_point(aes(size = cyl)) 
#### 设定图标大小的范围q + scale_size_area()

11 坐标系

每个图形,只能设定一个坐标系。默认情况下,ggplot2使用平面直角坐标系。用户可以指定使用极坐标coord_polar,也可以通过coord_trans,coord_flip等对坐标轴的刻度进行相应变换。

11.1 平面直角坐标系

1
2
r <- b + geom_bar()
r + coord_cartesian(xlim = c(0, 5))

11.2 横轴、纵轴以固定比例显示

1
r + coord_fixed(ratio = 1/2)

11.3 横轴纵轴调换

1
r + coord_flip()

11.4 极坐标, 适用于绘制饼图

1
r + coord_polar(theta = "x", direction=1 )

11.4.1 横轴、纵轴的变换,如 log, sqrt等

1
r + coord_trans(y = "sqrt")

11.5 设定坐标轴范围

1
2
3
4
t + coord_cartesian(xlim = c(0, 100), ylim = c(10, 20))
## NULL
t + xlim(0, 100) + ylim(10, 20)
## NULL

12 细节调整

12.1 柱状图的叠加以及比较

12.1.1 并排排列

1
2
s <- ggplot(mpg, aes(fl, fill = drv))
s + geom_bar(position = "dodge")

12.1.2 堆叠排列

1
s + geom_bar(position = "stack")

12.1.3 按百分比堆叠排列, 各柱子等高

1
s + geom_bar(position = "fill")

12.1.4 散点图的随机化

在每个点的x,y方向上都加上较小的随机值, 以便点能散开。

1
f + geom_point(position = "jitter")

13 绘图主题与风格

所谓主题,就是绘图的风格。通过设定图形的主题,可以生成各种风格的图形。

ggplot2自身提供了一些主题,如:

  •  `theme_grey()`
    
  •  `theme_gray()`
    
  •  `theme_bw()`
    
  •  `theme_linedraw()`
    
  •  `theme_light()`
    
  •  `theme_dark()`
    
  •  `theme_minimal()`
    
  •  `theme_classic()`
    
  •  `theme_void()`
    
  •  `theme_test()`
    
1
2
3
4
t <- ggplot(mpg, aes(cty, hwy)) + geom_point()
t + theme_grey()
t + theme_classic()
t + theme_minimal()

ggthemes程序包(https://jrnold.github.io/ggthemes/reference/index.html)提供了更多主题,加载后,即可与ggplot2混合使用)提供了更多主题,加载后,即可与提供了更多主题,加载后,即可与ggplot2混合使用)ggplot2混合使用提供了更多主题,加载后,即可与ggplot2混合使用)。

  •  `theme_base()`:     模拟plot()的风格
    
  •  `theme_calc()`:     LibreOffice     Calc风格
    
  •  `theme_economist()` :     经济学家杂志风格
    
  •  `theme_economist_white()`:     经济学家杂志
    
  •  `theme_excel()`:     微软Office     Excel传统风格
    
  •  `theme_excel_new()`:     微软Office     Excel最新风格
    
  •  `theme_few()`:Few’s     “Practical Rules for Using Color in Charts”
    
  •  `theme_fivethirtyeight()`:     Theme     inspired by fivethirtyeight.com plots
    
  •  `theme_foundation()`
    
  •  `theme_gdocs()` :     google文档风格
    
  •  `theme_hc()`:     Highcharts     Theme
    
  •  `theme_igray()`:     逆向灰色梯度风格
    
  •  `theme_map()`:     简约地图风格 Clean     theme for maps
    
  •  `theme_pander()` :     A     ggplot theme originated from the pander package
    
  •  `theme_par()`:     Theme     which uses the current ‘base’ graphics parameter values from     par(). Not all par() parameters, are supported, and not all are     relevant to ggplot2 themes.
    
  •  `theme_solarized()` `theme_solarized_2()`:     ggplot     color themes based on the Solarized palette
    
  •  `theme_solid()`:     Theme with nothing other than a background color
    
  •  `theme_stata()`:     Stata统计软件绘图风格
    
  •  `theme_tufte()`:Tufte     Maximal Data, Minimal Ink Theme
    
  •  `theme_wsj()`:华尔街日报风格     Wall     Street Journal theme
    

更多细节调整,可以查看theme()函数。

14 图形分面 facet

当要按照某一个因子的不同水平,将每个水平分别展示在不同的图形时,可以使用图形分面。例如,各省份GDP的逐年变化,可以按照年份绘制多个地图,每个小地图(分面)只展示该年份的GDP即可。

1
2
3
###按照因子组合绘制多图
t <- ggplot(mpg, aes(cty, hwy)) + geom_point()
t + facet_grid(. ~ fl) ### 按照列, 排列不同 fl
1
t + facet_grid(year ~ .)  ### 按照行, 排列不同 year
1
t + facet_grid(year ~ fl) ### 行为 year, 列为 fl
1
t + facet_wrap(~ fl)      #### 设定显示为几行几列, nrow = NULL, ncol = NULL
1
2
#### 每幅图小标题的显示
t + facet_grid(. ~ fl, labeller = label_both)
1
t + facet_grid(. ~ fl, labeller = label_bquote(alpha ^ .(x)))
1
t + facet_grid(. ~ fl, labeller = label_parsed)

15 标题和坐标轴

15.1 更改标题和坐标轴名称

默认情况下,ggplot2绘制的图形并没有标题,添加标题,可以用ggtitle函数。

1
t + ggtitle("New Plot Title")  ### 标题
1
t + xlab("New X label")        ### x轴标题
1
t + ylab("New Y label")        ### y轴标题
1
t + labs(title =" New title", x = "New x", y = "New y") ### 同时设定标题, xy轴标题

ggtitle添加的标题默认是向左排列的,要设置标题居中,则用theme函数。

1
2
t + ggtitle("New Plot Title")+
theme(plot.title = element_text(hjust = 0.5))

15.2 图例位置

1
2
3
t2 <- ggplot(mpg, aes(cty, hwy, color = trans)) + geom_point()
t2 + theme(legend.position = "bottom")
###"bottom", "top", "left", or "right"
1
t2 + guides(color = "none")
1
t2 + scale_fill_discrete(name = "Title", labels = c("A", "B", "C"))

15.3 添加标注

而在ggplot2中,使用的是annotate()。annotate可以添加,文字、多边形或者任何其他geom对象。

16 绘制地图

16.1 geom_map

1
2
3
4
5
6
7
8
data <- data.frame(murder = USArrests$Murder,
state = tolower(rownames(USArrests)))
map <- map_data("state")

l <- ggplot(data, aes(fill = murder))

l + geom_map( aes(map_id = state), map = map ) +
expand_limits( x = map$long, y = map$lat )

16.2 geom_polygon

1
2
3
4
5
6
7
### 地图投影变换
### see:
library(maps)
thismap = map_data("world")
ggplot(thismap, aes(long, lat, group=group)) +
geom_polygon(fill="white", colour="gray") +
coord_map(projection = "ortho", orientation=c(41, -74, 0))

16.3 geom_sf

ggplot2 程序包还可以支持sf程序包的对象,geo_sf系列函数可以较为方便地生成地图。

由于sf程序包的st_read, st_transform, st_as_sf提供了读取和转换空间数据的办法,因此通过sf读取和处理空间数据,用ggplot2进行可视化,不失为很好的选择。

1
2
3
4
5
stat_sf()
geom_sf()
geom_sf_label()
geom_sf_text()
coord_sf()

17 保存图像

ggplot2的ggsave函数,可以根据图形的扩展名, 将ggplot2绘制的图形保存为相应的文件格式,默认保存7×7英寸, 300dpi的图形。

1
ggsave()

18 进一步阅读

  •  [http://www.cookbook-r.com/Graphs/](http://www.cookbook-r.com/Graphs/)
    
  •  https://www.rstudio.com/resources/cheatsheets/
    
  •  Hadley     Wickham (2010). A layered grammar of graphics. Journal of     Computational and Graphical Statistics, 19(1), 3-28.
    
  •  Wilkinson,     L. (2012). The grammar of graphics. In Handbook of Computational     Statistics (pp. 375-414). Springer, Berlin, Heidelberg.
    
  •  Wilkinson,     L. (2011). ggplot2: Elegant Graphics for Data Analysis by WICKHAM,     H. Biometrics, 67(2), 678-679.
    
  •  Hadley     Wickham (2007). Reshaping Data with the reshape Package. Journal of     Statistical Software, 21(12),     1-20. [http://www.jstatsoft.org/v21/i12/](http://www.jstatsoft.org/v21/i12/).
    
  •  Hadley     Wickham, Romain François, Lionel Henry and Kirill Müller (2019).     dplyr: A Grammar of Data Manipulation. R package version     0.8.0.1. [https://CRAN.R-project.org/package=dplyr](https://cran.r-project.org/package=dplyr)