将ggplot2中的hex bin设置为相同大小

seb*_*n-c 19 r hexagonal-tiles ggplot2

我正在尝试在几个类别中创建数据的hexbin表示.问题是,面对这些垃圾桶似乎使它们都有不同的尺寸.

set.seed(1) #Create data
bindata <- data.frame(x=rnorm(100), y=rnorm(100))
fac_probs <- dnorm(seq(-3, 3, length.out=26))
fac_probs <- fac_probs/sum(fac_probs)
bindata$factor <- sample(letters, 100, replace=TRUE, prob=fac_probs)

library(ggplot2) #Actual plotting
library(hexbin)

ggplot(bindata, aes(x=x, y=y)) +
  geom_hex() +
  facet_wrap(~factor)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

是否有可能设置一些东西使所有这些箱子的物理尺寸相同?

cbe*_*ica 19

正如朱利叶斯所说,问题在于hexGrob没有得到关于箱子大小的信息,而是从它在方面内发现的差异中猜测出来.

显然,手dxdy一个是有意义的hexGrob- 没有六边形的宽度和高度就像在不给出半径的情况下指定一个圆心.

解决方法:

解决方法

resolution如果构面包含两个x和y不同的相邻haxagons,则该策略有效.因此,作为一种解决方法,我将手动构建一个data.frame,其中包含单元格的x和y中心坐标,以及facetting的因子和计数:

除了问题中指定的库,我还需要

library (reshape2)
Run Code Online (Sandbox Code Playgroud)

而且bindata$factor实际上也需要成为一个因素:

bindata$factor <- as.factor (bindata$factor)
Run Code Online (Sandbox Code Playgroud)

现在,计算基本的六边形网格

h <- hexbin (bindata, xbins = 5, IDs = TRUE, 
             xbnds = range (bindata$x), 
             ybnds = range (bindata$y))
Run Code Online (Sandbox Code Playgroud)

接下来,我们需要根据计算计数 bindata$factor

counts <- hexTapply (h, bindata$factor, table)
counts <- t (simplify2array (counts))
counts <- melt (counts)
colnames (counts)  <- c ("ID", "factor", "counts")
Run Code Online (Sandbox Code Playgroud)

由于我们有单元格ID,我们可以将此data.frame与正确的坐标合并:

hexdf <- data.frame (hcell2xy (h),  ID = h@cell)
hexdf <- merge (counts, hexdf)
Run Code Online (Sandbox Code Playgroud)

这是data.frame的样子:

> head (hexdf)
  ID factor counts          x         y
1  3      e      0 -0.3681728 -1.914359
2  3      s      0 -0.3681728 -1.914359
3  3      y      0 -0.3681728 -1.914359
4  3      r      0 -0.3681728 -1.914359
5  3      p      0 -0.3681728 -1.914359
6  3      o      0 -0.3681728 -1.914359
Run Code Online (Sandbox Code Playgroud)

ggplotting(使用下面的命令)这会产生正确的bin大小,但是这个图有一些奇怪的外观:绘制了0个计数六边形,但只有在其他一些facet填充了这个bin的地方.为了抑制绘图,我们可以设置其中的计数NA并使其na.value完全透明(默认为grey50):

hexdf$counts [hexdf$counts == 0] <- NA

ggplot(hexdf, aes(x=x, y=y, fill = counts)) +
  geom_hex(stat="identity") +
  facet_wrap(~factor) +
  coord_equal () +
  scale_fill_continuous (low = "grey80", high = "#000040", na.value = "#00000000")
Run Code Online (Sandbox Code Playgroud)

得出帖子顶部的数字.

只要binwidth正确而没有facetting,此策略就可以正常工作.如果binwidths设置很小,resolution仍可能会产生过大dxdy.在这种情况下,我们可以提供hexGrob两个相邻的箱(但x和y都不同)和NA每个方面的计数.

dummy <- hgridcent (xbins = 5, 
                    xbnds = range (bindata$x),  
                    ybnds = range (bindata$y),  
                    shape = 1)

dummy <- data.frame (ID = 0,
                     factor = rep (levels (bindata$factor), each = 2),
                     counts = NA,
                     x = rep (dummy$x [1] + c (0, dummy$dx/2), 
                              nlevels (bindata$factor)),
                     y = rep (dummy$y [1] + c (0, dummy$dy  ), 
                              nlevels (bindata$factor)))
