R语言:ggplot2精细化绘图——以实用商业化图表绘图为例(转)

本文旨在介绍R语言中ggplot2包的一些精细化操作,主要适用于对R画图有一定了解,需要更精细化作图的人,尤其是那些刚从excel转ggplot2的各位,有比较频繁的作图需求的人。不讨论那些样式非常酷炫的图表,以实用的商业化图表为主。包括以下结构:

1、画图前的准备:自定义ggplot2格式刷 
2、画图前的准备:数据塑形利器dplyr / tidyr介绍 
3、常用的商业用图:

    1)简单柱形图+文本(单一变量) 
    2)分面柱形图(facet_wrap/facet_grid) 
    3)簇型柱形图(position=”dodge”) 
    4)堆积柱形图(需要先添加百分比,再对百分比的变量做柱形图) 
    5)饼图、极坐标图 
    6)多重线性图

前言

这篇文章其实是我之前那篇博文的一个延续。因为接了一个活要用R定制化数据报表,其中涉及大量的对图表精雕细琢的工作。在深入研究ggplot2时,深深感觉到用ggplot2画图与用excel画图的不一样。

如果要用ggplot2画图,还是需要了解很多技术细节的。这些细节要么散落在R可视化技术和ggplot2:数据分析与图表技术这两本书里,要么散落在网上。因此在这里以我学习和总结的过程,对ggplot2的精细化画图做一个阐述,介绍我整理后的作图理念。

如果有进一步学习需要的各位,请直接买书或者自己实践学习。很多技术细节需要自己摸索才知道的,祝大家好运。

 

1、画图前的准备:自定义ggplot2格式刷

在画图前,我们首先定义一下ggplot2格式刷。

首先,ggplot2本身自带了很漂亮的主题格式,如theme_gray和theme_bw。但是在工作用图上,很多公司对图表格式配色字体等均有明文的规定。像我们公司,对主色、辅色、字体等都有严格的规定。如刘万祥老师早期的一篇配色博文里,大家更是可以看到,很多商业杂志的图表,配色风格都是非常相近的。因此,修改主题,使其更加适合我们的商业需求,保持图表风格统一,是非常必要的。

虽然ggplot2可以通过代码的追加,细细修改表距、背景色以及字体等框架。但是如果每做一个图,都要如此细调,代码将会非常繁琐,而且万一老板突然兴起要换风格时,代码修改将会非常痛苦。

幸运的是,ggplot2允许我们事先定制好图表样式,我们可以生成如mytheme或者myline这样的有明确配色主题的对象,到时候就像excel的定制保存图表模板或者格式刷,直接在生成的图表里引用格式刷型的主题配色,就可以快捷方便的更改图表内容,保持风格的统一了。

在运行之前,首先加载相关包

library(ggplot2)
library(dplyr)
library(ColorBrewer)
library(tidyr)
library(grid)
#载入格式刷
######

#定义好字体
windowsFonts(CA=windowsFont("Calibri"))

接下来是一个示范。我首先共享了我常用的一个主题刷,配色参考以下:

主体色:蓝色 085A9C ,红色 EF0808,灰色 526373 
辅助色:浅黄色 FFFFE7,橙色 FF9418, 绿色 219431, 明黄色 FF9418,紫色 9C52AD

定制了mytheme, myline_blue, mycolour等多个对象:

#定义好字体
windowsFonts(CA=windowsFont("Calibri"))
#事先定制好要加图形的形状、颜色、主题等
#定制主题,要求背景全白,没有边框。然后所有的字体都是某某颜色
#定制主题,要求背景全白,没有边框。然后所有的字体都是某某颜色
mytheme<-theme_bw()+theme(legend.position="top",
                         panel.border=element_blank(),
                         panel.grid.major=element_line(linetype="dashed"),
                         panel.grid.minor=element_blank(),
                         plot.title=element_text(size=15,
                                                 colour="#003087",
                                                 family="CA"),
                         legend.text=element_text(size=9,colour="#003087",
                                                  family="CA"),
                         legend.key=element_blank(),
                         axis.text=element_text(size=10,colour="#003087",
                                                family="CA"),
                         strip.text=element_text(size=12,colour="#EF0808",
                                                 family="CA"),
                         strip.background=element_blank()

                       )
