R语言--同一图片中绘制两种比例的曲线


 今天有同学问怎样用R绘制右边这样一张图片。一看这不就是双坐标轴么,简单啊,虽然现在用R比较少,直接上手代码有点羞涩,但还是知道在哪能够找到资源的。为此打开R语言实战这本宝典,想要绘制双坐标轴。
书上绘制的样子是如右图这样的,代码如下:

x=c(1:10)

y=x

z=10/x

opar=par(no.readonly=TRUE)

par(mar=c(5,4,4,8),0.1)

plot(x,y,type="b",pch=21,col="red",yaxt="n",lty=3,ann=FALSE)

lines(x,z,type="b",pch=22,col="blue",lty=2)

axis(2,at=x,labels=x,col.axis="red",las=2)

axis(4,at=z,labels=round(z,digits=2),col.axis="blue",las=2,cex.lab=0.7,tck=-0.008)

mtext("y=1/x",side=4,line=3,cex.lab=1,las=0,col="blue")

title("An Example of Creative Axes",xlab="X Values",ylab="Y=X")

par(opar)

此时纵轴的量级是一样的,我的图片是想要左右量级不同时,也能在一张图里展示。

 

 

 为此,将z=1/x,带入,由于z值范围在0-1之间,所以展示出来的样子如下,只能看到一个z值。这不行啊,不是我的目标啊。
 

思来想去,是不是我没限定左右两个坐标轴的范围呢,试试吧:

x=c(1:10);

y=x;

z=1/x;

opar=par(no.readonly=TRUE)

par(mar=c(5,4,4,8),0.1)

plot(x,y,ylim=c(0,10),type="b",pch=21,col="red",yaxt="n",lty=3,ann=FALSE)

lines(x,z,ylim=c(0,1),type="b",pch=22,col="blue",lty=0,ann=FALSE)## ylim=c(0,1)限定z值的范围。

axis(2,at=x,labels=x,col.axis="red",las=0)

axis(4,at=c(z[1],'','','','','','','','',z[10]),labels=round(z,digits=2),col.axis="blue",las=2,cex.lab=0.7,tck=-0.008)

##由于z之太密集,为展示好看,令c(z[1],'','','','','','','','',z[10])只显示两个值。

mtext("y=1/x",side=4,line=3,cex.lab=1,las=0,col="blue")

title("An Example of Creative Axes",xlab="X Values",ylab="Y=X")

par(opar)

展示图片如下

 

但是这个样子还是不是我想要的。搜罗脑海中关于绘制图片的R代码,但是没想到什么好的办法来解决。正当绞尽脑汁的时候,看到一个指导。立马来试一下。

原文介绍是这样:大家在使用R绘图的时候,经常使用属性不同的点或线来展示数据信息,这种数据展示方法贯穿了整个ggplot2系列。使用这种方法时,如果不同指标之间量级相差很大,就会泯灭量级较小指标的的变化,如下图所示,指标2和指标3几乎成了一条直线,这幅图显然不能充分展示数据信息。

dtf = data.frame(RMB=seq(7000,3400,-200),

指标1=c(200,400,450,500,300,100,400,700,830,1200,400,350,200,700,370,800,200,100,120),

指标2=c(2,5,8,3,2,2,4,7,9,4,4,2,2,7,5,12,5,4,4),

指标3=c(1.2,1.3,1.2,0.9,2.1,1.4,2.9,3.4,2.1,1.1,1.2,1.5,1.2,0.9,0.5,3.3,2.2,1.1,1.2))

library(tidyverse);

library(reshape2)

dtf%>%melt(id='RMB')%>%ggplot(aes(RMB,value,group=variable))+geom_line(aes(linetype=variable))+theme_classic();  展示如下

 

今天给大家介绍一种稍微不同的数据展示方法,在同一张图中使用自由度不同的y轴来展示数据的不同属性,这种方法可以很好地解决指标量级不同下数据展示问题。

