为什么不要把引进的青年教师称为“论文写手”?

最近,南京林业大学李明阳教授的博文《人才引进背后的隐忧》引发热议, 各大网络媒体竞相转载。由于受到多方关注, 新华社主办的《半月谈》杂志还就此发表文章《引进林学人才,竟不认识树木?行业院校争抢“论文写手”引人忧》。

这篇博文讨论了引进人才的标准、数量及其与现有人才的关系。文中强调,一些农林院校最近几年引进的人才 “基本上是在利用开放式数据源、在电脑上玩模型的论文写手。一个林业专业学科,引进的师资不认识树木、没有野外调查实践经验,天晓得如何胜任教学任务” ,“大部分以补充师资身份引进的青椒在成长的初期以消耗资源为主” ,“除了C9集团少数以科研为主导的一流高校外,绝大部分学校绝大部分教师的主要工作还是教书育人” 。

李教授的这篇博文, 可谓针砭时弊, 列出了当前高校引进人才的一些问题,例如只看论文影响因子和数量,忽略人才在教学等方面的能力等。诚然,引进的人才的标准和数量, 不同人会有不同的看法。由于资源有限,引进的人才与在职人员也存在各种矛盾, 特别是待遇方面。不过要看到,绝大部分人才引进单位在引进人才之前,用人单位是经过充分论证的,特别是引进人才的科研水平,更是要经得起考验。恐怕没有哪一所大学愿意引进无科研论文发表的“人才”。

1. 学术论文的形式与内容

当前, 对科研人员的评价标准主要是看他/她能否在国际重要期刊发表一定数量的研究论文。研究论文是科学家最主要的交流媒介,报道新发现,提出新理论,对原有理论进行批评和改进,评论研究现状并做出进一步展望等等,都是通过发表学术论文进行的。

为什么一定要在期刊上进行讨论,而不是通过博客或者QQ群,微信群讨论呢? 这是因为研究论文需要对针对某一个问题的知识体系进行系统梳理:学术论文要说清楚前人做了什么,有什么观点,问题在什么地方,哪些地方还不清楚,作者的理论和假设是怎样的,应该如何检验,数据是怎样采集的,怎样分析的,得到了什么结果,结果的意义是什么等。论文不但要充分涉及这些方面,而且每一个论点和证据都要提供详细的参考文献,列出前人在某一个问题的贡献,并提供文献的作者、年份、题目、期刊、卷、页码等。如果研究中使用了软件,不仅要列出软件名称, 还要提供软件的版本,甚至获取方式和获取日期。近几年兴起的可重复研究(reproducible research), 更是提倡作者提供原始数据和计算机代码(如R\Python\Matlab\SAS的原代码)。 由于涉及的内容复杂,为了方便理解和撰写,学术期刊上发表的论文要遵循十分严格的范式,学术论文一般分为前言、材料与方法、结果、讨论等几大部分,并有摘要、参考文献,并常有附录。因此,有人甚至戏称学术论文比八股文更为八股。

学习过学术写作的人都知道,学术写作所用的语言要求平实易懂,与文学语言有所区别。在小说、诗歌、散文中,为了传递情感,语言常常有浓厚的感情色彩。然而学术论文主要是陈述事实、阐述思想,要求句式简单,易于理解。同是文章,学术论文行文要求有理有据,与小说和博客的文字是有很大区别的。

2. 发表学术论文的难度

“写手”这个词本无贬义, 但是用在这种语境下, 就有一定的贬义。笔者认为, “写手”这种提法是不合适的。 “写手” 原本是指会写东西的人,可泛指各种从事写作的人:写博客的人可称为写手, 写网络小说的人也可以称为写手。然而将写学术论文的年轻学者称为“写手”, 难免会让不了解学术研究, 不了解学术论文写作的人产生误解:认为科研论文人人都能写。如果科研论文人人都能写, 那么大学何苦花重金引进科研人才?

科研论文从形式和内容的复杂性已经决定撰写时要耗费极大精力。然而这还不是全部,因为学术论文的灵魂是创新,论文当中或多或少要有新的发现、新的认知。新发现和新认知,是科学能够不断提升人类对自然认知的保证,也是科学研究最重要的意义。一篇学术论文是否能够在主流刊物发表,其创新性、研究的合理性,撰写等都非常重要。而这些都要经过同行评议。论文能否发表,不是取决于作者自己,也不是取决于期刊的编辑,绝大部分论文都要经过短则一、两个月,长则一年多的审稿过程。稿子是谁来评审呢?一般是研究方向相同或者相近的2到3位匿名审稿人,有时候甚至是双盲审稿,稿件作者不知道审稿人是谁, 审稿人不知道稿件作者是谁,以保证评价的客观和公正。由于研究和论文难免有一定的缺陷或者瑕疵,或者由于稿件写的不够好,如逻辑不清, 语言不过关等,拒稿是家常便饭。 有些期刊的拒稿率甚至高达90%。越是重要的期刊,文章接受发表的难度也越大。

世界上从事科研工作的人很多,但是主流的期刊数量有限。主流期刊,一般是业界关注率比较高的期刊。在这些期刊上发表的论文,其他同行比较容易见到,所以研究的成果也更容易受到关注。以生物地理学和群落生态学为例, SCI影响因子较高的期刊,一般是主流期刊, 而排在最前面的,有时候也称为“权威”期刊。这些刊物包括 Nature , Science, PNAS, Ecology Letters, Ecological Mongraphs, The American Naturalist, Global Ecology and Biogeography, Journal of Biogeography, Ecography, Ecology, Journal of Ecology, Oikos, Diversity and Distributions等。 只有将自己的研究成果发表在这些刊物上,才更容易受到国际同行的关注和承认。如果论文没有发表在这些刊物上, 并不是说研究就一定不重要或者不好, 但是难以获得学术界关注和承认是肯定的。如果科研人员没有重量级的论文发表,就难以获得学术界承认,基本上只能自娱自乐了。 这也是为什么顶尖学者一定要将研究成果以论文的形式发表在主流刊物上。

3. 科研是怎样促进教学的?

李教授的博客中提到, 一些引进的人才只会写论文,连认树木都不认识, 难以承担教学任务。笔者认为这基本上是杞人忧天, 而且将科学研究与教学对立起来是不好的。

现代大学的功能,主要包括通过传播思想、知识和技能,进行科学研究与技术开发等为社会服务,同时为社会发展提供人才等,保证科学和文化能够很好的传承。由于历史原因, 我国的高等院校有理工、农林、师范、综合院校等区别,但若要满足社会发展的需求,若以李教授提到的C9院校以科研为主,其他院校以“教书育人”为主是不妥的。如果C9以外的院校都不做科学研究, 只做教学, 那么这些大学是否能满足社会发展的要求?只重教学不做科研的后果, 当然就是无论文产出,老师缺乏课题经费,学校学术声望降低,学校排名下降, 最后学生是否愿意就读都成问题,何谈学校发展? 何谈大学的社会责任?

当然,在这样学校里经历过“教书育人”熏陶的学生仍然会对社会有所贡献。 但是不做科学研究, 不了解研究进展的教学,究竟会优秀到何种程度还很难说。我国大学教材中的知识体系和方法上, 在一定程度上落后于欧美一流大学的教材。原因之一可能是编写教材的老师,很难有精力大量阅读国际上最前沿的进展并编写到课本中,以致中文教材滞后于同时期欧美英文教材。当代科学研究学科划分十分精细,技术和认知更新都很快, 如果只从事教学而不做研究,不写论文,甚至很难读懂最新的研究进展,势必对教学有很大的影响。