pie_theme=mytheme+theme(axis.text=element_blank(),
                       axis.ticks=element_blank(),
                       axis.title=element_blank(),
                       panel.grid.major=element_blank())
#定制线的大小
myline_blue<-geom_line(colour="#085A9C",size=2)
myline_red<-geom_line(colour="#EF0808",size=2)
myarea=geom_area(colour=NA,fill="#003087",alpha=.2)
mypoint=geom_point(size=3,shape=21,colour="#003087",fill="white")
mybar=geom_bar(fill="#0C8DC4",stat="identity")
#然后是配色,考虑到样本的多样性,可以事先设定颜色,如3种颜色或7种颜色的组合
mycolour_3<-scale_fill_manual(values=c("#085A9C","#EF0808","#526373"))
mycolour_7<-scale_fill_manual(values=c("#085A9C","#EF0808","#526373",
"#FFFFE7","#FF9418","#219431","#9C52AD"))
mycolour_line_7<-scale_color_manual(values=c("#085A9C","#EF0808","#526373",
                                            "#0C8DC4","#FF9418","#219431","#9C52AD")) 

把以上代码在R里面运行以后,就可以直接使用了。譬如以下:

1)先生成一个简单的图表:

#未使用格式刷
p<-ggplot(iris,aes(x=species,y=sepal_length)) +geom_bar(stat="identity")+ ggtitle("sepal_length by species")
p

简单地指定x轴为离散型变量species,y为求和,会得到下面的柱形图 

这时候,套用一下之前设置好的主题(mytheme),背景、坐标轴还有字体颜色就相应改变了。

p+mytheme

然后,因为之前格式刷部分我设定了一个蓝色的柱形图样式(mybar),这里直接引用的话,就可以直接生成蓝色的柱形图了。

ggplot(iris,aes(x=species,y=sepal_length)) +ggtitle("sepal_length by species")+mybar+mytheme

2、画图前的准备:数据塑形利器dplyr / tidyr

有了事先设定的一些格式刷以后,我们就可以快速有效地作图了。

但是在作图之前,就像excel作图总要先把数据用处理成想要的形式 。在excel里面,我们常用的是数据透视表或者一些公式辅助,而在R里,则是用一些常用的包,如dplyr及tidyr,对数据进行重塑再造

在我之前看的那两本ggplot2的书里,基本用的都是reshape2+plyr的组合。但实际上hadley后续出的dplyr与tidyr更加有用。具体的使用方法,在JHU Getting and cleaning data有介绍,老师还编了一个swirl课程供人使用,安装方法如下。

install.packages("swirl")
library(swirl)
#安装getting and cleaning data相关的课程教学包
install_from_swirl("Getting and Cleaning Data")
swirl()

其他的也可以参考我这篇博文

总之,用好dplyr的话,你可以快速的把一些数据,如下面的股票逐笔成交记录 
 
随你所欲地汇总(group_by & summarize) 甚至再拆分 (spread),譬如示例里面就是把成交记录按照成交价格和BuySell拆分

data #刚刚演示的那些数据,在预测者网可以下载
data %>% group_by(Price,BuySell) %>% summarize(Money=sum(Money,na.rm=TRUE)) %>% spread(BuySell,Money)

要想做好ggplot2的图,对数据快速进行塑形的方法是我们必须要掌握的。上面的s wirl课程非常有用,而且值得是最新的一个技术方法,值得大家学习。

3、常用的商业用图

接下来分享一下我在这次作图过程中,最常用的几个图形的代码。首先声明,这些图形的进一步做法以及变形,基本都可以在这两本参考书籍里(R可视化技术 | ggplot2:数据分析与图表技术 )找到。我这里更多的摘取一些我比较常用的图表进行讲解

