生信图可视化大全R语言技巧数据-R语言-图表-决策-Linux-Python

科研人员焦虑到头疼的时候,止痛靠艺术.gif

2019-07-28  本文已影响106人  9d760c7ce737

这个要看到最后啊。
最近啃下了图片处理的神包magick, 里面把动图融合到另外一张图片中的操作很神奇。
举个简单的例子。

第一个例子

加载R包,用image_read函数读入图片

install.packages("magick")
library(magick)
# 读取前景图片
banana <- image_read("https://jeroen.github.io/images/banana.gif")

可以用image_scale函数调整图片大小

banana <- image_scale(banana, "150")

导入一张背景图片,调整大小,设置为背景

logo <- image_read("https://jeroen.github.io/images/Rlogo.png")
logo <- image_scale(logo, "200")
background <- image_background(logo, "white", flatten = TRUE)

现在通过image_composite函数把两个图片整合起来,offset参数设置图片的相对位置,第一个加号是x轴,第二个加号是y轴

frames <- image_composite(background, banana, offset = "+70+30")

image_animate函数这是最终图片的帧数快慢

image_animate(frames, fps = 10)

这时候,图片就做好了,好像并不惊艳,因为用PPT就可以实现这个操作。

第二个例子

下面我们就这个例子,再换种方法操作,这里面涉及到批量操作。
一样的读入两张图片,调整大小

library(magick)
logo <- image_read("https://www.r-project.org/logo/Rlogo.png")
banana <- image_read("https://jeroen.github.io/images/banana.gif")
## 调整图片大小
front <- image_scale(banana, "300")
background <- image_scale(logo, "400")

批量地把用image_flatten函数,把动图的帧数一张张融合到背景上,形成多张图片,储存为列表

frames <- lapply(as.list(front), function(x) image_flatten(c(background, x)))

image_join函数把他们合并起来

image_join(frames)

最后再用image_animate函数把他们动起来

image_animate(image_join(frames))

在这里我知道一个概念,就是image_join函数可以操作列表。

第三个例子

下面举第三个例子,学习图片和ggplot2图表的融合。
先读入一张图片,调整大小

frink <- image_read("https://jeroen.github.io/images/frink.png")
frink <- image_scale(frink, "150")

下面这个操作,很不得了,ggplot2直接和图片不好融合,整理提供了一个方案,就是先打开一张画布,把ggplot2的图画在里面,成为能够被识别的对象。
image_graph打开一张画布,然后ggplot2作图,最后关闭这张画布,对象储存为fig

fig <- image_graph(width = 400, height = 400, res = 96)
ggplot2::qplot(mpg, wt, data = mtcars, colour = cyl)
dev.off()

现在我们用之前的image_composite函数就可以把他们融合起来了

image_composite(fig, frink, offset = "+220+70")

当然,把动图插入到ggplot2也是很容易的事情。

frames <- image_composite(fig, banana, offset = "+30+50")
image_animate(frames, fps = 10)

这跟香蕉贱兮兮的哈,真欠揍。

总结一下,

现在重点来了!

我在网上找到一个碉堡的构图函数

phi <- (1 + sqrt(5)) / 2 
golden_angle <- pi*(3-sqrt(5))
create_art <- function(n=1800,u=5,v=0,angle=golden_angle,colors="#ffffff",...){
  my_colours <- colors 
  df <- tibble(
    idx = c(0:(n-1)),
    t = seq(0,2*pi,length.out=n),
    r = sqrt(idx),
    x = r*cos(angle*idx),
    y = r*sin(angle*idx),
    color_angle = atan2(y=y,x=x)
  )
  v <- ifelse(v<u,v,v%%u)
  max_r <- max(df$r)*1.1
  my_art <- df %>% 
    ggplot(aes(x=x,y=y,color=color_angle)) +
    geom_path(data= . %>% filter(idx%%u==v),
              lineend="round", linejoin="mitre", linemitre=3,
              aes(size=idx, alpha=idx)) + 
    coord_fixed() +
    theme_void() +
    scale_alpha_continuous(guide="none", range=c(0,1), trans="sqrt")+ 
    scale_size_continuous(guide="none",  range=c(10,0), trans="sqrt") +
    scale_color_gradientn(guide="none", colors=my_colours) +
    theme(panel.background = element_rect(fill="#000000de")) +
    expand_limits(x=c(-max_r,max_r),y=c(-max_r,max_r)) 
  
  my_art + annotate(geom="text", x=Inf,y=-Inf,
                    label=str_glue('n: {n} | u: {u} | v: {v} | angle: {round(angle,3)} radian'),
                    family="Roboto Condensed", color="#ffffffae",
                    hjust=1,vjust=-1)
}