教学与科研应该是相辅相成的,而不应该是”论文写手连树木都不认识,何谈教学?”。恰恰是因为这些引进的青年人才在写论文, 能够了解最新的研究进展, 才能将新知识和新技能传授给学生,在教学过程中能启发学生进行批判性的思考, 从而达到更好的教学效果。如果只以“不认识树木”作为单一的评价标准,对这些青年教师来讲是不公平的。他们所教的课程,是否一定要求“认识树木”? 认识多少种树算认识树木? 他们的课堂,学生是否满意? 是否达到了学校的教学要求,这些恐怕并不是“认识几种树木”那么简单。如果授课教师未能达到教学要求,最早有意见的恐怕是学生本身。没有经过学校和学院的批准,教师是否能开展教学工作? 不能完成教学任务,管理机构难道会坐视不管?

4. 不做实验的科研不是好的科研吗?

博文中说,这些引进的人才, 基本上是“利用开放式数据源、在电脑上玩模型的论文写手”,然而利用开放式数据源, 通过运行模型的结果撰写论文是近些年兴起的生物信息学和生物多样性信息学的主要方法。如果认为研究人员不自己做实验,亲自收集数据就是在钻科研的空子,其实是十分荒谬的。

近年来,生命科学从宏观上和微观上都积累了海量的数据, 如保存DNA序列、蛋白质序列和基因组学信息的Genbank数据库, 保存物种分布数据的GBIF、 NSII数据库, 保存全球地形、气候、植被、土壤的USGS数据库,保存植物功能性状的TRY数据库, 保存物种化石记录和分化时间的 TIMETREE (http://www.timetree.org/)网站 , 还有诸如地震数据、人口数据、光污染数据库等等。 这些数据库基本上实现了开放获取。 例如,要查询某一个种在世界范围内的分布情况,是否濒危,查询GBIF数据库就可以了。这些信息在不同的时空尺度有一定的规律性,找出其中的规律以及理解背后的机制,正是科研工作者的重要任务。通过实验收集数据,获得的新认知是科学发现,而对现有大数据进行深入分析, 获得的新认知也是科学发现, 并不存在谁优谁劣的问题。前文提到,在学术领域, 发表科研论文是要经过同行评议的, 现代科学的主要发现是通过学术论文展示的,既然能够在“权威期刊”上发表学术论文, 研究的重要性当然是有目共睹的。

当然, 不排除有些作者以发论文为目的,论文的方法和材料都缺乏创新性,但是这样的论文即使能发表, 在学术界也没有多少人关注,很难发表在主流期刊,更谈不上权威期刊。科研人员的时间和精力有限, 大部分人是想做出出色的原创性成果的。诚然,大部分研究只能对学科发展做出有限的推进,不过质变是建立在量变基础上的,证据不断积累,学科之间不断融合,才能促进新的理论或者新的方法的诞生。

前文提到的论文,为一般的研究论文,但是科学论文还有综述性论文等。综述又分为描述性综述和系统性综述。Meta analysis(整合分析)就是综述的一种。在meta analysis中,研究人员在充分搜集文献的基础上, 从现有文献提取数据,然后根据每个研究的样本量给予适当权重,再进一步计算各结果的重要性等从而做出判断。Meta analysis不仅阐述某一问题的研究进展,也会对相应的理论机制进行深入探讨,从而得出一些结论,获得新的认知。Meta analysis也不做实验,只是提取和汇总数据, 然后运行通过软件得出结果,但由于确实能加深人们对事物的认知,有理有据, 所以也能够以重量级的科研论文形式发表, 而且在学术界也很受欢迎。

5. 人才引进与青年教师的生存困境

当前, 青年教师的生存状况总体上令人忧虑,但这是否是由于人才引进导致的? 引进的青年人才是否在生活上无后顾之忧,从而一心扑在教学和科研第一线呢? 当然, 高房价、高生活成本与高校青年教师微薄的薪水之间形成强烈的反差, 而发表论文,获得科研项目支持, 对于职称晋升, 改善青年学者的生存状况至关重要。从国外或者外校引进的青年教师,在待遇上可能确实相对好一些,但是仍然面临很大的生存压力。毕竟在科研领域,不发表论文, 没有研究成果,就不可能拿到基金资助,不能晋升职称,此时就很难谈上事业上的发展。指出本校人才和引进人才待遇之间的不公平当然是好的,但是人们更为期待的是解决这些矛盾的具体措施和具体建议。

6. 结论

青年教师是大学科研、教学的中坚力量。青年教师在科研和教学领域投身一线工作都是需要鼓励和爱护的。如果将能写论文的青年教师贬称为“写手”,那么所有的科学家或许都是“写手”了。

参考

http://www.banyuetan.org/jy/detail/20180814/1000200033136041534209038987589123_1.html

http://blog.sciencenet.cn/blog-814548-1123826.html

生态学家、生态学研究与媒体

最近,中国科学院植物研究所一项雾霾与植物生长的研究结果表明,雾霾可能能促进树木生长,研究人员记录和分析了白杨在雾霾天的生长情况,深入探讨了其中的可能机制,研究成果发表在Global Change Biology上[1]。昨天,《中国青年报》以《雾霾越深,森林越壮》为标题介绍了这项研究[2],报道刊登到网站后,主要门户网站如中新网、新浪、网易等竞相转载[3,4,5]。一时间,该研究在网友中间引起轩然大波,质疑声和咒骂声不断。

其实这并不奇怪。

雾霾,本来就是人们避之所不及,人人谈之色变。通过科学实验得出雾霾能促进树木生长的结论,很容易让人以为是荒谬至极。很多人并没有阅读论文的原文,只是看了该报道,甚至只是看了标题就开始批判。网友评论也是一边倒,大有声讨生态学家智商之意。

不过事实并不这么简单。从论文原文来看,中科院植物所的科学家们并没有去评判雾霾的好坏,该研究旨在探讨雾霾是怎样促进树木生长的,这属于理论研究的范畴。而这种理论上的研究或者探讨,是在学术讨论范围内的。为了理解自然,我们需要收集数据与发现新现象,并探讨现象背后的机制是什么。虽然我本人不做全球变化、元素循环或污染等相关研究,但据我所知,探讨植物对气候变化与污染的响应过程和机制对于深刻理解全球变化,更好地应对环境污染是十分重要的,相关研究是关乎国计民生的知识及理论储备,是环境保护以及正确决策的前提,因此该研究仍然具有很重要的意义。

生态系统是非常复杂的开放系统,在生态学研究中,不同情形下得出的结论很可能完全相反。研究过程中除了结论本身有重要意义以外,实验或者数据分析用到的新方法,开发出的新工具也具有非常重要的价值,这是一些网友所不了解的。在互联网如此发达的今天,还有部分网友用二分法看问题,非黑即白,简单粗暴地对科研人员进行人身攻击,显然是不妥的。

当然,类似的新闻报道媒体也可能有一定责任。科学家在接触媒体时要很小心,因为有些媒体会在不提供研究背景的情况下,将一些结论或者学术讨论过度解读。更有些媒体为了博人眼球,刻意渲染在某些特定条件下才成立的结论。公众在这些报道的误导下,所了解的是失真、偏颇的研究进展或结论。而舆论一旦被引导到这个陷阱中,就可能对学术研究,甚至科学家造成伤害。

类似事件国外也有。去年年底,美国《华盛顿邮报》刊登了一篇文章,《濒危种无需保护,因为灭绝是进化的一部分》[6]。这篇文章的作者Alex Pyron是一所大学的副教授,进化生物学家,主要研究两栖和爬行动物在地质历史上的物种灭绝。在他看来,进化过程中出现物种灭绝是再自然不过了。但是他可能没有和《华盛顿邮报》沟通好,观点刊出时才用了上面的题目。此文一出,立即受到保育人士和公众的猛烈批评[如7],为此,Pyron不得不公开道歉。

人人都喜爱清新的空气,没有人喜欢雾霾,相信树木也如此。植物所的这项研究,应该只是想澄清雾霾过程中植物是怎样响应的。当然,从实验用的杨树推广到整个森林生态系统未必合适,而新闻报道的题目更值得商榷。但无论怎样,在这个时代,科学家都需要更为宽松自由的学术环境。在现在这种情况下,接触媒体时谨慎一些都是好的,而一些网友也需要提高自身的判断力。

参考:

[1] Wang X, Wu J, Chen M, et al. Field evidences for the positive effects of aerosols on tree growth. Glob Change Biol. 2018;00:1–10. https://doi.org/10.1111/gcb.14339

[2] http://zqb.cyol.com/html/2018-07/18/nw.D110000zgqnb_20180718_1-11.htm

[3] http://news.sina.com.cn/o/2018-07-18/doc-ihfnsvyz7451437.shtml

[4] http://www.chinanews.com/sh/2018/07-18/8570635.shtml

[5] https://3g.163.com/all/article/DN0H3I2A0001875N.html

[6]https://www.washingtonpost.com/outlook/we-dont-need-to-save-endangered-species-extinction-is-part-of-evolution/2017/11/21/57fc5658-cdb4-11e7-a1a3-0d1e45a6de3d_story.html?noredirect=on

[7] http://evol-eco.blogspot.com/2017/11/of-course-we-need-to-save-endangered.html

物种分布模型相关的R程序包列表

最新版本参见 https://github.com/helixcn/sdm_r_packages

前言

自从BIOMOD程序包在CRAN发布以来,众多的生态学家将注意力集中到R。

这是因为:

  1. 用R语言开发软件包相对容易,R中的数据对象类型容易学习和理解,数据读取等也非常容易。
  2. 近些年诞生的一些R程序包,让R十分方便地处理shape文件和raster文件等, 这就让物种生态位建模中加载环境图层,读写其他软件安生成的文件以及保存结果非常方便。
  3. 绘图是R的优势之一,用户一般不需要特别复杂的编程,就可以生成精美的图形,而物种生态位模型研究中用图形展示结果非常重要。
  4. 计算性能方面,R程序可以与C或C++写的代码完美结合,克服了计算瓶颈。这就让物种生态位模型中常用的random forest, boosted regression trees, randomization test, cross validation, bootstrap等都能在可接受的时间内完成。
  5. R本身有较为完备的文档系统,近几年诞生的knitr, Rmarkdown等程序包, 让编写软件包指南变得非常容易。有了良好的文档系统, 用户也更容易学习和使用R程序包。
  6. R拥有庞大的用户群,通过R-sig邮件组, github以及stackoverflow等网站用户可以很快找到大部分问题的解决方案,其中当然也包括很多物种生态位模型预测相关的问题。

物种生态位建模的程序包很多,大部分在CRAN集中保存。不过CRAN上的程序包已经超过12000个,虽然CRAN task view已经按照程序包所属的类别分别做了介绍, 但是目前仍然没有一个专门针对物种生态位模型的CRAN task view。这些程序包混在这12000多个程序包中,难以寻找。 为此,本人整理了CRAN或者github上与物种生态位模型分析相关的程序包列表,希望能反映近几年的最新进展,以方便相关工作人员查找和使用。

由于掌握的信息有限,难免有很多错漏,望读者提出宝贵意见。

R程序包列表

  • adehabitatHS :分析动物栖息地
  • adespatial: 多元、多尺度物种分布空间分析, 维护者是Stephane Dray, 该程序包中的forward.sel函数与packfor包功能相似
  • ALA4R:查询澳大利亚The Atlas of Living Australia (ALA) 网站动植物分布记录
  • BIEN:查询NCEAS的BIEN数据库,包括物种分布记录、性状、样方数据和系统分类位置等 http://Bien.nceas.ucsb.edu/bien/
  • biogeo:用于检查分布点数据的质量,以提高物种分布模型的准确性。
  • biomod2:用于多种物种生态位模型的整合建模, 这是Wilfried Thuiller研究组开发的程序包, 是biomod的继承与发展。
  • bossMaps :用于将基于专家意见的物种分布图(如野外手册中的分布图)转换为连续分布面数据。用于进一步校正物种分布图
  • cocorresp:基于Co-CA方法,进行群落水平的物种相关性检验
  • coenocliner:群落生态学程序包, 作者Gavin Simpson, 用于模拟环境梯度上物种出现与否及其多度。
  • coenoflex: 蒙大拿大学David W. Roberts 开发的程序包, 用于模拟植被
  • coexist: 陈友华编写的物种共存分析的程序包
  • comclim: 群落结构与气候分析
  • CommEcol: 群落生态学数据分析
  • ConR: 估计物种分布区大小, 用于IUCN红色名录等级的分析
  • cooccur: 分析实地调查中物种共同出现的概率
  • CoordinateCleaner: 分布数据的校验, 特别是国家与地区水平,地名与经纬度是否相符等。 https://github.com/azizka/CoordinateCleaner
  • demoniche: 种群分布的空间分析
  • dismo: 物种生态位模型预测, 这是Robert Hijmans编写的程序包,功能繁多。作者的文档写得很清楚, 是入门的重要参考。
  • downscale: 基于粗尺度的物种分布区获得精细尺度的物种分布区 downscales species occupancy at coarse grain sizes to predict species occupancy at fine grain sizes (更多内容参见 http://www.meteo.unican.es/climate4R )
  • ecolottery: 用于模拟群落,可实现两种模拟,coalescent-based simulation, forward-in-time simulation
  • EcoSimR: 群落生态学研究中的零模型, 主要用于检测物种共存,计算生态位宽度等, 统计生态学名家N. Gotelli等人开发的程序包。
  • ecospat: 物种分布模型领军人物Antoine Guisan研究组开发的程序包, 用于进行空间生态学分析,特别是针对物种分布, 生态位, 群落构建等分析,有完整的工作流程 (http://www.unil.ch/ecospat/home/menuguid/ecospat-resources/tools.html)
  • ENiRG: 用R-GRASS进行物种分布区预测
  • ENMeval: 用于评估物种生态位模型,第一作者 Robert Muscarella 在群落生态学和宏生态学也有很深的造诣。
  • ENMTools: Dan Warren 开发的R程序包, 分析物种生态位进化。
  • EnvNicheR: 生态位宽度和重叠
  • FactorsR: 分析影响物种丰富度的因子及各因子的贡献
  • fitdistrplus: 物种多样性格局的模型与拟合
  • fuzzySim: 物种分布区数据的模糊化处理以及分布区预测
  • hSDM: 分层贝叶斯物种分布模型,该框架可使用 物种出现的01数据以及多度数据,结合生境适应性、空间关联、人为干扰以及物种被发现的容易程度进行分布区模型预测。 参考 https://onlinelibrary.wiley.com/doi/full/10.1111/ecog.02445
  • indicspecies: 基于物种多度和是否出现,计算生态位宽度等
  • iSDM: 入侵物种分布模型
  • jrich: 进化独特性及其Jack-Knife支持率分析 Jack-Knife Support for Evolutionary Distinctiveness Indices Iand W (https`](https://link.springer.com/chapter/10.1007/978-3-319-22461-9_11)
  • kissmig: 物种迁移预测
  • KnowBR: 基于物种分布数据评估某地点调查是否完整
  • letsR: 宏生态学研究中地理数据、物种分布数据和环境数据的处理与分析 (https://github.com/macroecology/letsR)
  • mapr: 利用spocc和rgbif等程序包获取的物种分布记录绘图,可生成基于leaflet的网页。
  • MaxentVariableSelection: 评估Maxent模型预测物种分布过程中,如何选取环境因子
  • maxlike: 利用极大似然方法估计物种分布区,直接生成分布概率。
  • maxnet: 用glmnet进行物种分布区预测 (https://github.com/mrmaxent/maxnet)
  • MetaLandSim: 分析景观水平物种分布区的变化以及全球变化带来的等影响等
  • MIAmaxent: 用于训练和筛选Maxent模型
  • mobsim: 群落物种分布和多度的空间模拟
  • modEvA: 用于物种分布区模型的评估 (http://modeva.r-forge.r-project.org/)
  • mopa: 基于物种生态位模型预测物种是否出现 (https://github.com/SantanderMetGroup/mopa/wiki) 用Pseudo-Absences方法进行物种分布区建模, 可基于Warren et al. (2008) 的方法计算物种生态位重叠
  • netassoc: 种间关联计算
  • nicheROVER: 生态位宽度与重叠
  • nodiv: 计算整合进化树和物种分布模型的两个指数 the specific overrepresentation score (SOS) and the geographic node diverg ence (GND) score (https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.12283)
  • paleobioDB: 查询PaleobioDB的记录,并进行简单可视化
  • pez: Pearse, Cadotte, Cavender-Bares, Ives, C. Tucker, Mat Helmus 等人编写的程序包, 用于群落系统发育分析,提供若干修正的指数以及 pglmm等。
  • phyloclim: 整合气候生态位进化以及系统发育, 可计算生态位重叠等,重建祖先分类单元的气候, 分析分布区大小和分化时间的关系,用随机化方法检验两个种生态位是否相等。
  • PresenceAbsence: 用于评估Presence-Absence模型的准确性,可计算confusion matrices, pcc, sensitivity, specificity, Kappa等指数并绘图等。
  • RADanalysis: 多度分布曲线分析
  • rangeBuilder: 物种分布数据的整理和标准化。Occurrence Filtering, Geographic and Taxonomic Standardization and Generation of Species Range Polygons
  • rangeMapper: 生活史性状的宏生态学分析平台,个体大小与地理分布的关系等
  • raptr: 确定优先保护区域, 本程序包基于商业软件Gurobi http://www.gurobi.com
  • rbison: 查询USGS ‘BISON数据库的R程序包,主要是北美物种分布数据 (https://bison.usgs.gov/#home)。
  • rCAT: 物种保护等级的评估,用于编写红色名录,包括计算物种分布区大小,分布区范围等。 由Kew Gardens编写。
  • rebird: 鸟类分布记录eBird数据库的R程序包接口,可用多种方式查询数据库
  • red: 计算IUCN红色名录评估过程中的一些指数,如分布区大小,分布的国家,海拔范围, 生成kml文件等。该程序包是进行物种濒危等级评估人员的重要工具。
  • redlistr: 用于IUCN红色名录评估过程中物种分布区变化,并推测未来分布区大小等
  • rfishbase: 查询http://www.fishbase.org 数据库中30000种鱼类的生物学、生态学、 形态学数据等
  • rgbif: GBIF的R接口程序包, 可查询物种名,记录数量,数据的meta信息以及绘图等。 https://ropenscilabs.github.io/occurrence-manual/
  • rinat: 访问iNaturalist网站获取物种分布数据
  • RInSp: 评估个体的生态位特化, 计算个体以及种群的生态位宽度 Arujo’s E, IS, Petraitis’s W, Roughgarden’s WIC/TNW
  • rioja: 第四纪数据分析 including constrained clustering, WA, WAPLS, IKFA, MLRC and MAT transfer functions, and stratigraphic diagrams.
  • rredlist: 查询 IUCN 红色名录数据库 http://apiv3.iucnredlist.org/api/v3/docs
  • rvertnet: 获取http://vertnet.org/数据库中脊椎动物数据, 可以按照物种和地点查询
  • sads: 物种多度分布的极大似然模型
  • sdm: 生态学家Miguel Araujo研究组的程序包。该程序包的特点是: 面向对象,分析可重复,可编写扩展组件。
  • SDMPlay: 主要用于生态位模型的展示与教学,包含两种模型BRT (Boosted Regression Trees) and MaxEnt (Maximum Entropy) ,同时提供AUC曲线等, 可评估模型的准确性。
  • sdmpredictors: 下载物种分布模型的数据, 包括古气候和预测的未来气候数据
  • SDMTools: 澳大利亚人开发的程序包,用于物种分布区模型的评估、可视化与比较分析等
  • sdmvspecies: 为物种分布区模型生成虚拟物种
  • SiMRiv: 模拟(动物)个体的运动
  • spacodiR: 群落多样性的空间及系统发育分析
  • SPECIES: 物种丰富度模型的拟合
  • SPEDInstabR: 分析ModestR软件给出的物种潜在分布区,确定影响物种分布的主要因素等
  • sperich: 估计物种分布区范围,并计算生物多样性热点地区等
  • spocc: 可查询各大物种分布记录的数据库, 包括 Global Biodiversity Information Facility (‘GBIF’), ‘USGSs’ Biodiversity Information Serving Our Nation (‘BISON’), ‘iNaturalist’, Berkeley ‘Ecoinformatics’ Engine, ‘eBird’, ‘AntWeb’, Integrated Digitized ‘Biocollections’ (‘iDigBio’), ‘VertNet’, Ocean ‘Biogeographic’ Information System (‘OBIS’), and Atlas of Living Australia (‘ALA’).
  • spThin: 基于空间分布,筛选物种分布记录 (Robert P. Anderson 组)
  • SSDM: Stacked Species Distribution Modelling, 基于Shiny界面的物种生态位模型预测。 该程序包能一次预测多个物种,并且有良好的界面支持。
  • subniche: 群落中生态位变化的补偿指数 Complementary indexes calculation to the Outlying Mean Index analysis to explore niche shift of a community and biological constraint within an Euclidean space, with graphical displays.
  • Traitspace: Laughlin研究组开发的程序包,可基于分层贝叶斯模型,用性状数据等估计物种在群落中出现的多度。
  • untb: 模拟中性理论中的Ecological Drift
  • usdm: 物种分布模型中的不确定性分析
  • vegdata: 从 http://www.synbiosys.alterra.nl/turboveg/http://www.vegetweb.de 两大植被网站下载数据,并提供植物名称处理的相关函数。
  • velociraptr: 古生物学数据下载、清洗、剔除和分析。
  • wallace: 物种分布区模型预测,使用Shiny GUI,用户可自己开发分析组件。 具备完成的分析流程,另可下载相应代码 (https://wallaceecomod.github.io/)。
  • zetadiv: 计算zeta-diversity和物种组成变化
  • zoon: 可重复性,可分享的物种分布区预测流程

请教问题时的几个“请”字

如果你请教问题:

  1. 请留下真实姓名和工作单位

  2. 请先认真阅读软件说明书

  3. 请提供可重复的例子,包括数据和源代码

  4. 请说明操作系统和版本

  5. 请提供软件的版本

  6. 请在提问之前google或者百度相关问题

  7. 请先在论坛或者QQ群提问,或者在微信群咨询

  8. 请保证你的软件操作路径和操作系统登录名不含中文

  9. 请给回邮件的人以足够的时间,一般需要72小时以上

  10. 请在给作者发邮件之前三思

诗一首:吐露港的午夜

29度的海风

带来了大海的温柔与睡意

 

午夜的天空

云彩高悬

细小的雨滴

轻轻打在眉宇间

 

透过云朵间的空隙

星星们勉强呼吸

对岸的车子仍在奔跑

不知疲倦

在雨里,在风中

是否也孤独到无法入眠?

 

小艇睡着了

鱼儿也睡着了

马达声还在远处

海面上波光点点

2018年7月3日

用tmap程序包绘制各省植物标本数量

下载本文的Rmarkdown源代码以及数据

herbarium_records.xlsx

tmap.Rmd

在R中绘制地图原本是困难的。困难之处在于绘图的组件分散于不同程序包中,而每个程序包只能实现一部分功能:有些只能实现投影转换, 有些只能添加指北针或比例尺,有些只能处理栅格数据, 能够导入shape文件的,又不能实现渲染……不难想象,在R中绘制地图,需要多么熟悉流程,并记住多少命令。

不过tmap包诞生之后,上述困难都已成为过去。一切原来可以如此简单……

tmap的语句类似于ggplot2,但是其调用方式更符合传统R用户的习惯, 即通过参数控制图层的效果。除了在设定投影上较为不便之外,其他功能,如数据读取,图像保存,渲染,添加比例尺和指北针,添加坐标点,添加图例以及对各图层的控制,都是用户梦寐以求的。

下面的代码用于绘制广西植物所研究所标本馆2008年各省份标本数的空间分布。读者可借此了解tmap命令的简洁与优雅:

省份province 植物标本数n_specimens
河北 1612
山西 823
内蒙古 269
辽宁 1754
吉林 794
黑龙江 610
江苏 532
浙江 505
安徽 480
福建 998
江西 4264
山东 231
河南 716
湖北 1192
湖南 8143
广东 27425
广西 100372
海南 17514
四川 13672
贵州 3296
云南 8944
西藏 112
陕西 4024
甘肃 756
新疆 662
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
setwd("C:/Users/jlzhang/Desktop/New folder (2)")
#### 导入所需要的程序包
library(openxlsx)
library(rgdal)
library(dplyr)
library(tmap)
library(tmaptools)
rm(list = ls())
## 删除所有对象
## 广西植物研究所各省标本记录 (林春蕊等 2008)
nspecimens <- read.xlsx("herbarium_records.xlsx")## 读取地图
country <- readOGR("bou1_4l.shp") ## 国界
province <- readOGR("province_polygon.shp") ## 省界
province$ID <- as.character(province$ID)
## 默认为WGS84坐标系,
## 如果shp文件自带投影文件, 则读取投影文件
# 更多投影参见
# 指定 EPSG 编号即可
# 注意:生成的图形采用西安80坐标系,高斯-克吕格投影,指北针的方向并不指向正北

country <- set_projection(country, projection = 2343) ## 西安80坐标系,高斯-克吕格投影
province <- set_projection(province, projection = 2343) ## 西安80坐标系,高斯-克吕格投影

province2 <- left_join(province, nspecimens, by=c("ID" = "province_cn"))

tm_shape(country) +
tm_lines() +
tm_shape(province2) +
tm_fill("n_specimens",
breaks = c(500, 1000, 5000, 10000, 50000, 100000, 150000),
title ="Number of specimens") +
tm_borders(col = "gray40", lwd = 1) +
tm_scale_bar(position=c("left", "bottom")) +
tm_compass(type = "4star", position=c("left", "top")) +
tm_layout(inner.margins=c(0.12,0.03,0.08,0.03))

img

1
2
3
4
5
6
7
8
9
10
11
12
tm_shape(country) + 
tm_lines(col="dodgerblue3") +
tm_shape(province2) +
tm_bubbles("n_specimens",
border.col = "black", border.alpha = .5,
style="fixed",contrast=1,
title.size="Number of specimens",
col = "red") +
tm_borders("grey40", lwd = 1) +
tm_scale_bar(position=c("left", "bottom")) +
tm_compass(type = "4star", position=c("left", "top")) +
tm_layout(inner.margins=c(0.12,0.03,0.08,0.03))

img

Shiny程序包学习要点

全文PDF Shiny.pdf

\1. 什么是Shiny?

\2. Shiny App的基本结构

2.1 运行Shiny App

2.2 app.R文件

​ 2.2.1 ui用户界面

​ 2.2.2 server函数

​ 2.2.3 shinyApp

2.3 运行shiny程序包中的例子

\3. 信息的输入与输出

\4. 响应式编程与html标签

\5. 编写高效的ShinyApp

1. 什么是Shiny?

Shiny 是Rstudio公司开发的R程序包。最早于2012年12月出现在CRAN上。

长期以来,R编写图形界面都不是很方便,Shiny在这方面进行了很大努力。Shiny在R中定义了网页中多种对象,因而可用其制作与R互动的网页。在Shiny生成的网页中,用户可提交数据,调整参数,控制生成的图形,如地图、箱线图等,也可以控制要显示的结果,如表格,模型拟合结果等。

想要在本地运行和调试用Shiny编写的用户界面,就要先安装Shiny及其依赖的程序包。Shiny应用程序可以部署在服务器端, 用户只要访问相应的网址,就可直接对网页中的对象进行操作。安装在服务器上的Shiny Server会收集信息并控制网页如何响应。

例1. 安装 Shiny程序包

1
install.packages("shiny")

2. Shiny App的基本结构

一个文件夹,加上包含Shiny命令的app.R文件,再加上用到的数据文件和R脚本等, 就称为ShinyApp。

Shiny App总是由三部分组成: 1. 文件夹 2. app.R的脚本 3. 其他数据和R脚本等

文件夹的名字就是shinyApp的名称,因此最好不要有英文或数字以外的字符。

2.1 运行Shiny App

shinyApp需要在导入Shiny程序包之后运行。

1
2
3
4
## 在本地运行shiny app
setwd("/Users/jinlong/Desktop/")
library(shiny)
runApp("learn_shiny")

2.2 app.R文件

app.R 文件必须包含三部分: 1. ui 设定图形界面 2. server函数 3. 调用shinyApp的命令 shinyApp(ui, server)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 一个最简单的app.R脚本
library(shiny)# Define UI ----
ui <- fluidPage(

)

# Define server logic ----
server <- function(input, output) {

}

# Run the app ----

shinyApp(ui = ui, server = server)

2.2.1 ui用户界面

其中ui定义网页中对象的展示方式,包括文字的字体,字号,颜色,排列方式,以及各种组件的默认参数,可以选择的参数等。

2.2.2 server函数

server函数读取组件中收集到的数据,计算后,再传递给UI。

2.2.3 shinyApp

shinyApp(ui, server) 分别调用ui和server函数,生成网页。

shiny程序包中内置了十几个例子, 通过以下方式运行:

2.3 运行shiny程序包中的例子

1
2
library(shiny)
runExample("01_hello")

用户还可以查看其它Shiny模版, 参见https://rstudio.github.io/shinythemes/

3. 信息的输入与输出

例1

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
# Define UI for app that draws a histogram ----
# ui为user interface的缩写,ui是基本组件之一。此处定义ui,用于生成频度直方图
ui <- fluidPage(
# App title ----
# 添加标题
titlePanel("Hello Shiny!"),
# Sidebar layout with input and output definitions ----
# 添加侧面的导航栏, 同时定义输入input和输出的显示模式
sidebarLayout(
# Sidebar panel for inputs ----
# 输入数据用的导航栏
sidebarPanel(
# Input: Slider for the number of bins ----
# Input: 定义直方图的数量
sliderInput(inputId = "bins",
label = "Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Main panel for displaying outputs ----
# 网页的主要板块用于输出结果
mainPanel(
# Output: Histogram ----
# 输出结果:频度直方图
plotOutput(outputId = "distPlot")
)
)
)
# 定义server函数,绘制频度直方图
server <- function(input, output) {
# server函数同时包括input和output两个参数
# 输出结果要保存在output参数中

# output中,用来保存绘图结果
# 返回给putput中的对象,是经过 renderPlot转换过的R脚本
# renderPlot本身是一个函数, 内部却直接放花括号
# 花括号内的R脚本, 与普通R脚本无异
output$distPlot <- renderPlot({

x <- faithful$waiting
bins <- seq(min(x), max(x), length.out = input$bins + 1)

hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times")

})

}
# 脚本必须以shinyApp(ui, server)结束。shinyApp(ui, server)

要点

  • shiny application 包括 UI 和 Server以及shinyApp(ui, server)三部分。
  • UI负责收集数据和展示数据。fluidPage中的参数,titlePanel, sidebarLayout, mainPanel用“,”分隔。
  • 收集数据的一般在 SidePanel 中进行
  • 展示数据在MainPanel中进行
  • 所有网页内容要放在fluidPage当中
  • UI中对象的命名习惯是,首字母小写,第二个单词的首字母大写,中间无任何间隔符号 (例如下划线_),这与javaScript的命名习惯相同
  • titlePanel用来给整个程序命名
  • sidebarLayout主要用来控制Sidebar独立为一列
  • 任何要输入的内容一般都放在sidebarPanel
  • 要输出的内容放在mainPanel
  • 输出的内容需要放在plotOutput中,以生成动态图形
  • 输入的内容需要用 outputId 指定
  • server 必须为一个函数,参数为input和output
  • 所有server函数要输出的内容,都必须作为output的组件,创建output组件用$指明即可
  • 所有从ui界面的数据获取,计算,绘图等都需要在renderPlot中处理
  • renderPlot的调用方法, 看似一个函数, 但是在小括号内放花括号,可放置多行R代码。
  • 从UI提取的数据,是input的参数的组件,用input$xxx提取
  • shinyApp结尾, 必须用shinyApp()`` 指明ui和server。格式为shinyApp(ui = ui, server = server)`

例2

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(shiny)
# Define UI for dataset viewer app ----
# 定义图形界面,用于查看数据
ui <- fluidPage( # App title ----
# 添加标题
titlePanel("Shiny Text"),
# Sidebar layout with a input and output definitions ----
# 添加导航栏,并定义input和output
sidebarLayout(
# Sidebar panel for inputs ----
# 用于输入数据的导航栏
sidebarPanel(
# Input: Selector for choosing dataset ----
# Input: 输入数据选择器
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
# Input: Numeric entry for number of obs to view ----
# Input:输入要查看的记录条数
numericInput(inputId = "obs",
label = "Number of observations to view:",
value = 10)
), # Main panel for displaying outputs ----
# 主显示版
mainPanel(
# Output: Verbatim text for data summary ----
# Output: 直接显示数据概要
verbatimTextOutput("summary"),
# Output: HTML table with requested number of observations ----
# Output: 显示指定行数的表格
tableOutput("view")

)
)
)

# Define server logic to summarize and view selected dataset ----
# 定义server函数,用于汇总和查看所选择数据
server <- function(input, output) {
# Return the requested dataset ----
# 返回所请求的数据
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})
# Generate a summary of the dataset ----
# 创建数据汇总summary
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})
# Show the first "n" observations ----
# 显示前n个观测值
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})

}