1、简单柱形图+文本(单一变量) 
2、分面柱形图(facet_wrap/facet_grid) 
3、簇型柱形图(position=”dodge”) 
4、堆积柱形图(需要先添加百分比,再对百分比的变量做柱形图) 
5、饼图、极坐标图 
6、多重线性图

在作图之前,首先讲一下ggplot2的局限。

ggplot2最大的局限是,它基本不支持双坐标图和饼图。即使能做这些图形,也要很多设置,做起来非常繁琐。 
按我个人理解,这个局限的根源与ggplot2开发者Hadley本身的审美习惯以及分析习惯脱不了关系。具体请看他在stackoverflow的这一段问答:

It’s not possible in ggplot2 because I believe plots with separate y scales (not y-scales that are transformations of each other) are fundamentally flawed.

大神有技术就能任性。即使一堆人在他那回复下面各种求双坐标。。不知道Hadley现在有没有改变主意,把双坐标列为ggplot2的下一个更新点。但是如果你想画双坐标图或者饼图,至少经个人的实践,这些都是比较困难的,设置繁琐而且不美观。要么选择用excel完成,要么听大神的话,用分面图(facet)或者柱形图代替,会更加省事一些。

所以,在了解以下常用图形前,我们需要记住,ggplot2不是万能的,它虽然能做出非常美观的图表,但是总有一些图不能做,因此多个工具结合使用是非常必要的。

在知道以上前提下,我们以ggplot2自带的diamonds数据集为基础,结合dplyr/tidyr的应用,介绍一下常用图形的画法。

然后来讲一下除了双坐标图和饼图以外,ggplot2可以支持的常用图形的画法。数据的话,我们使用ggplot2自带的数据包diamonds

首先定义一下

mytitle="演示:以diamond为例"

1)简单柱形图 

 
代码组成如下,这里使用格式刷mybar和mytheme,然后用geom_text添加柱形图标签(vjust=1表示在柱形图里面显示)

data1<-diamonds %>% group_by(cut) %>% summarize(avg_price=mean(price))
柱形图<-ggplot(data1,aes(x=cut,y=avg_price,fill=as.factor(cut)))+
       mytitle+mybar+mytheme+
       geom_text(aes(label=round(avg_price)),vjust=1,colour="white")

2)带分类的柱形图

举个例子来说,在有时候,我们想要快速绘图。使用facet_wrap或者facet_grid可以快速绘制相应图形。这也是ggplot2不太支持双坐标的原因:可以快速绘图,就不需要做那么多无用功了。 
 
代码如下:

#dplyr处理数据
data2<-diamonds %>% group_by(cut,color) %>% summarize(avg_price=mean(price))
#画图,套用设定好的绘图元素
ggplot(data2,aes(x=color,y=avg_price))+facet_wrap(~cut,ncol = 2)+
       mytitle+mybar+mytheme
#在facet_wrap里面,如果加上scales="free"的话,坐标就不一样了。

 3)簇型图 

制图要点是,对数据作图后,添加geom_bar时,position=”dodge”(分开的)如果去掉这部分,默认是生成堆积图.

代码如下:

data3<-diamonds %>% filter(cut %in% c("Fair","Very Good","Ideal")) %>%
       group_by(cut,color) %>% summarize(avg_price=mean(price))
#簇状图
簇状柱形图<-ggplot(data3,aes(x=color,y=avg_price,fill=cut))+
       geom_bar(stat="identity",position="dodge")+
       mytheme+mytitle+mycolour_3
簇状柱形图

这里如果想要定义颜色的相应顺序的话,可以使用factor 

譬如以下,只是用这行代码对颜色重新定义一下,用levels改变factor顺序,再画图的时候,颜色以及柱子顺序就会跟着改变了。非常方便。

