首页 > 解决方案 > 了解 R 如何将图分配为对象

问题描述

我在这里看到很多与我的问题无关的帖子,但并没有达到目标。抱歉,如果我错过了其他地方的解决方案。

我注意到 R 似乎将不同类型的图分配为不同类型的对象或 NULL,但我不知道为什么。你能帮我解开这个吗?目标是简单地将绘图保存为一个可以稍后在各种降价文件中显示的对象,但我不需要任何比基本打印更复杂的东西——没有格子等。

例如

# Toy data setup 
set.seed(63)
d <- rnorm(100)

单独调用对象时不显示基本直方图,但在包装在 plot() 函数中时会显示。

hist(d)       # works as expected
p1 <- hist(d) # saves as a "List of 6" with class "histogram"
p1; print(p1) # both print all data in the list but no histogram plot
plot(p1)      # shows histogram plot

使用 plot 函数的变化保存为 NULL

plot(d, type="h") # works as expected
p2 <- plot(d) # saves as "NULL (empty)"
p2; print(p2) # both print NULL as expected given how it saved
plot(p2)      # generates error message, as expected

ggplot 方法也可以按预期保存和工作

library(tidyverse)
ggplot() +aes(d) + geom_histogram()  # works as expected with message info
p3 <- ggplot() +aes(d) + geom_histogram()  # saves as "List of 9" with class "gg" and "ggplot"
p3  # shows histogram as expected

因此,有 3 种不同的方式来显示基本的直方图(类似)图,并且在尝试将图分配为稍后调用的对象时,它们的行为都不同。即使 hist() 和 ggplot() 保存为对象,在调用时也会显示不同,即使它们都保存为列表。

我错过了什么?

为了让事情变得更复杂一点,我注意到如果我将图(如下面的直方图)重叠成一个图,则分配的对象不包含两个图。我可以看到这对于保存拟合线、添加的点或文本等也很有用。

我需要做什么才能将绘图添加保存到绘图对象?以下示例代码来自R Bloggers

#Random numbers
h2<-rnorm(1000,4)
h1<-rnorm(1000,6)
# Histogram Colored (blue and red)
hist(h1, col=rgb(1,0,0,0.5),xlim=c(0,10), ylim=c(0,200), main="Overlapping Histogram", xlab="Variable")
hist(h2, col=rgb(0,0,1,0.5), add=T)

他们按预期工作。但是,如果我在将第一个分配给对象后用分号将它们连接起来,则第一个直方图修改消失并且重叠直方图丢失。重叠直方图消失是有道理的,因为第二个命令实际上并未应用于保存的直方图对象,但我很好奇如何添加它。

标签: robjectggplot2plotassign

解决方案


具有创建图形绘图副作用的函数可能会或可能不会返回某些内容。例如,使用该ggplot2包,它会返回一个复杂的列表结构,其中包含足够的信息和预定义的属性,以便 (1)print生成图形对象 (“grob”),或者 (2) 可以添加更多层或属性更改为此列表结构。举个例子,

library(ggplot2)
gg <- ggplot(mtcars, aes(mpg,disp)) + geom_point()
str(gg, max.level=1)
# List of 9
#  $ data       :'data.frame':  32 obs. of  11 variables:
#  $ layers     :List of 1
#  $ scales     :Classes 'ScalesList', 'ggproto', 'gg' <ggproto object: Class ScalesList, gg>
#     add: function
#     clone: function
#     find: function
#     get_scales: function
#     has_scale: function
#     input: function
#     n: function
#     non_position_scales: function
#     scales: list
#     super:  <ggproto object: Class ScalesList, gg> 
#  $ mapping    :List of 2
#   ..- attr(*, "class")= chr "uneval"
#  $ theme      : list()
#  $ coordinates:Classes 'CoordCartesian', 'Coord', 'ggproto', 'gg' <ggproto object: Class CoordCartesian, Coord, gg>
#     aspect: function
#     backtransform_range: function
#     clip: on
#     default: TRUE
#     distance: function
#     expand: TRUE
#     is_free: function
#     is_linear: function
#     labels: function
#     limits: list
#     modify_scales: function
#     range: function
#     render_axis_h: function
#     render_axis_v: function
#     render_bg: function
#     render_fg: function
#     setup_data: function
#     setup_layout: function
#     setup_panel_params: function
#     setup_params: function
#     transform: function
#     super:  <ggproto object: Class CoordCartesian, Coord, gg> 
#  $ facet      :Classes 'FacetNull', 'Facet', 'ggproto', 'gg' <ggproto object: Class FacetNull, Facet, gg>
#     compute_layout: function
#     draw_back: function
#     draw_front: function
#     draw_labels: function
#     draw_panels: function
#     finish_data: function
#     init_scales: function
#     map_data: function
#     params: list
#     setup_data: function
#     setup_params: function
#     shrink: TRUE
#     train_scales: function
#     vars: function
#     super:  <ggproto object: Class FacetNull, Facet, gg> 
#  $ plot_env   :<environment: R_GlobalEnv> 
#  $ labels     :List of 2
#  - attr(*, "class")= chr [1:2] "gg" "ggplot"

“只是一个list。”

非网格图形函数有时采用类似的策略。例如,hist总是返回一个命名的list; 如果您使用 default plot=TRUE,那么它会不可见地返回此列表,并且一个副作用是创建绘图。hist(..., plot=FALSE)但是,使用时,list会明显返回,并且不会创建任何图。与(和朋友)ggplot2的 S3 方法类似,有一个用于返回对象(类)的 S3 方法,命名为,所以如果你这样做printggplot2:::print.ggplot2histhistogramgraphics:::plot.histogram

h <- hist(mtcars$disp, plot = FALSE)
str(h)
# List of 6
#  $ breaks  : int [1:10] 50 100 150 200 250 300 350 400 450 500
#  $ counts  : int [1:9] 5 7 4 1 4 4 4 1 2
#  $ density : num [1:9] 0.003125 0.004375 0.0025 0.000625 0.0025 ...
#  $ mids    : num [1:9] 75 125 175 225 275 325 375 425 475
#  $ xname   : chr "mtcars$disp"
#  $ equidist: logi TRUE
#  - attr(*, "class")= chr "histogram"

然后一个简单的plot(h)将生成情节。(即使您第一次使用默认值绘制它h <- hist(..., plot=TRUE),您也可以稍后使用 重新生成该图plot(h)。)

但并非所有绘图功能或其附属功能都会返回一些东西。lines并且points,例如,总是返回NULL。您不能“捕获”输出lines并在以后(重新)应用它。

但据我所知,没有基本的 R 函数“返回”绘图对象。grid函数可能,特别是那些修改 grobs 的函数。

如果您想“保存”绘图本身(而不是list用于创建它的组件),请查看?recordPlot,它可以在任何基本图形功能(包括辅助功能 、 等)之后立即lines运行points


推荐阅读