# Create Shiny app ----
# 创建ShinyAppshinyApp(ui = ui, server = server)

要点

  • 每一个形为*Input的组件,如 selectInputnumericInput 都是R函数,可以在帮助文件查询到各参数的要求。
  • 在ui中,输入数据可以用selectInput组件建立,此时用inputId参数识别输入的数据。
  • 输入数据可以用numericInput组件建立,此时用inputId识别输入的数据
  • selectInputnumericInput组件在输入数据时, 都有inputId, label以及value三个选项
  • 直接输出要打印的数据,可以用verbarimTextOutput("")
  • 其中“”中放要显示的对象名称,这个对象是由server中的output参数返回的,如“summary”
  • 要输出表格, 用tableOutput("view")
  • server函数中,通过reactive提取input$dataset中的数据
  • reactive面对的是selectInput组件,则需要用switch对UI中相应的操作做出响应
  • reactive的结果保存为一个对象, 也是在括号内放花括号, 以保证读取多行
  • 要输出的结果, 都必须保存到output对象中, 保存结果的操作符为 操作符为$
  • 要输出的结果分别用renderPrint, 或者renderTable转换为Print或者Table相应的类型。即使是一行,也需要用花括号将要打印的值或者表格包
  • datasetInputreactive返回的对象,但是也是一个函数,用来获取UI界面获取的值, 所以调用时, 都用datasetInput(), 与调用函数时一样
  • server文件中, 输入的数值, 可以直接用input$obs 的方式提取。
  • 所有要输出的内容, 都是作为output的一部分, 用$指定并赋值。这是响应式编程的基本要求。