data3$cut<-factor(data3$cut,levels=c("Very Good","Ideal","Fair"))

4)百分比堆积图 

制图前要事先添加一个百分比的数据之后才好作图,这里我们用mutate(percent=n/sum(n))添加该百分比数据。同时去掉position=”dodge” 

data4<-diamonds %>% filter(cut %in% c("Fair","Very Good","Ideal")) %>%
        count(color,cut) %>%
       mutate(percent=n/sum(n))
堆积图<-ggplot(data4,aes(x=color,y=percent,fill=cut))+mytitle+
       geom_bar(stat="identity")+mytheme+mytitle+mycolour_3
堆积图

当然,也可以做面积图。不过如果数据有缺失,面积图出错几率蛮大的

5)饼图以及极坐标图

参考一下这篇文章《【R】初吻R–ggplot绘制Pie Chart饼图》以及这篇文章使用ggplot2画图 
在ggplot2里并没有直接画饼图的方法,基本上都是先画出柱形图,再用coord_polar转化为饼图

有两种作图方法: 
1)不指定x轴,直接用geom_bar生成y轴,然后fill=分类颜色,coord_polar直接投影y 
该方法的好处代码是比较简单(coord_polar(“y”) 
加标签方法请见: http://stackoverflow.com/questions/8952077/pie-plot-getting-its-text-on-top-of-each-other# 

data5<-diamonds %>% count(cut) %>% 
       mutate(percent=n/sum(n))
ggplot(data5,aes(x=factor(1),y=percent,fill=cut))+geom_bar(stat="identity",width=3)+mycolour_7+
       coord_polar("y")+pie_theme+mytitle

2)指定x轴,x轴同时也是颜色(fill),先画柱形图,再转化为圆形。坏处是公式相对比较繁琐一些。

ggplot(data5,aes(x=cut,y=percent,fill=cut))+
       geom_bar(stat="identity",width=3)+
mycolour_7+coord_polar("x")+pie_theme+mytitle

但是我尝试了多次,在饼图里加标签方法非常难以理解。。如果要饼图加标签的话,或许还不如柱形图

附上分面柱形图画法: 

data5_1<-data5 %>% filter(color %in% c("D","E","F","G"))
ggplot(data5_1,aes(x=factor(1),y=percent,fill=cut))+geom_bar(stat="identity",width=3)+mycolour_7+
       coord_polar("y")+pie_theme+facet_wrap(~color,ncol = 4)+
       theme(legend.position="bottom")+mytitle

6、折线图

除了以上柱形图以外,折线图我们做的也比较多。 
简单的折线图直接做就好了 
然后像下图这样的 

要点是,先做成如A-B-变量这样的二联表,然后,x轴为A,group为b,colour为b 
下面代码展示了这个处理 
如果去掉group的话,折线图会不知道怎么去处理数字。

data6<-diamonds %>% count(color,cut) %>% filter(color %in% c("D","E","F"))%>%
       mutate(percent=n/sum(n))
ggplot(data6,aes(x=cut,y=n,group=color,colour=color))+geom_line(size=1.5)+mypoint+
       mycolour_line_7+mytheme+mytitle

还有一些其他有用的图形 
总之,ggplot2的语法还是比较独特的,而且其实处处有坑,处处有惊喜。如果作为商业绘图的话,需要一点一点地去探索去改变,保证风格和细节完美无缺。 
不过ggplot2绘图有个好处是,一旦整理出常用的绘图代码,以后就可以无限次套用,尤其是那些格式刷,事先设定好的主题等。即ggplot2绘图,是完全可以做到越绘越快,再开发成本低廉的。

 

另外补充说明的是,ggplot2绘图,个人更看好其多种映射,以及在探索性数据分析里快捷绘图的能力,还有跟地图啊等结合的能力。还有动态交互等等。

譬如现在比较流行的R/Python与动态网页(大部分是D3)的结合 示例1,示例2