Run Code Online (Sandbox Code Playgroud)

这种方法的另一个优点是我们可以删除已经有0个计数的所有行counts,在这种情况下,将大小减少hexdf大约3/4(122行而不是520):

counts <- counts [counts$counts > 0 ,]
hexdf <- data.frame (hcell2xy (h),  ID = h@cell)
hexdf <- merge (counts, hexdf)
hexdf <- rbind (hexdf, dummy)
Run Code Online (Sandbox Code Playgroud)

该图看起来与上面完全相同,但您可以通过na.value不完全透明来可视化差异.


更多关于这个问题

这个问题并不是刻面的唯一问题,但是如果占用太少的箱子就会发生这种问题,因此没有"对角"相邻的箱子被填充.

这是一系列显示问题的最小数据:

首先,我跟踪hexBin所以我得到相同的六边形网格的所有中心坐标ggplot2:::hexBin和返回的对象hexbin:

trace (ggplot2:::hexBin, exit = quote ({trace.grid <<- as.data.frame (hgridcent (xbins = xbins, xbnds = xbnds, ybnds = ybnds, shape = ybins/xbins) [1:2]); trace.h <<- hb}))
Run Code Online (Sandbox Code Playgroud)

设置一个非常小的数据集:

df <- data.frame (x = 3 : 1, y = 1 : 3)
Run Code Online (Sandbox Code Playgroud)

情节:

p <- ggplot(df, aes(x=x, y=y)) +  geom_hex(binwidth=c(1, 1)) +          
     coord_fixed (xlim = c (0, 4), ylim = c (0,4))

p # needed for the tracing to occur
p + geom_point (data = trace.grid, size = 4) + 
    geom_point (data = df, col = "red") # data pts

str (trace.h)

Formal class 'hexbin' [package "hexbin"] with 16 slots
  ..@ cell  : int [1:3] 3 5 7
  ..@ count : int [1:3] 1 1 1
  ..@ xcm   : num [1:3] 3 2 1
  ..@ ycm   : num [1:3] 1 2 3
  ..@ xbins : num 2
  ..@ shape : num 1
  ..@ xbnds : num [1:2] 1 3
  ..@ ybnds : num [1:2] 1 3
  ..@ dimen : num [1:2] 4 3
  ..@ n     : int 3
  ..@ ncells: int 3
  ..@ call  : language hexbin(x = x, y = y, xbins = xbins, shape = ybins/xbins, xbnds = xbnds, ybnds = ybnds)
  ..@ xlab  : chr "x"
  ..@ ylab  : chr "y"
  ..@ cID   : NULL
  ..@ cAtt  : int(0) 
Run Code Online (Sandbox Code Playgroud)

我重复一下情节,省略数据点2:

p <- ggplot(df [-2,], aes(x=x, y=y)) +  geom_hex(binwidth=c(1, 1)) +          coord_fixed (xlim = c (0, 4), ylim = c (0,4))
p
p + geom_point (data = trace.grid, size = 4) + geom_point (data = df, col = "red")
str (trace.h)

Formal class 'hexbin' [package "hexbin"] with 16 slots
  ..@ cell  : int [1:2] 3 7
  ..@ count : int [1:2] 1 1
  ..@ xcm   : num [1:2] 3 1
  ..@ ycm   : num [1:2] 1 3
  ..@ xbins : num 2
  ..@ shape : num 1
  ..@ xbnds : num [1:2] 1 3
  ..@ ybnds : num [1:2] 1 3
  ..@ dimen : num [1:2] 4 3
  ..@ n     : int 2
  ..@ ncells: int 2
  ..@ call  : language hexbin(x = x, y = y, xbins = xbins, shape = ybins/xbins, xbnds = xbnds, ybnds = ybnds)
  ..@ xlab  : chr "x"
  ..@ ylab  : chr "y"
  ..@ cID   : NULL
  ..@ cAtt  : int(0) 
Run Code Online (Sandbox Code Playgroud)

一切都很好 六角绘图搞砸了

  • 请注意,结果来自hexbin同一网格(单元格编号没有更改,只是单元格5不再填充,因此未列出),网格尺寸和范围没有变化.但绘制的六边形确实发生了巨大变化.

  • 另请注意hgridcent忘记返回第一个单元格的中心坐标(左下角).

虽然它被填充:

df <- data.frame (x = 1 : 3, y = 1 : 3)