4. 响应式编程与html标签

例3

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
# Define UI for dataset viewer app ----
# 定义ui, 该app用于查看数据
ui <- fluidPage(
# App title ----
# App标题
titlePanel("Reactivity"),
# Sidebar layout with input and output definitions ----
# 导航栏
sidebarLayout(
# Sidebar panel for inputs ----
# 输入数据的导航栏
sidebarPanel(
# Input: Text for providing a caption ----
# Note: Changes made to the caption in the textInput control
# are updated in the output area immediately as you type

# Input: 选择的标题会马上显示在右侧的结果显示区域中

textInput(inputId = "caption",
label = "Caption:",
value = "Data Summary"),
# Input: Selector for choosing dataset ----
# Input: 输入数据选择器
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
# Input: Numeric entry for number of obs to view ----
# Input:设定要查看的记录条数
numericInput(inputId = "obs",
label = "Number of observations to view:",
value = 10)

), # Main panel for displaying outputs ----
# 显示输出结果的主要面板

mainPanel(
# Output: Formatted text for caption ----
# Output: 修改标题格式
h3(textOutput("caption", container = span)),
# Output: Verbatim text for data summary ----
# Output: 打印data summary
verbatimTextOutput("summary"),
# Output: HTML table with requested number of observations ----
# Output: 生成HTML表格,以显示指定数量的观测值
tableOutput("view")

)
)
)