但愿各位不要将绘图局限于上述所选的一些最常用的图形与格式化调整里。请容我吐槽一句,这样子调风格学习真的很苦(づ ̄ ~~ ̄|||)づ


End

转自:http://mp.weixin.qq.com/s?__biz=MzA3MTM3NTA5Ng==&mid=2651055257&idx=1&sn=786922515def9e46ce991178a082e881&chksm=84d9c50eb3ae4c181313a495965f4578653955ab6566899e0f4ec4b73f4d2bddebfc5e7b6288&scene=0#rd

 

转载于:https://www.cnblogs.com/payton/p/6078094.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/542221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux中常用的命令

1.文件建立 touch file&#xff08;文件的名字&#xff09; 注意&#xff1a; touch不但可以建立文件也可以修改文件的时间戳 时间戳分为&#xff1a; atime&#xff1a;文件内容被访问的时间标识 mtime&#xff1a;文件内容被修改的时间标识 ctime&#xff1a;文件属性或文件内…

蓝桥杯宝藏排序题目算法(冒泡、选择、插入)

冒泡排序: def bubble_sort(li): # 函数方式for i in range(len(li)-1):exchangeFalsefor j in range(len(li)-i-1):if li[j]>li[j1]:li[j],li[j1]li[j1],li[j]exchangeTrueif not exchange:return 选择排序: 从左往右找到最小的元素&#xff0c;放在起始位置…

hive分区用2个字段有何限制_[特性]Hive动态分区功能使用

[特性]Hive动态分区功能使用2016-01-31 21:40说明Hive有两种分区&#xff0c;一种是静态分区&#xff0c;也就是普通的分区。另一种是动态分区。动态分区在数据导入时&#xff0c;会根据具体的字段值自行决定导入&#xff0c;并创建相应的分区。使用上更为方面。举例准备工作创…

Linux系统中输出输入的管理

1.什么是输入和输出 输入和输出是计算机系统中的主机与外部进行通信的系统。它由外围设备和输入输出控制系统两部分组成&#xff0c;我们在shell中键入指令&#xff0c;然后送入CPU中运算产生结果&#xff0c;再将结果送到字符设备中显示。简单点来说输入输出就是通过我们的键盘…

find 命令示例_数组find()方法以及JavaScript中的示例

find 命令示例JavaScript find()方法 (JavaScript find() method) find() method is used to get the first element from an array which passes the given test (condition). find()方法用于从通过给定测试(条件)的数组中获取第一个元素。 Syntax: 句法&#xff1a; array.…

统计Apache或Nginx访问日志里的独立IP访问数量的Shell

1、把IP数量直接输出显示&#xff1a; cat access_log_2011_06_26.log |awk ‘{print $1}’|uniq -c|wc -l 2、把IP数量输出到文本显示&#xff1a; cat access_log_2011_06_26.log |awk ‘{print $1}’|uniq -c|wc -l > ip.txt 总结&#xff1a;如果单个访问日志大小超过2G…

ggplot2箱式图两两比较_R绘图 第四篇:绘制箱图(ggplot2)

箱线图通过绘制观测数据的五数总括&#xff0c;即最小值、下四分位数、中位数、上四分位数以及最大值&#xff0c;描述了变量值的分布情况。箱线图能够显示出离群点(outlier)&#xff0c;离群点也叫做异常值&#xff0c;通过箱线图能够很容易识别出数据中的异常值。箱线图提供了…

Linux系统中用户的管理

#####用户管理###### 1在Linux中&#xff0c;有三种用户&#xff1a; 1 root : 也成为超级用户&#xff0c;对系统有控制权限&#xff0c;超级用户可以不受限制的运行任何命令&#xff0c;root 用户可以看作是系统的管理员。 2 系统用户&#xff1a; 系统用户通常为系统功能所必…

c# 命名空间命名规范_C#命名空间能力问题和解答 套装3

c# 命名空间命名规范1) There are following namespaces are given below, which is correct about "using" statement in C#.NET? In C#.Net, "using" statement is used to import the namespace in our programWe can create a new namespace with the…

