如何在ggplot中使用图像作为点?

58
有没有办法在ggplot2的散点图中使用特定的小图片作为点?理想情况下,我希望能够根据变量调整图片大小。
这是一个例子:
library(ggplot2)
p <- ggplot(mtcars, aes(wt, mpg))
p + geom_point(aes(size = qsec, shape = factor(cyl)))

我想知道是否有一种方法可以提供一个特定的图像作为形状?

3个回答

35

有一个叫做ggimage的库可以实现这个功能。在这里查看介绍文档

您只需要向您的data.frame添加一列图片地址,它们可以存储在网络上或者本地电脑上,之后您就可以使用geom_image()函数了:

library("ggplot2")
library("ggimage")

# create a df

set.seed(2017-02-21)
d <- data.frame(x = rnorm(10),
                y = rnorm(10),
                image = sample(c("https://www.r-project.org/logo/Rlogo.png",
                                 "https://jeroenooms.github.io/images/frink.png"),
                               size=10, replace = TRUE)
                )
# plot2
  ggplot(d, aes(x, y)) + geom_image(aes(image=image), size=.05)

输入图像的描述

注意,ggimage 依赖于 EBImage。 因此,要安装 gginamge,我必须执行以下操作:

# install EBImage
  source("https://bioconductor.org/biocLite.R")
  biocLite("EBImage")
# install ggimage
  install.packages("ggimage")

1
这是一个展示ggimage使用的绝佳例子。如果您能提供一个从计算机中使用图像的例子,将不胜感激。谢谢。 - MYaseen208
2
如何添加图例,以便图像在图例中,并对其进行注释? - yuliaUU
您有解决方案可以防止更改绘图纵横比时出现失真吗? - MartineJ
我猜你可以尝试添加 + coord_equal() 或者 + theme(aspect.ratio=1)。这两个替代方案中的一个可能会解决纵横比问题。 - rafa.pereira
显示剩余2条评论

32

这里有一个极简的几何图形,可以显示光栅图像而不是点。

library(ggplot2)
library(grid)

## replace by a named list with matrices to be displayed
## by rasterGrob
.flaglist <- list("ar" = matrix(c("blue", "white", "blue"), 1), 
                  "fr" = matrix(c("blue", "white", "red"), 1))

flagGrob <- function(x, y, country, size=1, alpha=1){
  grob(x=x, y=y, country=country, size=size, cl = "flag")
}

drawDetails.flag <- function(x, recording=FALSE){

  for(ii in seq_along(x$country)){
    grid.raster(x$x[ii], x$y[ii], 
                width = x$size[ii]*unit(1,"mm"), height = x$size[ii]*unit(0.5,"mm"),
                image = .flaglist[[x$country[[ii]]]], interpolate=FALSE)
  }
}


scale_country <- function(..., guide = "legend") {
  sc <- discrete_scale("country", "identity", scales::identity_pal(), ..., guide = guide)

  sc$super <- ScaleDiscreteIdentity
  class(sc) <- class(ScaleDiscreteIdentity)
  sc
}

GeomFlag <- ggproto("GeomFlag", Geom,
                    required_aes = c("x", "y", "country"),
                    default_aes = aes(size = 5, country="fr"),

                    draw_key = function (data, params, size) 
                    {
                      flagGrob(0.5,0.5, country=data$country,  size=data$size)
                    },

                    draw_group = function(data, panel_scales, coord) {
                      coords <- coord$transform(data, panel_scales)     
                      flagGrob(coords$x, coords$y, coords$country, coords$size)
                    }
)

geom_flag <- function(mapping = NULL, data = NULL, stat = "identity",
                      position = "identity", na.rm = FALSE, show.legend = NA, 
                      inherit.aes = TRUE, ...) {
  layer(
    geom = GeomFlag, mapping = mapping,  data = data, stat = stat, 
    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
    params = list(na.rm = na.rm, ...)
  )
}


set.seed(1234)
d <- data.frame(x=rnorm(10), y=rnorm(10), 
                country=sample(c("ar","fr"), 10, TRUE), 
                stringsAsFactors = FALSE)


ggplot(d, aes(x=x, y=y, country=country, size=x)) + 
  geom_flag() + 
  scale_country()

输入图像描述

(来自ggflags包的输出)


3
我知道现在有点过时了,但你能不能提供一些评论来���释这段代码呢?创建geoms似乎非常有用,但是如何入手有点难以理解。 - MokeEire
1
@MokeEire,一个不错的起点:https://cran.r-project.org/web/packages/ggplot2/vignettes/extending-ggplot2.html - PatrickT

4

首先,这是你的答案:

为了向你展示如何更好地使用小部件来表示数据差异,我向你介绍 R 图库中 切诺夫面 的例子。:

alt text
(来源: free.fr)

生成此示例的所有代码都可在该网站上获得。

或者,查看ggplot的stat_spoke以获得一个简单的小部件: alt text
(来源:had.co.nz)

grImport提供了一种机制,可以将简单的PDF图像导入到您的绘图中用作点。

现在对您的示例进行评论。


这不是散点图,而是有序数据点的流式列表,其中使用颜色表示文本变量之一,并且使用了无信息和冗余的小部件来框定数据,但在大小或形状方面没有提供任何视觉反馈。
它不是一个好的图表,因为它完全未能回答所述问题“支付更多是否会导致更好的结果”,并且让读者自己努力得出结论(必要时使用其他图表)。
此外,作者浪费了x、y轴,本可以用它们来根据收益和结果的位置来放置元素,以提供对性价比的视觉理解。相反,他们选择按每人费用与平均毕业率的比率对图标进行排序,这在某种程度上是有用的,但不能回答所述问题,并且不能直接比较大学之间的相对比率或成本与价值之间的关系。
正如我所说,在我看来,这是一个糟糕的图表,你复制它将不会为你的读者提供良好的服务。

谢谢你的回答!我已经删除了那个链接,因为我认为你是对的。更普遍地说,除非我漏掉了什么,否则似乎faces()函数和stat_spoke都不能满足我的需求。faces()只显示面孔...你无法改变图像。而stat_spoke也不允许你改变图像。但是grImport看起来非常有前途!谢谢! - griffin
5
您的图片链接已损坏……我稍微查看了一下试图修复它们,但没有成功。 - joran
6
看起来问题已经被编辑到回答不再有意义的程度了;还有一些图像链接已经失效。 - Peter Ellis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接