跟着Nature microbiology学画图~R语言ggplot2以原点为中心画坐标轴

2021-01-20 16:03:23 浏览数 (2)

前天的推文里跟着Nature microbiology学画图~ggplot2散点图添加分组边界模仿论文中的散点图以原点为中心花了一个坐标轴,R语言的ggplot2画图通常坐标轴是在左下角,如果想把坐标轴改成以原点(0,0)为中心应该如何实现呢?经过搜索找到了一些办法,记录在这篇推文里。

参考的链接是

https://stackoverflow.com/questions/17753101/center-x-and-y-axis-with-ggplot2

第一步需要确定数据的范围,比如用鸢尾花的数据集花瓣长宽分别做x和y

summary()函数看一下数据的范围

代码语言:javascript复制
summary(iris)

最大值是6.9,那我们将坐标轴的范围设置为-7~7.

代码语言:javascript复制
axis_begin<- -7
axis_end<-7

刻度设置为15个

代码语言:javascript复制
total_ticks<-15

最终是通过geom_segment()函数来画坐标轴,所以需要先构造画图的数据

代码语言:javascript复制
library(magrittr)#这个包里有管道符
tick_frame<-data.frame(ticks=seq(axis_begin,
                                 axis_end,
                                 length.out = total_ticks),
                       zero=0)%>%
  subset(ticks != 0)
tick_frame
label_frame<-data.frame(lab=seq(axis_begin,axis_end),
                        zero=0)%>%
  subset(lab!=0&abs(lab)!=7)
label_frame
首先是基本的散点图
代码语言:javascript复制
ggplot(iris,aes(x=Petal.Length,y=Petal.Width)) 
  geom_point(color="red",size=3)

image.png

接下来简单修饰

包括

  • 去灰色背景
  • 更改坐标轴范围
  • 添加最外圈的方框
  • 去掉最外圈的文字和小短线
代码语言:javascript复制
ggplot(iris,aes(x=Petal.Length,y=Petal.Width)) 
  geom_point(color="red",size=3) 
  theme_bw() 
  scale_x_continuous(limits = c(-7,7)) 
  scale_y_continuous(limits = c(-7,7)) 
  theme(panel.grid = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank())

image.png

添加坐标轴的线和刻度以及文字标签
代码语言:javascript复制
ggplot(iris,aes(x=Petal.Length,y=Petal.Width)) 
  geom_point(color="red",size=3) 
  theme_bw() 
  theme(panel.grid = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank()) 
  
  geom_segment(x=0,xend=0,y=-7,yend=7) 
  geom_segment(x=-7,xend=7,y=0,yend=0) 
  scale_x_continuous(expand = c(0,0),limits = c(-7,7)) 
  scale_y_continuous(expand = c(0,0),limits = c(-7,7)) 
  geom_segment(data=tick_frame,aes(x=zero,xend=zero 0.1,
                                   y=ticks,yend=ticks)) 
  geom_segment(data=tick_frame,aes(x=ticks,xend=ticks,
                                   y=zero,yend=zero 0.1)) 
  geom_text(data=label_frame,aes(x=zero-0.2,y=lab,label=lab)) 
  geom_text(data=label_frame,aes(x=lab,y=zero-0.2,label=lab))

最终的效果如下

在前天的推文下跟着Nature microbiology学画图~ggplot2散点图添加分组边界有人留言直接把以上代码打包成了函数

代码语言:javascript复制
draw_axis_line <- function(length_x,length_y,tick_step=NULL,lab_step=NULL){       
  axis_x_begin <- -1 * length_x    
  axis_x_end <- length_x    
  axis_y_begin  <- -1 * length_y    
  axis_y_end    <- length_y        
  if (missing(tick_step))        
    tick_step <- 1    
  if (is.null(lab_step))        
    lab_step <- 2        #axis ticks data    
  tick_x_frame <- data.frame(ticks=seq(axis_x_begin,axis_x_end,by=tick_step))    
  tick_y_frame <- data.frame(ticks=seq(axis_y_begin,axis_y_end,by=tick_step))    #axis labels data    
  lab_x_frame <- subset(data.frame(lab=seq(axis_x_begin,axis_x_end,by=lab_step),zero=0),lab!=0)    
  lab_y_frame <- subset(data.frame(lab=seq(axis_y_begin,axis_y_end,by=lab_step),zero=0),lab!=0)        #set tick length    
  tick_x_length <- 15/length(tick_x_frame$ticks)/2    
  tick_y_length <- 8/length(tick_y_frame$ticks)/2        #set zero point    
  data <- data.frame(x=0,y=0)
  library(ggplot2)
  p <- ggplot(data=data)      #draw axis line    
    geom_segment(y=0,yend=0,x=axis_x_begin,xend=axis_x_end,size=0.5)       
    geom_segment(x=0,xend=0,y=axis_y_begin,yend=axis_y_end,size=0.5)      #draw x ticks    
    geom_segment(data=tick_x_frame,aes(x=ticks,xend=ticks,y=0,yend=0   tick_x_length))      #draw y ticks    
    geom_segment(data=tick_y_frame,aes(x=0,xend=0   tick_y_length,y=ticks,yend=ticks))       #labels    
    geom_text(data=lab_x_frame,aes(x=lab,y=zero,label=lab),vjust=1.5)      
    geom_text(data=lab_y_frame,aes(x=zero,y=lab,label=lab),hjust=1.5)      
    theme_void()        
  return(p)}