shell 查出文件并复制到另一个文件夹

找出所有大于100M的文件并展示出来find / -size 100M -exec ls -lh {} \;找出特定文件内大于200字节的文件并备份到另一个文件夹里去find /opt/test -type f -size 200c -exec cp {} /opt/test/cp/ \;转载于:https://blog.51cto.com/406647516/1875417

correl函数相关系数大小意义_用Correl函数返回相关系数,以确定属性关系

我们辛辛苦苦制作了表格&#xff0c;当然是要作出分析的&#xff0c;肯定不能就是这么几个数据吧。常用的分析法都是图表&#xff0c;虽然看起来直观&#xff0c;但是对于非作者来说&#xff0c;理解意思显然不是那么方便。下面&#xff0c;教大家使用函数&#xff0c;来算出相…

Java之类的构造器(反射)

反射&#xff1a; Java反射机制&#xff1a;指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。Java的反射机制允许在对类未知的情…

java 系统自动检测_如何在Java中检测OS(操作系统)名称?

java 系统自动检测To detect the OS (operating system) name in Java, we use the getProperties() method, which is defined in System class, while calling the method, we need to pass the property name to get the OS (operating system name). 要检测Java中的OS(操作…

shell中返回值是1为真还是假_shell脚本中判断上一个命令是否执行成功

SQL Server 系列文章快速导航(SWF版)一.前言 在博客园写博客不自不觉已经有5个年头了,一开始只是为了记录工作中遇到的问题和解决办法,后来写的文章不自不觉的侧重在SQL Server方面的技术文章,在2014年1月终于鼓起勇气申请了微软S ...duilib帮助1.窗口基类:见介绍 顺便贴下出来…

Linux中对进程的管理

1.what is 进程 程序&#xff08;program&#xff09;放置在储存媒体中&#xff08;如硬盘、光盘、软盘、磁盘等&#xff09;&#xff0c;为实体的型态存在。 进程&#xff1a;程序被触发后&#xff0c;执行者的权限与属性、程序的程序码与所需数据等都会被载入内存中&#xff…

带C#示例的String.Equality(==)运算符

C&#xff03;String.Equality运算符 (C# String.Equality operator ) "" is a String.Equality operator in C#, it is used to check whether two strings objects have the same values or not. “ ”是C&#xff03;中的String.Equality运算符 &#xff0c;用于检…

jQuery 倒计时

function getSec(){//获取名称为remindataSec的ulobj document.getElementsByName("remindataSec");for(i0;i<obj.length;i){//循环得到每个毫秒数var intDiff $("#remindataTime"i"").text();var id "reminTime"i;//得到毫秒数…

Linux远程连接与sshd服务安全设定

1.远程连接&#xff1a; 首先设置ip&#xff1a; 设置好之后&#xff0c;先ping一下IP 看能不能通 ssh root172.25.13.103 ##表示的是&#xff1a;连接ip为172.25.13.103的root用户 2.系统控制命令 系统控制命令的查看相关参数如下表 systemctl服务控制命令systemctl stat…

rabbitmq 同步策略_RabbitMQ高可用方案总结

RabbitMQ的集群方案有以下几种&#xff1a;1.普通的集群exchange&#xff0c;buindling再所有的节点上都会保存一份&#xff0c;但是queue只会存储在其中的一个节点上&#xff0c;但是所有的节点都会存储一份queue的meta信息。因为这样有两个好处&#xff1a;1)存储空间。如果每…

一个简单的封ip规则

2019独角兽企业重金招聘Python工程师标准>>> 一个简单通过nginx日志封ip规则&#xff08;仅仅自己方便使用&#xff09; #!/bin/bash #Version:1.0 #Date:2016-08-09 #作用:防刷IP地址,解封蜘蛛,解封5天前封的IP地址function deny () { Date$(date "%F-%H-%M&q…