要点

  • shiny中,可以直接使用html5标签
  • h3 为 第三级标题的html标签
  • tableOutput 直接生成表格

例4

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
library(shiny)

# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("More Widgets"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
# 导航栏
sidebarPanel(
# Input: Select a dataset ----
# Input: 选择数据
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),

# Input: Specify the number of observations to view ----
# Input: 查看多少条记录
numericInput("obs", "Number of observations to view:", 10),
# Include clarifying text ----
# 帮助
helpText("Note: while the data view will show only the specified",
"number of observations, the summary will still be based",
"on the full dataset."),

# Input: actionButton() to defer the rendering of output ----
# until the user explicitly clicks the button (rather than
# doing it immediately when inputs change). This is useful if
# the computations required to render output are inordinately
# time-consuming.
# 当获得结果所需时间较长, 是否运行脚本需要由用户决定, 此时用本按钮。

actionButton("update", "Update View")

),

# Main panel for displaying outputs ----
# 主面板
mainPanel(
# Output: Header + summary of distribution ----
# 输出
h4("Summary"),
verbatimTextOutput("summary"),
# Output: Header + table of distribution ----
# 输出
h4("Observations"),
tableOutput("view")
)

)
)# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {
# Return the requested dataset ----
# Note that we use eventReactive() here, which depends on
# input$update (the action button), so that the output is only
# updated when the user clicks the button
datasetInput <- eventReactive(input$update, {
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
}, ignoreNULL = FALSE)

