将绘图对象存储在列表中
Posted
技术标签:
【中文标题】将绘图对象存储在列表中【英文标题】:Storing plot objects in a list 【发布时间】:2010-12-21 16:36:57 【问题描述】:我昨天向this 询问了有关在对象中存储绘图的问题。我尝试实施第一种方法(意识到我没有在原始问题中指定我使用的是qplot()
)并注意到它没有按预期工作。
library(ggplot2) # add ggplot2
string = "C:/example.pdf" # Setup pdf
pdf(string,height=6,width=9)
x_range <- range(1,50) # Specify Range
# Create a list to hold the plot objects.
pltList <- list()
pltList[]
for(i in 1 : 16)
# Organise data
y = (1:50) * i * 1000 # Get y col
x = (1:50) # get x col
y = log(y) # Use natural log
# Regression
lm.0 = lm(formula = y ~ x) # make linear model
inter = summary(lm.0)$coefficients[1,1] # Get intercept
slop = summary(lm.0)$coefficients[2,1] # Get slope
# Make plot name
pltName <- paste( 'a', i, sep = '' )
# make plot object
p <- qplot(
x, y,
xlab = "Radius [km]",
ylab = "Services [log]",
xlim = x_range,
main = paste("Sample",i)
) + geom_abline(intercept = inter, slope = slop, colour = "red", size = 1)
print(p)
pltList[[pltName]] = p
# close the PDF file
dev.off()
在这种情况下,我使用了示例编号,因此如果只是复制代码,它就会运行。我确实花了几个小时对此感到困惑,但我无法弄清楚出了什么问题。它可以毫无问题地写入第一组 pdf,因此我有 16 个带有正确绘图的 pdf。
那么当我使用这段代码时:
string = "C:/test_tabloid.pdf"
pdf(string, height = 11, width = 17)
grid.newpage()
pushViewport( viewport( layout = grid.layout(3, 3) ) )
vplayout <- function(x, y)viewport(layout.pos.row = x, layout.pos.col = y)
counter = 1
# Page 1
for (i in 1:3)
for (j in 1:3)
pltName <- paste( 'a', counter, sep = '' )
print( pltList[[pltName]], vp = vplayout(i,j) )
counter = counter + 1
dev.off()
我得到的结果是每个图表上的最后一个线性模型线 (abline
),但数据没有改变。当我检查我的情节列表时,似乎所有情节都被最近的情节所覆盖(abline
对象除外)。
一个不太重要的次要问题是如何生成一个多页 pdf,每页上都有多个绘图,但我的代码的主要目标是将绘图存储在一个列表中,以便以后访问。
【问题讨论】:
【参考方案1】:好的,如果你的绘图命令改为
p <- qplot(data = data.frame(x = x, y = y),
x, y,
xlab = "Radius [km]",
ylab = "Services [log]",
xlim = x_range,
ylim = c(0,10),
main = paste("Sample",i)
) + geom_abline(intercept = inter, slope = slop, colour = "red", size = 1)
然后一切都按预期工作。这就是我怀疑正在发生的事情(尽管哈德利可能会澄清一些事情)。当 ggplot2 “保存”数据时,它实际上所做的是保存数据框和参数名称。所以对于我给出的命令,你会得到 p>
> summary(pltList[["a1"]])
data: x, y [50x2]
mapping: x = x, y = y
scales: x, y
faceting: facet_grid(. ~ ., FALSE)
-----------------------------------
geom_point:
stat_identity:
position_identity: (width = NULL, height = NULL)
mapping: group = 1
geom_abline: colour = red, size = 1
stat_abline: intercept = 2.55595281266726, slope = 0.05543539319091
position_identity: (width = NULL, height = NULL)
但是,如果您未在 qplot 中指定 data
参数,则所有变量都会在当前范围内进行评估,因为没有附加(读取:已保存)数据框。
data: [0x0]
mapping: x = x, y = y
scales: x, y
faceting: facet_grid(. ~ ., FALSE)
-----------------------------------
geom_point:
stat_identity:
position_identity: (width = NULL, height = NULL)
mapping: group = 1
geom_abline: colour = red, size = 1
stat_abline: intercept = 2.55595281266726, slope = 0.05543539319091
position_identity: (width = NULL, height = NULL)
因此,当第二次生成绘图时,它不使用原始值,而是使用x
和y
的当前 值。
【讨论】:
感谢 RCS 和 Jonathan,这解决了问题。我不知道 data 参数以及如何使用它来存储数据。我现在正在检查这本书的那个部分。【参考方案2】:我认为您应该在qplot
中使用data
参数,即将您的向量存储在数据框中。
参见 Hadley 的书,第 4.4 节:
对数据的限制很简单:必须是数据框。这是限制性的,与 R 中的其他图形包不同。Lattice 函数可以采用可选的数据框或直接从全局环境中使用向量。 ...
数据作为副本存储在绘图对象中,而不是参考。这有两个 重要后果:如果您的数据发生变化,情节将不会发生变化;和 ggplot2 对象是完全独立的,因此可以将它们保存()到磁盘,然后加载()并绘制,而不需要该会话中的任何其他内容。
【讨论】:
我遇到了类似 OP 的问题。我正在使用data.table
s,并在我的循环中添加setDF(data)
解决了我的特殊情况。 (有趣的是,copy(data)
不起作用。)您对 ggplot 如何与数据交互的引用让我找到了解决方案。【参考方案3】:
您的代码中有一个关于列表下标的错误。应该是
pltList[[pltName]]
不是
pltList[pltName]
注意:
class(pltList[1])
[1] "list"
pltList[1] 是一个 list,其中包含 pltList 的第一个元素。
class(pltList[[1]])
[1] "ggplot"
pltList[[1]]是pltList的第一个元素。
【讨论】:
抱歉 - 我的粘贴内容有误。我没有完全理解语法之间的区别,并且一直在编辑它以查看区别。但是,如上所述,我的错误仍然存在。【参考方案4】:关于您的第二个问题:多页 pdf 很容易——请参阅 help(pdf)
:
onefile: logical: if true (the default) allow multiple figures in one
file. If false, generate a file with name containing the
page number for each page. Defaults to ‘TRUE’.
对于您的主要问题,我不明白您是要将 plot 输入 存储在列表中以供以后处理,还是 plot 输出。如果是后者,我不确定plot()
返回一个可以存储和检索的对象。
【讨论】:
我希望存储绘图输出。如果我存储绘图输入,是否包括该特定时间的 x 和 y 值? 当然。只需将所有函数参数等存储在列表中。这是非常标准的。但是您存储 plot output 的假设不是。绘图结果与设备相关,并且很可能与操作系统相关。只需写入一个文件,可能是位图,然后显示它。或者编写 GUI 风格的应用程序。或者只是打开多个绘图窗口。 但是,ggplot
很可能会将对象返回给您。在这种情况下,爱德华多的答案就是你的关键。
ggplot 图形确实是通过创建一个规范来构建的,该规范是使用 print.ggplot() 方法转换为图形的。因此,您可以(方便地!)创建一个 ggplot 对象而不打印它,然后使用 ggsave() 直接将其保存到 PDF。或者使用 save() 来保存数据结构。【参考方案5】:
关于您的第二个问题的另一个建议是使用 Sweave 或 Brew,因为它们可以让您完全控制如何显示多页 pdf。
看看at this related question。
【讨论】:
以上是关于将绘图对象存储在列表中的主要内容,如果未能解决你的问题,请参考以下文章