推荐大家使用R基础绘图系统绘制这种多重坐标图,不建议大家使用ggplot2绘图系统。因为ggplot2的所有工作都是在唯一的坐标系中进行的,如果你分别绘制不同量级的指标,就意味着坐标系统发生变化,必然导致绘图失败。但也不能说ggplot2不画这种图,只是过程会非常艰辛。Hradly大神也不愿看到你那么辛苦地画了一个十分拙略的图,他可能会推荐你使用分面的方式展示数据,但分面不是今天的主题。

绘图策略:首先绘制一张图片,然后在第一张图片上绘其他图片,最后手动添加坐标及图例。过程非常简单明了,但其中一些细节大家要注意。在绘制第一张图时,若绘制双Y轴要在图片的右边留足位置用来添加坐标,若绘制多Y轴坐标要在坐标留出至少10行的距离,右边尽可能少留空间,若图像允许可以把右边留白设为0;第一张图绘制成功后要调用par(new=T)函数,保证第二张图是绘制在第一张图的基础上,第二张图绘制成功后,调用aixs绘制坐标刻度,mtext添加坐标标签。最后使用legend添加图例,建议大家使用bty='n'去掉图例的边框,使用cex=0.85对字体进行放缩。

 

另外如果只想绘制双Y坐标轴,可以使用plotrix包中的twoord.plot和twoord.stackplot,两者稍有区别,前者使用不同Y轴相同的X轴,后者在同一张图上使用不同的坐标系。还有lattice包中的doubleYScale函数,Plotly直接在add_lines函数中声明要绘制双Y轴即可,highcharter中通过hc_add_series直接添加不同尺度的Y轴。

这才是想要的样子么。这样的图是怎么绘制呢?别急,代码来了,

双重坐标轴:

op=par(mar = c(5,5,2,5),cex.axis=0.6,cex.lab=0.75)

with(dtf, plot(RMB, 指标1, type="l", col="gray10", ylab='指标1',ylim=c(0,1300)))

par(new = T)

with(dtf, plot(RMB, 指标2, type="l", axes=F, xlab=NA, ylab=NA,lty=2,col="gray30"))

axis(side = 4)

mtext(side = 4, line = 3, '指标2',cex=0.75)

legend("topright",cex = 0.75,legend=c('指标1', '指标2'),bty = 'n',lty=c(1,2), col=c("gray10", "gray30"))

title(main = 'base:双重坐标轴',cex=0.8,font=1)

par(op)

三重坐标轴:

attach(dtf)

op=par(mar=c(4, 11, 2, 1) + 0.1,cex.axis=0.75)

plot(RMB, 指标1, axes=F, ylim=c(0,max(指标1)), xlab='', ylab='',type='l',col='black', main='',xlim=c(7000,3400))

axis(2, ylim=c(0,max(指标1)),col='black',lwd=2)

mtext(2,text='指标1',line=2,cex = 0.75)

par(new=T)

plot(RMB, 指标2, axes=F, ylim=c(0,max(指标2)), xlab='', lty=2,ylab='',type='l',col='black', main='',xlim=c(7000,3400))

axis(2, ylim=c(0,max(指标2)),col='black',lwd=2,line=3.5)

mtext(2,text='指标2',line=5.5,cex = 0.75)

par(new=T)

plot(RMB, 指标3, axes=F, ylim=c(0,max(指标3)), xlab='', lty=3,ylab='',type='l',col='black', main='',xlim=c(7000,3400))

axis(2, ylim=c(0,max(指标2)),col='black',lwd=2,line=7)

mtext(2,text='指标3',line=9,cex = 0.75)

axis(1,pretty(range(RMB),10))

mtext('RMB',side=1,col='black',line=2,cex=0.75)

legend('topleft',cex=0.65,bty='n',legend=c('指标1','指标2','指标3'),lty=c(1,2,3))

title(main = 'base:三重坐标轴',cex=0.8,font=1)

par(op)

根据自己的需要就可以绘制一张完美的二重或三重坐标图了。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM