Answers:
这是一项艰巨的任务,没有现成的解决方案(这当然是因为密度图是如此诱人的后备,而没人真正关心)。所以,你可以做什么?
如果它们确实重叠(即X和Y坐标完全相同)并且您没有使用Alpha,则最好的办法就是使用以下方法减少重叠 unique
(使用alpha,可以将它们叠加在这样的组上)。
如果不是,您可以手动将坐标四舍五入到最接近的像素并使用以前的方法(但是这是一个肮脏的解决方案)。
最后,您仅可以使用密度图对最密集区域中的点进行二次采样。另一方面,这将不会产生完全相同的图,并且如果未精确调整,可能会引入伪影。
unique
通过四舍五入或通过四舍五入减少重叠可能会导致图的偏差(欺骗性)。重要的是要通过某种图形方式(例如亮度或向日葵图)指示重叠的数量。
看一下实现Dan Carr的纸张/方法的hexbin软件包。该PDF小品有更多的细节,我引述如下:
1概述
六边形合并是一种双变量直方图,可用于可视化具有大n的数据集中的结构。六边形合并的基本概念非常简单。
- 集合(range(x),range(y))上的xy平面由六边形的规则网格细分。
- 计算落在每个六边形中的点数并存储在数据结构中
如果以巧妙的方式选择网格的大小和色带上的切口,则数据的固有结构应出现在合并图中。六边形合并与直方图同样要注意,在选择合并参数时应格外小心
smoothScatter {RColorBrewer}
和densCols {grDevices}
。我可以确认它与遗传数据中的千至百万个点非常有效。
我必须承认,我不完全理解你的最后一段:
“我不是在寻找密度图(尽管它们通常是有用的),但我希望获得与简单的图调用相同的输出,但是如果可能的话,它要比数百万的超图快得多。”
还不清楚您要查找哪种类型的绘图(函数)。
假定您具有度量变量,则可能会发现六角形合并图或向日葵图很有用。有关更多参考,请参见
这是我叫的文件bigplotfix.R
。如果您提供它,它将定义一个包装,当包装plot.xy
数据很大时,将为其“压缩” 包装数据。如果输入较小,则包装器不执行任何操作,但是如果输入较大,则包装器将其分成多个块,并仅绘制每个块的最大和最小x和y值。采购bigplotfix.R
也重新绑定graphics::plot.xy
以指向包装器(多次采购是可以的)。
请注意,plot.xy
是一个标准的绘图方法,如在“主力”的功能plot()
,lines()
以及points()
。因此,您可以不修改而继续在代码中使用这些功能,并且大图将被自动压缩。
这是一些示例输出。它本质上是plot(runif(1e5))
,带有点和线,带有或不带有此处实现的“压缩”。由于压缩的性质,“压缩点”图缺少中间区域,但是“压缩线”图看起来更接近未压缩的原始图。时间是针对png()
设备的;出于某些原因,png
设备中的点比设备中的点要快得多X11
,但是其加速却X11
是可比的(X11(type="cairo")
比X11(type="Xlib")
我的实验要慢)。
我写这篇文章的原因是因为我厌倦了plot()
在大型数据集(例如WAV文件)上意外运行。在这种情况下,我将不得不选择等待几分钟以完成绘图,然后终止我的R会话并发出信号(从而丢失我最近的命令历史记录和变量)。现在,如果我记得在每个会话之前加载此文件,那么在这些情况下,我实际上可以获得一个有用的图。一条小的警告消息指示何时已“压缩”绘图数据。
# bigplotfix.R
# 28 Nov 2016
# This file defines a wrapper for plot.xy which checks if the input
# data is longer than a certain maximum limit. If it is, it is
# downsampled before plotting. For 3 million input points, I got
# speed-ups of 10-100x. Note that if you want the output to look the
# same as the "uncompressed" version, you should be drawing lines,
# because the compression involves taking maximum and minimum values
# of blocks of points (try running test_bigplotfix() for a visual
# explanation). Also, no sorting is done on the input points, so
# things could get weird if they are out of order.
test_bigplotfix = function() {
oldpar=par();
par(mfrow=c(2,2))
n=1e5;
r=runif(n)
bigplotfix_verbose<<-T
mytitle=function(t,m) { title(main=sprintf("%s; elapsed=%0.4f s",m,t["elapsed"])) }
mytime=function(m,e) { t=system.time(e); mytitle(t,m); }
oldbigplotfix_maxlen = bigplotfix_maxlen
bigplotfix_maxlen <<- 1e3;
mytime("Compressed, points",plot(r));
mytime("Compressed, lines",plot(r,type="l"));
bigplotfix_maxlen <<- n
mytime("Uncompressed, points",plot(r));
mytime("Uncompressed, lines",plot(r,type="l"));
par(oldpar);
bigplotfix_maxlen <<- oldbigplotfix_maxlen
bigplotfix_verbose <<- F
}
bigplotfix_verbose=F
downsample_xy = function(xy, n, xlog=F) {
msg=if(bigplotfix_verbose) { message } else { function(...) { NULL } }
msg("Finding range");
r=range(xy$x);
msg("Finding breaks");
if(xlog) {
breaks=exp(seq(from=log(r[1]),to=log(r[2]),length.out=n))
} else {
breaks=seq(from=r[1],to=r[2],length.out=n)
}
msg("Calling findInterval");
## cuts=cut(xy$x,breaks);
# findInterval is much faster than cuts!
cuts = findInterval(xy$x,breaks);
if(0) {
msg("In aggregate 1");
dmax = aggregate(list(x=xy$x, y=xy$y), by=list(cuts=cuts), max)
dmax$cuts = NULL;
msg("In aggregate 2");
dmin = aggregate(list(x=xy$x, y=xy$y), by=list(cuts=cuts), min)
dmin$cuts = NULL;
} else { # use data.table for MUCH faster aggregates
# (see http://stackoverflow.com/questions/7722493/how-does-one-aggregate-and-summarize-data-quickly)
suppressMessages(library(data.table))
msg("In data.table");
dt = data.table(x=xy$x,y=xy$y,cuts=cuts)
msg("In data.table aggregate 1");
dmax = dt[,list(x=max(x),y=max(y)),keyby="cuts"]
dmax$cuts=NULL;
msg("In data.table aggregate 2");
dmin = dt[,list(x=min(x),y=min(y)),keyby="cuts"]
dmin$cuts=NULL;
# ans = data_t[,list(A = sum(count), B = mean(count)), by = 'PID,Time,Site']
}
msg("In rep, rbind");
# interleave rows (copied from a SO answer)
s <- rep(1:n, each = 2) + (0:1) * n
xy = rbind(dmin,dmax)[s,];
xy
}
library(graphics);
# make sure we don't create infinite recursion if someone sources
# this file twice
if(!exists("old_plot.xy")) {
old_plot.xy = graphics::plot.xy
}
bigplotfix_maxlen = 1e4
# formals copied from graphics::plot.xy
my_plot.xy = function(xy, type, pch = par("pch"), lty = par("lty"),
col = par("col"), bg = NA, cex = 1, lwd = par("lwd"),
...) {
if(bigplotfix_verbose) {
message("In bigplotfix's plot.xy\n");
}
mycall=match.call();
len=length(xy$x)
if(len>bigplotfix_maxlen) {
warning("bigplotfix.R (plot.xy): too many points (",len,"), compressing to ",bigplotfix_maxlen,"\n");
xy = downsample_xy(xy, bigplotfix_maxlen, xlog=par("xlog"));
mycall$xy=xy
}
mycall[[1]]=as.symbol("old_plot.xy");
eval(mycall,envir=parent.frame());
}
# new binding solution adapted from Henrik Bengtsson
# https://stat.ethz.ch/pipermail/r-help/2008-August/171217.html
rebindPackageVar = function(pkg, name, new) {
# assignInNamespace() no longer works here, thanks nannies
ns=asNamespace(pkg)
unlockBinding(name,ns)
assign(name,new,envir=asNamespace(pkg),inherits=F)
assign(name,new,envir=globalenv())
lockBinding(name,ns)
}
rebindPackageVar("graphics", "plot.xy", my_plot.xy);
也许我会因为自己的方法而回避,对我的一位研究教授的糟糕记忆大喊大叫,因为他们通过将它们转换为类别来扔掉好的数据(当然,我现在已经同意了,大声笑),不知道。无论如何,如果您正在谈论散点图,那么我也遇到了同样的问题。现在,当我拥有数值数据时,对我进行分类以进行分析没有多大意义。但是可视化是另外一个故事。我发现最适合我的方法是:首先(1)使用cut函数将自变量分成几组。您可以计算组的数量,然后(2)只是简单地将DV与IV的剪切版本作图。R将生成箱形图,而不是该令人讨厌的散点图。我确实建议从绘图中删除异常值(使用plot命令中的outline = FALSE选项)。同样,我永远也不会通过分类和分析来浪费完美的数值数据。这样做有太多问题。尽管我知道这是一个棘手的辩论主题。但这是专门为至少从数据中获得视觉效果的目的而进行的,对我而言,危害不大。我已经绘制了高达10M的数据,但仍然可以从这种方法中理解数据。希望有帮助!最好的祝福!我已经看到了。我已经绘制了高达10M的数据,但仍然可以从这种方法中理解数据。希望有帮助!最好的祝福!我已经看到了。我已经绘制了高达10M的数据,但仍然可以从这种方法中理解数据。希望有帮助!最好的祝福!
对于较大的时间序列,我已经喜欢上smoothScatter(基本R的一部分)。我经常必须包含一些其他数据,并且保留基本的绘图API确实很有帮助,例如:
set.seed(1)
ra <- rnorm(n = 100000, sd = 1, mean = 0)
smoothScatter(ra)
abline(v=25000, col=2)
text(25000, 0, "Event 1", col=2)
给您(如果您原谅设计):
它始终可用,并且可以与庞大的数据集一起很好地工作,因此至少可以看看您所拥有的东西真是太好了。