p <- ggplot(df, aes(x=x, y=y)) +  geom_hex(binwidth=c(0.5, 0.8)) +          
     coord_fixed (xlim = c (0, 4), ylim = c (0,4))

p # needed for the tracing to occur
p + geom_point (data = trace.grid, size = 4) + 
    geom_point (data = df, col = "red") + # data pts
    geom_point (data = as.data.frame (hcell2xy (trace.h)), shape = 1, size = 6)
Run Code Online (Sandbox Code Playgroud)

一切搞砸了

这里,六边形的渲染可能不正确 - 它们不属于一个六边形网格.


Gee*_*cid 12

我尝试使用晶格使用相同的数据集复制您的解决方案hexbinplot.最初,它给了我一个错误xbnds[1] < xbnds[2] is not fulfilled.此错误是由于错误的数字向量指定了binning应涵盖的值范围.我改变了这些论点hexbinplot,并以某种方式起作用.不确定它是否可以帮助你用ggplot解决它,但它可能是一个起点.

library(lattice)
library(hexbin)
hexbinplot(y ~ x | factor, bindata, xbnds = "panel", ybnds = "panel", xbins=5, 
           layout=c(7,3))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

编辑

虽然矩形垃圾箱stat_bin2d()工作得很好:

ggplot(bindata, aes(x=x, y=y, group=factor)) + 
    facet_wrap(~factor) +
    stat_bin2d(binwidth=c(0.6, 0.6))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Jul*_*ora 5

有两个源文件,我们感兴趣的是:STAT-binhex.rGEOM的hex.r,主要是hexBinhexGrob功能.

正如@Dinre所提到的,这个问题与分面无关.我们可以看到的是,binwidth它没有被忽略并以特殊的方式使用hexBin,该函数分别应用于每个方面.之后,hexGrob适用于每个方面.确保你可以用例如检查它们

trace(ggplot2:::hexGrob, quote(browser()))
trace(ggplot2:::hexBin, quote(browser()))
Run Code Online (Sandbox Code Playgroud)

因此,这解释了为什么尺寸不同 - 它们取决于binwidth每个方面本身的数据和数据.

由于各种坐标变换很难跟踪过程,但请注意输出 hexBin

data.frame(
  hcell2xy(hb),
  count = hb@count,
  density = hb@count / sum(hb@count, na.rm=TRUE)
)
Run Code Online (Sandbox Code Playgroud)

似乎总是看起来很普通,它hexGrob负责绘制十六进制箱,失真,即它有polygonGrob.如果小平面中只有一个十六进制箱,则会出现更严重的异常现象.

dx <- resolution(x, FALSE)
dy <- resolution(y, FALSE) / sqrt(3) / 2 * 1.15
Run Code Online (Sandbox Code Playgroud)

?resolution我们可以看到

描述

 The resolution is is the smallest non-zero distance between adjacent
 values. If there is only one unique value, then the resolution is
 defined to be one.
Run Code Online (Sandbox Code Playgroud)

因此(resolution(x, FALSE) == 1resolution(y, FALSE) == 1)polygonGrob示例中第一个方面的x坐标是

[1] 1.5native  1.5native  0.5native  -0.5native -0.5native 0.5native 
Run Code Online (Sandbox Code Playgroud)

如果我没有错,在这种情况下,原生单位就像npc,所以它们应该在0和1之间.也就是说,在单个十六进制bin的情况下它会超出范围,因为resolution().这个功能也是@Dinre提到的失真的原因,即使有多达几个六角形箱.

因此,目前似乎没有选择具有相同大小的六角形箱.时间(并且对很多因素非常不方便)解决方案可以从这样的事情开始:

library(gridExtra)
set.seed(2)
bindata <- data.frame(x = rnorm(100), y = rnorm(100))
fac_probs <- c(10, 40, 40, 10)
bindata$factor <- sample(letters[1:4], 100, 
                         replace = TRUE, prob = fac_probs)

binwidths <- list(c(0.4, 0.4), c(0.5, 0.5),
                  c(0.5, 0.5), c(0.4, 0.4))

plots <- mapply(function(w,z){
  ggplot(bindata[bindata$factor == w, ], aes(x = x, y = y)) +
    geom_hex(binwidth = z) + theme(legend.position = 'none')
}, letters[1:4], binwidths, SIMPLIFY = FALSE)

do.call(grid.arrange, plots)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述