在 ggplot2 散点图中使用伪彩色来指示密度
Using pseudocolour in ggplot2 scatter plot to indicate density
有人知道如何创建像屏幕截图中那样的图表吗?我试图通过调整 alpha 获得类似的效果,但这会使离群值几乎不可见。我只从一个叫做 FlowJo 的软件中知道这种类型的图表,在这里他们将其称为 "pseudocolored dot plot"。不确定这是否是官方术语。
我想专门在 ggplot2 中执行此操作,因为我需要分面选项。我附上了我的一个图表的另一个屏幕截图。垂直线描绘了某些基因组区域的突变簇。其中一些集群比其他集群密集得多。我想用密度颜色来说明这一点。
数据很大,很难模拟,但还是试一试吧。我看起来不像实际数据,但数据格式是一样的。
chr <- c(rep(1:10,1000))
position <- runif(10000, min=0, max=5e8)
distance <- runif(10000, min=1, max=1e5)
log10dist <- log10(distance)
df1 <- data.frame(chr, position, distance, log10dist)
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25, alpha=0.5, show.legend = FALSE) +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x")
非常感谢任何帮助。
library(ggplot2)
library(ggalt)
library(viridis)
chr <- c(rep(1:10,1000))
position <- runif(10000, min=0, max=5e8)
distance <- runif(10000, min=1, max=1e5)
log10dist <- log10(distance)
df1 <- data.frame(chr, position, distance, log10dist)
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25, show.legend = FALSE) +
stat_bkde2d(aes(fill=..level..), geom="polygon") +
scale_fill_viridis() +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x")
实际上,我会先猜测初始带宽,然后计算出最佳带宽。除了采用懒惰的方法并仅绘制点 w/o 过滤(smoothScatter()
过滤除基于 npoints
的异常值之外的所有内容)这会像您发布的示例一样生成 "smoothed scatterplot" .
smoothScatter()
使用不同的默认值,所以结果有点不同:
par(mfrow=c(nr=2, nc=5))
for (chr in unique(df1$chr)) {
plt_df <- dplyr::filter(df1, chr==chr)
smoothScatter(df1$position, df1$log10dist, colramp=viridis)
}
geom_hex()
将显示异常值,但不是不同的点:
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25, show.legend = FALSE, color="red") +
scale_fill_viridis() +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x")
这个:
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25) +
stat_bkde2d(bandwidth=c(18036446, 0.05014539),
grid_size=c(128, 128), geom="polygon", aes(fill=..level..)) +
scale_y_continuous(limits=c(3.5, 5.1)) +
scale_fill_viridis() +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x") +
theme_bw() +
theme(panel.grid=element_blank())
使您非常接近 smoothScatter()
使用的默认值,但仅通过限制 y 轴限制就可以巧妙地完成 nrpoints
过滤代码在 smoothScatter()
函数中所做的大部分工作。
叫我老派,但为什么不使用包 latticeExtra 中的 panel.smoothScatter
。它提供对 smoothScatter
的直接访问,但鉴于它是一个面板功能,它会自动将其应用于已定义面板的每个子集。你说你需要 "facetting" 所以 lattice 是一个明显的选择,因为它被明确设计为产生小的倍数(即小平面,或者在格子中,面板)。使用 y ~ x | g
可以轻松创建面板,其中 g
是用于定义小倍数的变量。对于您的示例,这只是:
library(latticeExtra)
chr <- c(rep(1:10,1000))
position <- runif(10000, min=0, max=5e8)
distance <- runif(10000, min=1, max=1e5)
log10dist <- log10(distance)
df1 <- data.frame(chr, position, distance, log10dist)
clrs <- colorRampPalette(brewer.pal(9, "Reds"))
xyplot(log10dist ~ position | chr, data = df1,
panel = panel.smoothScatter, layout = c(5, 2),
as.table = TRUE)
这样您就可以完全控制平滑功能,无需修改。
虽然生成可能有数百万个点的图可能需要大量计算,但这里有一个解决方案,可以根据每个点的局部密度(即“伪彩色”点图)为每个点着色。
计算局部密度的通用函数(比较快)。
densVals <- function(x, y = NULL, nbin = 128, bandwidth, range.x) {
dat <- cbind(x, y)
# limit dat to strictly finite values
sel <- is.finite(x) & is.finite(y)
dat.sel <- dat[sel, ]
# density map with arbitrary graining along x and y
map <- grDevices:::.smoothScatterCalcDensity(dat.sel, nbin, bandwidth)
map.x <- findInterval(dat.sel[, 1], map$x1)
map.y <- findInterval(dat.sel[, 2], map$x2)
# weighted mean of the fitted density map according to how close x and y are
# to the arbitrary grain of the map
den <- mapply(function(x, y) weighted.mean(x = c(
map$fhat[x, y], map$fhat[x + 1, y + 1],
map$fhat[x + 1, y], map$fhat[x, y + 1]), w = 1 / c(
map$x1[x] + map$x2[y], map$x1[x + 1] + map$x2[y + 1],
map$x1[x + 1] + map$x2[y], map$x1[x] + map$x2[y + 1])),
map.x, map.y)
# replace missing density estimates with NaN
res <- rep(NaN, length(sel))
res[sel] <- den
res
}
给定染色体分组,将其应用于每个点。
library(dplyr)
library(ggplot2)
df1 %>% group_by(chr) %>% mutate(point_density = densVals(position, log10dist)) %>%
arrange(chr, point_density) %>%
ggplot(aes(x = position, y = log10dist, color = point_density)) +
geom_point(size = .5) +
scale_color_viridis_c() +
facet_wrap(vars(chr), ncol = 5, scales = "free_x")
(pseudo-colored dot plot)
有人知道如何创建像屏幕截图中那样的图表吗?我试图通过调整 alpha 获得类似的效果,但这会使离群值几乎不可见。我只从一个叫做 FlowJo 的软件中知道这种类型的图表,在这里他们将其称为 "pseudocolored dot plot"。不确定这是否是官方术语。
我想专门在 ggplot2 中执行此操作,因为我需要分面选项。我附上了我的一个图表的另一个屏幕截图。垂直线描绘了某些基因组区域的突变簇。其中一些集群比其他集群密集得多。我想用密度颜色来说明这一点。
数据很大,很难模拟,但还是试一试吧。我看起来不像实际数据,但数据格式是一样的。
chr <- c(rep(1:10,1000))
position <- runif(10000, min=0, max=5e8)
distance <- runif(10000, min=1, max=1e5)
log10dist <- log10(distance)
df1 <- data.frame(chr, position, distance, log10dist)
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25, alpha=0.5, show.legend = FALSE) +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x")
非常感谢任何帮助。
library(ggplot2)
library(ggalt)
library(viridis)
chr <- c(rep(1:10,1000))
position <- runif(10000, min=0, max=5e8)
distance <- runif(10000, min=1, max=1e5)
log10dist <- log10(distance)
df1 <- data.frame(chr, position, distance, log10dist)
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25, show.legend = FALSE) +
stat_bkde2d(aes(fill=..level..), geom="polygon") +
scale_fill_viridis() +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x")
实际上,我会先猜测初始带宽,然后计算出最佳带宽。除了采用懒惰的方法并仅绘制点 w/o 过滤(smoothScatter()
过滤除基于 npoints
的异常值之外的所有内容)这会像您发布的示例一样生成 "smoothed scatterplot" .
smoothScatter()
使用不同的默认值,所以结果有点不同:
par(mfrow=c(nr=2, nc=5))
for (chr in unique(df1$chr)) {
plt_df <- dplyr::filter(df1, chr==chr)
smoothScatter(df1$position, df1$log10dist, colramp=viridis)
}
geom_hex()
将显示异常值,但不是不同的点:
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25, show.legend = FALSE, color="red") +
scale_fill_viridis() +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x")
这个:
ggplot(df1, aes(position, log10dist)) +
geom_point(shape=16, size=0.25) +
stat_bkde2d(bandwidth=c(18036446, 0.05014539),
grid_size=c(128, 128), geom="polygon", aes(fill=..level..)) +
scale_y_continuous(limits=c(3.5, 5.1)) +
scale_fill_viridis() +
facet_wrap(~chr, ncol = 5, nrow = 2, scales = "free_x") +
theme_bw() +
theme(panel.grid=element_blank())
使您非常接近 smoothScatter()
使用的默认值,但仅通过限制 y 轴限制就可以巧妙地完成 nrpoints
过滤代码在 smoothScatter()
函数中所做的大部分工作。
叫我老派,但为什么不使用包 latticeExtra 中的 panel.smoothScatter
。它提供对 smoothScatter
的直接访问,但鉴于它是一个面板功能,它会自动将其应用于已定义面板的每个子集。你说你需要 "facetting" 所以 lattice 是一个明显的选择,因为它被明确设计为产生小的倍数(即小平面,或者在格子中,面板)。使用 y ~ x | g
可以轻松创建面板,其中 g
是用于定义小倍数的变量。对于您的示例,这只是:
library(latticeExtra)
chr <- c(rep(1:10,1000))
position <- runif(10000, min=0, max=5e8)
distance <- runif(10000, min=1, max=1e5)
log10dist <- log10(distance)
df1 <- data.frame(chr, position, distance, log10dist)
clrs <- colorRampPalette(brewer.pal(9, "Reds"))
xyplot(log10dist ~ position | chr, data = df1,
panel = panel.smoothScatter, layout = c(5, 2),
as.table = TRUE)
这样您就可以完全控制平滑功能,无需修改。
虽然生成可能有数百万个点的图可能需要大量计算,但这里有一个解决方案,可以根据每个点的局部密度(即“伪彩色”点图)为每个点着色。
计算局部密度的通用函数(比较快)。
densVals <- function(x, y = NULL, nbin = 128, bandwidth, range.x) {
dat <- cbind(x, y)
# limit dat to strictly finite values
sel <- is.finite(x) & is.finite(y)
dat.sel <- dat[sel, ]
# density map with arbitrary graining along x and y
map <- grDevices:::.smoothScatterCalcDensity(dat.sel, nbin, bandwidth)
map.x <- findInterval(dat.sel[, 1], map$x1)
map.y <- findInterval(dat.sel[, 2], map$x2)
# weighted mean of the fitted density map according to how close x and y are
# to the arbitrary grain of the map
den <- mapply(function(x, y) weighted.mean(x = c(
map$fhat[x, y], map$fhat[x + 1, y + 1],
map$fhat[x + 1, y], map$fhat[x, y + 1]), w = 1 / c(
map$x1[x] + map$x2[y], map$x1[x + 1] + map$x2[y + 1],
map$x1[x + 1] + map$x2[y], map$x1[x] + map$x2[y + 1])),
map.x, map.y)
# replace missing density estimates with NaN
res <- rep(NaN, length(sel))
res[sel] <- den
res
}
给定染色体分组,将其应用于每个点。
library(dplyr)
library(ggplot2)
df1 %>% group_by(chr) %>% mutate(point_density = densVals(position, log10dist)) %>%
arrange(chr, point_density) %>%
ggplot(aes(x = position, y = log10dist, color = point_density)) +
geom_point(size = .5) +
scale_color_viridis_c() +
facet_wrap(vars(chr), ncol = 5, scales = "free_x")
(pseudo-colored dot plot)