了解 R 如何将绘图分配为对象
Understanding how R assigns plots as objects
我在这里看到很多与我的问题无关的帖子,但没有完全切中要害。对不起,如果我错过了其他地方的解决方案。
我注意到 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)
它们按预期工作。但是,如果我在将第一个分配给对象后用分号连接它们,则第一个直方图修改消失并且重叠直方图丢失。重叠直方图消失是有道理的,因为第二个命令实际上并未应用于保存的直方图对象,但我很好奇如何添加它。
具有创建图表的副作用的函数可能会也可能不会 return 什么。例如,对于 ggplot2
包,它 return 是一个复杂的列表结构,具有足够的信息和预定义的属性,(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"
"Just a list
."
非网格图形函数有时采用类似的策略。例如,hist
总是 return 一个命名的 list
;如果您使用默认值 plot=TRUE
,那么它 return 这个列表 不可见 并且一个副作用是创建一个情节。然而,对于 hist(..., plot=FALSE)
,list
被明显地 return 编辑并且没有创建绘图。类似于 ggplot2
用于 print
(ggplot2:::print.ggplot2
和朋友)的 S3 方法,有一个用于 hist
的 return 对象的 S3 方法(class histogram
), 命名为 graphics:::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)
重新生成该图。)
但不是所有的绘图函数或它们的附属函数return。 lines
和 points
,例如,总是 return NULL
。您不能 "capture" 来自 lines
的输出并在以后(重新)应用它。
但据我所知,没有基础 R 函数 "returns" 绘图对象。 grid
函数可能,特别是那些修改 grobs 的函数。
如果你想 "save" 绘图本身(而不是 list
或用于创建它的组件),然后查看 ?recordPlot
,它可以是 运行 紧跟在任何基本图形函数之后(包括附属函数 lines
、points
等)。
我在这里看到很多与我的问题无关的帖子,但没有完全切中要害。对不起,如果我错过了其他地方的解决方案。
我注意到 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)
它们按预期工作。但是,如果我在将第一个分配给对象后用分号连接它们,则第一个直方图修改消失并且重叠直方图丢失。重叠直方图消失是有道理的,因为第二个命令实际上并未应用于保存的直方图对象,但我很好奇如何添加它。
具有创建图表的副作用的函数可能会也可能不会 return 什么。例如,对于 ggplot2
包,它 return 是一个复杂的列表结构,具有足够的信息和预定义的属性,(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"
"Just a list
."
非网格图形函数有时采用类似的策略。例如,hist
总是 return 一个命名的 list
;如果您使用默认值 plot=TRUE
,那么它 return 这个列表 不可见 并且一个副作用是创建一个情节。然而,对于 hist(..., plot=FALSE)
,list
被明显地 return 编辑并且没有创建绘图。类似于 ggplot2
用于 print
(ggplot2:::print.ggplot2
和朋友)的 S3 方法,有一个用于 hist
的 return 对象的 S3 方法(class histogram
), 命名为 graphics:::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)
重新生成该图。)
但不是所有的绘图函数或它们的附属函数return。 lines
和 points
,例如,总是 return NULL
。您不能 "capture" 来自 lines
的输出并在以后(重新)应用它。
但据我所知,没有基础 R 函数 "returns" 绘图对象。 grid
函数可能,特别是那些修改 grobs 的函数。
如果你想 "save" 绘图本身(而不是 list
或用于创建它的组件),然后查看 ?recordPlot
,它可以是 运行 紧跟在任何基本图形函数之后(包括附属函数 lines
、points
等)。