# Generate a summary of the dataset ----
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})

# Show the first "n" observations ----
# The use of isolate() is necessary because we don't want the table
# to update whenever input$obs changes (only when the user clicks
# the action button)

output$view <- renderTable({
head(datasetInput(), n = isolate(input$obs))
})

}# Create Shiny app ----shinyApp(ui, server)

要点

  • helpText 用来显示SideBarPanel中的帮助文本
  • actionButton("update", "Update View") 是按钮, 前一个参数是动作, 后一个参数是按钮上的标签。
  • 使用eventReactive 捕获UI按钮中的动作。
  • 使用Widgets时, 需要指定名称以及标签, 名称用于访问,标签用于显示。名称一般全部小写。标签一般首字母大写。Widgets标签也是可以直接用html5的tag的。 无论是 chekboxGroupInput 还是 radioButtons, selectInput, 都涉及到choices参数, 输入的都是list()
  • helpText()用以显示灰色帮助文字

server 函数有两个参数,inputoutput, output表示运算的结果, input表示从Widget收集到的数据。

输入数据,在UI中, 使用*Output系列函数。

Shiny中可以直接使用html5的标签, 包括:

Shiny函数 html标签 说明
p <p> A paragraph of text
h1 <h1> A first level header
h2 <h2> A second level header
h3 <h3> A third level header
h4 <h4> A fourth level header
h5 <h5> A fifth level header
h6 <h6> A sixth level header
a <a> A hyper link
br <br> A line break (e.g. a blank line)
div <div> A division of text with a uniform style
span <span> An in-line division of text with a uniform style
pre <pre> Text ‘as is’ in a fixed width font
code <code> A formatted block of code
img <img> An image
strong <strong> Bold text
em <em> Italicized text

