2016-01-18 52 views
3

R有许多标准符号/形状可用作R线图中数据点的标记(如果含糊不清,请参阅我的意思http://www.cookbook-r.com/Graphs/Shapes_and_line_types/) 。使用自定义图像替代R线图标记的标准形状

我想要做的是使用我自己的自定义图标(例如苹果,香蕉,樱桃等GIF)来代替标准形状。

R我该怎么办?不必是原生R图形,我可以打包,例如ggplot2等。

我的预期用途是在一个折线图上,标记也出现在图例上。

这里的答案(Labelling the plots with images on graph in ggplot2)通过直接绘制图像就好像它们是独立的项目一样来解决相似的问题,所以不会与数据/图例真正绑定。

+1

你读[本SO后(http://stackoverflow.com/questions/20733328/labelling-the-plots-with-images-on-graph-in-ggplot2) ?这似乎是以前问过的问题。 –

+1

我做了,但不完全是我想要的;那些是散点图。我正在寻找折线图,其中的点是形状,这将出现在图例中。我会编辑我的问题来澄清 – Ricky

+0

最好的选择可能是[写你自己的geom](https://github.com/hadley/ggplot2/blob/master/vignettes/extending-ggplot2.Rmd#creating-a-新GEOM) – baptiste

回答

5

我不知道如何使用自定义点标记与geom_point一起工作(尽管您可以按照@baptiste的建议创建自己的geom)。然而,如果你愿意忍受一些编码痛苦,你可以使用annotation_custom来创建类似于你用geom_point得到的东西。最痛苦的部分是你必须做一些手动调整(尽管如果你打算这么做的话,你可能会创建一些程序逻辑来处理一些这样的问题)。情节也呈现得非常缓慢。不过,对它进行破解很有趣。

负载包,并获得两个图像,这将成为我们的点标记:

library(ggplot2) 
library(RCurl) 
library(jpeg) 
library(grid) 

## Image 1 
URL1 = "http://www.entertainmentearth.com/images/AUTOIMAGES/QMSER0179lg.jpg" 
serenity = readJPEG(getURLContent(URL1)) 

## Image 2 
URL2 = "http://cdn.pastemagazine.com/www/articles/2010/03/12/malcolm_reynolds.jpg" 
mal = readJPEG(getURLContent(URL2)) 

# Crop the mal image 
mal = mal[40:250,,] 

## Turn images into raster grobs 
serenity = rasterGrob(serenity) 
mal = rasterGrob(mal) 

# Make the white background transparent in the serenity image 
serenity$raster[serenity$raster=="#FFFFFF"] = "#FFFFFF00" 

制造假数据和设置的情节:

# Create fake data 
df = data.frame(x=rep(1:4,2), y=c(1,1,2,4,6.5,5,5.5,4.8), g=rep(c("s","m"),each=4)) 

# Set up a plot 
p = ggplot(df, aes(x, y, group=g)) + 
    geom_line() + 
    theme_bw() 

现在,而不是一个GEOM,使用annotation_custom绘制图像作为点标记。 annotation_custom似乎一次只能处理一个点,而不是一个点的矢量,所以我们将使用for循环来绘制每个点。我们有我们要绘制两个不同的图像,所以我们将使用为每一个单独的循环:

a=0.8 
for (i in rownames(df[df$g=="s",])) { 
    p = p + annotation_custom(serenity, df[i,"x"]-a,df[i,"x"]+a,df[i,"y"]-a,df[i,"y"]+a) 
} 

b=0.4 
for (i in rownames(df[df$g=="m",])) { 
    p = p + annotation_custom(mal, df[i,"x"]-b,df[i,"x"]+b,df[i,"y"]-b,df[i,"y"]+b) 
} 

最后,添加传说和关闭剪裁,使传说会出现在最终的情节:

a = 0.8*a 
b = 0.8*b 

p = p + coord_cartesian(xlim=c(0,5), ylim=c(0,7)) + 
    theme(plot.margin=unit(c(1,10,1,1),"lines")) + 
    annotation_custom(serenity, 5.8-a,5.8+a,3.4-a,3.4+a) + 
    annotate(geom="text", x=5.8+0.5, y=3.4, label="Serenity", hjust=0) + 
    annotation_custom(mal, 5.8-b,5.8+b,4.6-b,4.6+b) + 
    annotate(geom="text", x=5.8+0.5, y=4.6, label="Mal", hjust=0) 

# Turn off clipping 
p <- ggplot_gtable(ggplot_build(p)) 
p$layout$clip <- "off" 
grid.draw(p) 

enter image description here

UPDATE:ggimage package可能ulimately使这更容易一点。下面是一个例子。我想对结果图进行改进。

  • 更改图的纵横比也会改变图像的纵横比,而我更喜欢图像保持其原始纵横比。

  • 宁静的形象有一个白色的背景,涵盖了剧情网格和玛尔的形象(因为宁静是在玛尔后绘制的)。在上面的例子中,我使白色背景变得透明。但是,即使当我将上面创建的栅格栅格保存为jpegs(以便我可以使用具有透明背景的Serenity版本)并重新加载它们(而不是像下面那样从URL中直接获取图像)时,Serenity仍然有一个白色的背景。

  • 图例不使用图像作为“点标记”,而是具有标记通常会存在的空白区域。

也许未来版本的软件包将创建与这些问题相关的额外灵活性,或者可能已经有一种我不知道解决这些问题的方法。

df = data.frame(x=rep(1:4,2), y=c(1,1,2,4,6.5,5,5.5,4.8), 
       Firefly=rep(c("Serenity","Mal"),each=4), 
       image=rep(c("http://www.entertainmentearth.com/images/AUTOIMAGES/QMSER0179lg.jpg", 
          "http://cdn.pastemagazine.com/www/articles/2010/03/12/malcolm_reynolds.jpg"), each=4)) 

ggplot(df, aes(x, y)) + 
    geom_line(aes(group=Firefly)) + 
    geom_image(aes(image=image, size=Firefly)) + 
    theme_bw() + 
    scale_size_manual(values=c(0.1,0.15)) + 
    coord_fixed(ratio=2/3, xlim=c(0.5, 4.5), ylim=c(0,7)) 

enter image description here

相关问题