画图的时候直接用如下代码

代码语言:javascript复制
draw_axis_line(20, 4)

20是x轴的范围,4是y轴的范围

最终的出图效果

image.png

在文章开头提到的参考链接里,有人还提供了一个主题函数
代码语言:javascript复制
theme_geometry <- function(xvals, yvals, xgeo = 0, ygeo = 0, 
                           color = "black", size = 1, 
                           xlab = "x", ylab = "y",
                           ticks = 10,
                           textsize = 3,
                           xlimit = max(abs(xvals),abs(yvals)),
                           ylimit = max(abs(yvals),abs(xvals)),
                           epsilon = max(xlimit,ylimit)/50){

  #INPUT:
  #xvals .- Values of x that will be plotted
  #yvals .- Values of y that will be plotted
  #xgeo  .- x intercept value for y axis
  #ygeo  .- y intercept value for x axis
  #color .- Default color for axis
  #size  .- Line size for axis
  #xlab  .- Label for x axis
  #ylab  .- Label for y axis
  #ticks .- Number of ticks to add to plot in each axis
  #textsize .- Size of text for ticks
  #xlimit .- Limit value for x axis 
  #ylimit .- Limit value for y axis
  #epsilon .- Parameter for small space


  #Create axis 
  xaxis <- data.frame(x_ax = c(-xlimit, xlimit), y_ax = rep(ygeo,2))
  yaxis <- data.frame(x_ax = rep(xgeo, 2), y_ax = c(-ylimit, ylimit))

  #Add axis
  theme.list <- 
  list(
    theme_void(), #Empty the current theme
    geom_line(aes(x = x_ax, y = y_ax), color = color, size = size, data = xaxis),
    geom_line(aes(x = x_ax, y = y_ax), color = color, size = size, data = yaxis),
    annotate("text", x = xlimit   2*epsilon, y = ygeo, label = xlab, size = 2*textsize),
    annotate("text", x = xgeo, y = ylimit   4*epsilon, label = ylab, size = 2*textsize),
    xlim(-xlimit - 7*epsilon, xlimit   7*epsilon), #Add limits to make it square
    ylim(-ylimit - 7*epsilon, ylimit   7*epsilon)  #Add limits to make it square
  )

  #Add ticks programatically
  ticks_x <- round(seq(-xlimit, xlimit, length.out = ticks),2)
  ticks_y <- round(seq(-ylimit, ylimit, length.out = ticks),2)

  #Add ticks of x axis
  nlist <- length(theme.list)
  for (k in 1:ticks){

    #Create data frame for ticks in x axis
    xtick <- data.frame(xt = rep(ticks_x[k], 2), 
                        yt = c(xgeo   epsilon, xgeo - epsilon))

    #Create data frame for ticks in y axis
    ytick <- data.frame(xt = c(ygeo   epsilon, ygeo - epsilon), 
                        yt = rep(ticks_y[k], 2))

    #Add ticks to geom line for x axis
    theme.list[[nlist   4*k-3]] <- geom_line(aes(x = xt, y = yt), 
                                         data = xtick, size = size, 
                                         color = color)

    #Add labels to the x-ticks
    theme.list[[nlist   4*k-2]] <- annotate("text", 
                                            x = ticks_x[k], 
                                            y = ygeo - 2.5*epsilon,
                                            size = textsize,
                                            label = paste(ticks_x[k]))


    #Add ticks to geom line for y axis
    theme.list[[nlist   4*k-1]] <- geom_line(aes(x = xt, y = yt), 
                                             data = ytick, size = size, 
                                             color = color)

    #Add labels to the y-ticks
    theme.list[[nlist   4*k]] <- annotate("text", 
                                            x = xgeo - 2.5*epsilon, 
                                            y = ticks_y[k],
                                            size = textsize,
                                            label = paste(ticks_y[k]))
  }

  #Add theme
  #theme.list[[3]] <- 
  return(theme.list)
}

画图代码

代码语言:javascript复制
simdata <- data.frame(x = rnorm(50), y = rnorm(50))

ggplot(simdata)  
  theme_geometry(simdata$x, simdata$y)  
  geom_point(aes(x = x, y = y), size = 3, color = "red")   
  ggtitle("More geometric example")

最终效果如下

0 人点赞