这个create_art函数可以画出这样的图

library(tibble)
library(dplyr)
library(ggplot2)
library(stringr)
create_art()

更厉害的是,这个函数有四个重要的参数,大概是这样的。
n, 点的数量
u,跳过固定的点
angle,点之间的角度
v,整体图片的角度

我们用patchwork连接多个图来集中展示

devtools::install_github("thomasp85/patchwork")
library(patchwork)

现在仅仅改变点和点之间的角度来作8张图

create_art(n=360,angle=sqrt(2)) +
  create_art(n=360,angle=sqrt(3)) +
  create_art(n=360,angle=sqrt(5)) +
  create_art(n=360,angle=pi/7) +
  create_art(n=360,angle=pi/9) +
  create_art(n=360,angle=pi/46) +
  create_art(n=360,angle=2) +
  create_art(n=360,angle=1) +
  plot_layout(ncol = 4)

很惊艳是吧。
现在仅仅改变跳过的点数这个参数来做8张图

create_art(n=360,u=5) +
  create_art(n=360,u=11) +
  create_art(n=360,u=13) +
  create_art(n=360,u=6) +
  create_art(n=360,u=9) +
  create_art(n=360,u=8) +
  create_art(n=360,u=17) +
  create_art(n=360,u=3) +
  plot_layout(ncol = 4)

不可以思议。

那么现在问题来了,v这个选择整体图片角度的参数还没有用呢,如果我们制作成一系列带不同角度的图片,再用刚才学到的批量技能把他们融合起来,岂不是能够创造炫酷的动图?
首先,image_graph打开画布
其次,制作一个数据框,把几个参数一行行表示,这里面改变的只有v
使用pmap函数批量操作,这个函数很神奇,你如果传给他一个数据框,他就把一行一行的数据当做参数传给后面的函数
最后,关闭图形设备,所有的图片以列表形式存在imgs_1中。

library(magick)
imgs_1 <- image_graph(width=600, height=600)
params <- tibble(n=1800,u=44,v=seq(0,u-1,by=2),angle=golden_angle)
purrr::pmap(params,create_art)
dev.off()

这时候再用image_animate函数把她动起来。

image_animate(imgs_1,fps=10)

这真是思路决定出路
换一个图更加炫酷

imgs_2 <- image_graph(width=600, height=600)
params <- tibble(n=1800,u=22,v=seq(0,u-1,by=1),angle=-golden_angle)
purrr::pmap(params,create_art)
dev.off()
image_animate(imgs_2,fps=10)

好了,我们已经理解了他做动图的逻辑,就是把一系列图片合在一起,按照一定速度一张张播放,最终产生gif。

制作gif

如果这个理解是对的话,我们就有了一个制作gif动图的神器。
比如我在PPT里面先创作几张图片导出来,放在当前工作目录的magick文件夹中


然后批量读入,联合,加速播放即可

library(magick)
dd <- lapply(paste0("./magick/",list.files("./magick",pattern = "*.jpg")),image_read)
image_animate(image_join(dd),fps=4)

服不服?
理论上,如果你给他足够多的依次发生的图片,什么动作小人书,小电影都没问题,以下我简单地示范一下。


本次参考(甚至是复制)的教程在这里:
magick
https://cran.r-project.org/web/packages/magick/vignettes/intro.html#installing_magick
create_art:
https://chichacha.netlify.com/2019/01/29/playing-around-with-phyllotactic-spirals/

好了,我是果子,这几天很焦虑,明天见。

上一篇下一篇

猜你喜欢

热点阅读