UI中可放入如下Widgets

按钮 功能
checkboxGroupInput A group of check boxes
checkboxInput A single check box
dateInput A calendar to aid date selection
dateRangeInput A pair of calendars for selecting a date range
fileInput A file upload control wizard
helpText Help text that can be added to an input form
numericInput A field to enter numbers
radioButtons A set of radio buttons
selectInput A box with choices to select from
sliderInput A slider bar
submitButton A submit button
textInput A field to enter text

Shiny输出的对象类型, 函数名称及其返回的对象

Shiny输入的对象 Shiny返回的对象
dataTableOutput DataTable
htmlOutput raw HTML
imageOutput image
plotOutput plot
tableOutput table
textOutput text
uiOutput raw HTML
verbatimTextOutput text
  • \*Output可以放在 sidebarPanelmainPanel 中。在server中,任何一个widget都需要有自己的名字,这个名字用来从server函数内的input对象访问widget。 Output系列函数,用来直接读取server 函数中, output对方中保存的内容。
  • server 函数返回的是output对象。
  • widget 显示出的结果, 都作为output的子对象保存。 可以返回的类型
  • server函数中,要显示的内容,都是通过render* 函数输出的。包括以下类型s
render 函数 生成的对象
renderDataTable DataTable
renderImage images (saved as a link to a source file)
renderPlot plots
renderPrint any printed output
renderTable data frame, matrix, other table like structures
renderText character strings
renderUI a Shiny tag object or HTML

每一个render*函数,输入的参数都是用花括号包裹的。可以包含一行至多行代码。 数据文件放入data子文件夹。

5. 编写高效的ShinyApp

一般来说,运行ShinyApp是,ShinyApp本身只运行一次; Server函数,每一个用户访问时,都会运行一次; render* 函数里面的内容,用户一旦改变内容, 就会重新运行一次。

因此,为了Shiny程序能够高效运行, 一般有以下建议:

在server函数一开头,就要加载所有函数,程序包以及读取数据;

server函数中, 尽量在render* 函数意外建立新对象;

render* 函数中, 只放不可或缺的对象。

需要从网络下载的数据,一般放入 reactive({})环境中。

当数据发生变化时,R会自动更新。

reactive({}) 返回的也是函数, 其返回值要用render\* 显示时,后面要跟括号()。

注意: 只能在render\*系列中调用reactive expressions。

参考网址

《R语言编程概述》讲座前言

R语言是一种统计绘图用的计算机脚本语言。近年来在生态学与环境、进化、遗传学、经济学等领域都得到广泛应用。截至2018年6月,R程序包集成网络CRAN上已经有12000多个程序包,并且仍在增加中。此外,在Bioconductor, R-Forge, Github等多个网站上还有为数众多的R程序包。了解和学习R编程无疑能帮助科研人员用好这些宝贵的资源。

最近,生态学与进化研究领域的论文公开研究数据及计算机程序成为一大趋势。 R语言是其中不可或缺的重要分析工具,其中,由Rstudio公司谢益辉等编写的knitr, rmarkdown, bookdown, blogdown等R程序包更是可重复研究的中坚力量。在knitr和rmarkdown程序包帮助下,markdown文档中可直接运行R脚本,编译后的文档可保存运行结果以及绘制的图形,并转换为网页文件、 PDF文件等多种格式。不仅如此, 众多的程序包也在使用Rmarkdown撰写使用说明。因此,掌握Rmarkdown文档,无疑在R程序包编写以及R文档共享中发挥重要作用。本课程的全部内容就都是用Rmarkdown编写,用Rstudio编译为pdf的。

工欲善其事,必先利其器。编写R程序包所需要的工具软件一般包括 Rtools、MikTeX和Rstudio等。由于R软件有时候会用C, C++或者Fortran等语言的源代码,在使用时需要将这些语言的源代码编译成为动态链接库, 因此需要Rtools中提供的gcc等编译器。MikTeX保证能将R帮助文档和Sweave文档转换为pdf。 Rstudio则提供了一系列工具,结合devtools和roxygen2等程序包,为编写、检查、安装R程序包提供了极大方便。

任何程序都以结果准确为第一重要,同时要方便调用,能高效运行等。 要做到这些,需要编写程序的人有扎实的编程功底。

首先, 对数据类型、结构以及基本操作的理解与熟练掌握无疑是十分重要的。向量、矩阵、数据框、列表以及下标、索引、 流程控制、向量化编程,字符串操作等等,都是编写R函数的基础, 需要扎实掌握。

其次, R程序包看似结构简单,但是对于非计算机专业的科学家来说,各种知识点仍然比较多。如程序包需要有好的结构, NAMESPACE, DESCRIPTION文件, R, man, data, vignettes, test, src等文件夹中的对象和撰写要求,非常琐碎和细致。

再次,R面向对象编程。虽然R面向对象编程的功能比较弱, 但是S3 和S4这两种方式也是广泛应用的, 都能够降低R程序包的使用难度。S3和S4在泛型函数、子函数、类型创建等几乎都是编写R程序包所必需的。Bioconductor网站更是要求所有的R程序包都遵循S4编程。

最后,R的编程风格是保证程序可读性的重要保证。R中对象中的名称要精心设计,做到“观其名,知其意”,并撰写详尽的帮助文件和使用指南等。

近几年新工具也在不断涌现,常给人一种无所适从的感觉。因此本课程较为系统地介绍这些零散的知识点,以便熟悉编程过程中的各种概念和流程,主要包括:

第一,R程序包的结构,编译和检查。过去编写R程序包,一般是用package.skeletons()函数生成R程序包的骨架,然后对其中的各文件修改后,再进行编译和检查。这样生成的程序包虽然结构比较简单,但其文档是用类似Latex代码写成的Rd文件, 但难以维护。最近五年来的新工具在一定程度是降低了R程序包的开发和维护的门槛。如devtools程序包整合了Rcmd工具中检查、安装等命令,用户不必再通过Windows的Command Prompt运行Rcmd命令即可编译。而Roxygen2程序包能将R脚本中的oxygen标签转换为Rd文件,省去了寻找和编辑Rd文件的麻烦。

第二, 程序是否能准确运行,需要进行准确测试,以确定在不同的情形下各函数以及程序包的行为是否符合预期。Hadley Wickham编写的testthat程序包能够很好地解决这个问题。

第三, R程序包的版本控制和共享。任何程序都可能会出错,发现错误后不得不对源代码进行修改。 此时就会用到版本控制软件,如git和svn软件等。R程序包编写好后又离不开分享,主要分享渠道是github, rforge, CRAN, Bioconductor等网站。每个网站都有对程序包几乎都有不同的要求,这是编程人员需要特别留意的。

《R语言编程概述》是为2018年6月23日在广州热带林业研究所举办的《基于R语言的生态与环境科学数据分析培训班》准备的,内容包括上述各方面,幻灯片和练习的代码保存在 https://github.com/helixcn/programing_in_r_cn 。不过当时只有三小时的时间讲解, 将这么多内容高度浓缩是很困难的。限于篇幅和讲解时间,不能对每一部分都深入展开,一些高级内容, 如用Rcpp程序包整合C++程序编程,也无法收录,只能在将来有机会再介绍了。

由于本人学识和水平有限,幻灯片中难免有不少错误和不足, 敬请各位读者批评指正。

张金龙

2018年6月25日

于香港大埔

当原创幻灯片也遇到剽窃

本人在2010年制作并发布在科学网博客的幻灯片 《R语言初步:统计、绘图与编程》 (http://blog.sciencenet.cn/blog-255662-399095.html ) 遭遇剽窃:

中国地质大学(武汉)图书馆高思宇发布的 《R语言入门教程》(2015年公布,网址是 www.lib.cug.edu.cn/ueditor/upload/2015111087546.ppt)与我的幻灯片相似度超过95%, 该幻灯片的内容、文字、示例均基本上没有做修改,但署名为高思宇。

上述行为已经严重侵犯了本人的著作权。因此,本人要求:

\1. 高思宇以书面方式向本人正式道歉,并保证类似事件不再发生;

\2. 中国地质大学图书馆网站将该幻灯片删除。

本人保留进一步追究的权利。为了比较,我下载了两个幻灯片,大家可通过 https://pan.baidu.com/s/1K3jlsNxt60JjQsYaQ_83Tw 下载查看。

本人欢迎各位老师在教学、培训中使用该幻灯片,但是幻灯片为本人原创, 使用中应保留本人姓名。在没有做较大改动的情况下,私自将著作人改为自己是不合适的。

张金龙

2018年6月14日

于香港大埔

R绘制中国地图:你去过哪些省份?

最近,微信中去过哪些省份的小程序十分火爆,用户通过选择去过哪些省份和地级市, 提交之后后台就自动生成地图。其实该地图要绘制起来并不困难。 这里给出绘制去过哪些省份的R代码。供参考

代码和R脚本 map of china.zip

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
setwd("C:\\Users\\jlzhang\\20180604")
#### 导入所需要的程序包library(maptools)
## Loading required package: sp
## Checking rgeos availability: TRUE
library(ggplot2)
library(rgdal)
## rgdal: version: 1.3-1, (SVN revision 747)
## Geospatial Data Abstraction Library extensions to R successfully loaded
## Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
## Path to GDAL shared files: C:/Users/jlzhang/Documents/R/win-library/3.5/rgdal/gdal
## GDAL binary built with GEOS: TRUE
## Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
## Path to PROJ.4 shared files: C:/Users/jlzhang/Documents/R/win-library/3.5/rgdal/proj
## Linking to sp version: 1.2-7
rm(list = ls()) ## 删除所有对象

## 去过的地方
provinces_visited <- c("Beijing", "Hebei", "Heilongjiang",
"Liaoning", "Jilin", "Jiangxi", "Hunan",
"Zhejiang", "Hubei", "Chongqing", "Sichuan",
"Henan", "Guangxi", "Guangdong", "Fujian",
"Hainan", "Yunnan", "Guizhou")
provinces_visited_df <- data.frame(province_pinyin = provinces_visited,
visited_status = rep("Visited", length(provinces_visited)))

## 读取地图
country <- readOGR("bou1_4l.shp")
## OGR data source with driver: ESRI Shapefile
## Source: "C:\Users\jlzhang\20180604\bou1_4l.shp", layer: "bou1_4l"
## with 1382 features
## It has 8 fields
## Integer64 fields read as strings: FNODE_ TNODE_ LPOLY_ RPOLY_ BOU1_4M_ BOU1_4M_ID
province <- readOGR("province_polygon.shp") ## 各省多边形
## OGR data source with driver: ESRI Shapefile
## Source: "C:\Users\jlzhang\20180604\province_polygon.shp", layer: "province_polygon"
## with 34 features
## It has 10 fields
province$ID <- as.character(province$ID)

## 转换为ggplot2绘图用的data.frame
country_df <- fortify(country)
province_df <- fortify(province)
## Regions defined for each Polygons
## 提取省级数据中的信息
province_dat <- province@data

## 改正省级数据中关于香港和澳门的错误
index_HK <- which(province_dat$ID == "Xianggang")
province_dat$X[index_HK] <- 114.156121
province_dat$Y[index_HK] <- 22.37725
province_dat$ID[index_HK] <- "Hong Kong"

index_MC <- which(province_dat$ID == "Aomen")
province_dat$X[index_MC] <- 113.545681
province_dat$Y[index_MC] <- 20.197303
province_dat$ID[index_MC] <- "Macau"

## id与province_df数据表中的省出现的顺序相同, 这里id都从0开始, 所以需要减去1,以便匹配
province_dat$id <- as.character(1:nrow(province_dat) - 1)

## 增加省拼音
province_dat2 <- merge(province_dat, provinces_visited_df, by.x = "ID",
by.y = "province_pinyin", all.x = TRUE)


## 由于visited status 默认是 factor 类型, 这里需要先转换为字符串, 再处理
province_dat2$visited_status <- as.character(province_dat2$visited_status)

## 所有没有匹配上的省份都是没有去过的, 状态为 not yet
province_dat2$visited_status[is.na(province_dat2$visited_status)] <- "Not Yet"
province_df_merged <- merge(province_df, province_dat2, by = "id")

## 绘图
## 用geom_path绘制读取的polyline,因为国界线是polyline
## 多圆锥投影
## http://desktop.arcgis.com/zh-cn/arcmap/10.3/guide-books/map-projections/polyconic.htm

ggplot() + geom_path(data = country_df,
aes(x = long, y = lat, group=group), colour="darkblue") +
coord_map("polyconic") +
geom_polygon(data = province_df_merged,
aes(x = long, y = lat, group=group,
fill = visited_status), colour="grey") +
geom_text(mapping = aes(x = X, y = Y, label = ID),
data = province_dat, colour = 'Black')+
ggtitle("Provinces I have been to:") +
xlab("Longitude") +
ylab("Latitude") +
theme(legend.position = "bottom") +
scale_fill_discrete(name = "Province")

img

1
2
3
4
参考
## https://zhuanlan.zhihu.com/p/25231546
## http://eriqande.github.io/rep-res-web/lectures/making-maps-with-R.html
## http://www.statsoft.org/wp-content/uploads/2016/09/Lecture6_HKMapVis.html