如何在 R 和 ggplot2 中将绘图拟合到背景图像上
how to fit the plot over a background image in R and ggplot2
我正在尝试调整显示在背景图像上的绘图。由于清晰度的损失,我无法过度拉伸图像。因此,我必须将绘图放在比绘图薄得多的背景图像上。我不知道怎么做。请看附图:
这是示例 R 代码:
library(ggplot2)
library(readxl)
library(jpeg)
library(grid)
# find the ".jpg" image files and parse them to get the depth ranges for each image
setwd('~/R/Image_Example')
image_file <- "C1_9195-9197.jpg"
# read in the image file
img <- readJPEG(image_file)
g <- rasterGrob(img, interpolate = FALSE)
# read in the CT data
df_ct <- read_excel("CT_Doris25_short.xlsx", col_names = FALSE)
g_ct <- ggplot(data=df_ct) +
annotation_custom(g, xmin=min(df_ct$X1), xmax=max(df_ct$X1), ymin=-Inf, ymax=Inf) +
geom_path(aes_string(x=df_ct$X1, y=df_ct$X0), color='cyan') +
scale_y_reverse() +
theme(plot.margin = unit(c(0,0,0,0), "lines"))
g_ct
如您所见,
我正在尝试调整 annotation_custom 中的 xmin 和 xmax。有没有一种方法可以让 'cyan' 颜色的绘图完全适合背景图像的 'width'?我不介意图表是否更薄并且未显示 X 轴。事实上,当我使用 gridExtra 包 assemble 与许多其他地块一起绘制时,这就是我所做的。
我想在显示的图像顶部显示起始深度 9195,在图像底部显示结束深度 9197。然后我不需要 Y 轴。我知道如何抑制 X 轴和 Y 轴标签的显示。所以这不是问题。我打开它们以进行澄清。可以通过编程方式完成吗?
如您所见,沿 Y 轴的刻度以 0.5 为步长变化,即 9195、9195.5、9196 等。我想让它们以 0.1 而不是 0.5 的步长上升(或下降)。另外,我不想显示 Y 轴标签,只显示刻度线。图像顶部(9195)和底部(9197)的深度足够。
所以它看起来应该类似于下图所示:
请无视左边的彩图,那是一个单独的图,我不能去掉,否则无法显示'ticks'。它是使用 MatLab 完成的。我正在尝试用 R 图替换 MatLab 图。 Matlab 使用的是 TIFF 图像,它更重但也更清晰。我要使用可接受的 JPEG。
感谢您的宝贵时间。
您可以将 rasterGrob
中的宽度和高度参数都设置为 1 "npc",这将强制图像填充绘图区域。然后在保存图像时指定图像的高度和宽度以获得您想要的纵横比。主题和 scale_y_reverse 选项可用于控制轴的外观,如下所示。请注意,我们还可以使用 expand
参数来确保坐标轴不会比图像或数据延伸得更远。
g <- rasterGrob(img, width=unit(1,"npc"), height=unit(1,"npc"), interpolate = FALSE)
g_ct <- ggplot(data=df_ct) +
annotation_custom(g, -Inf, Inf, -Inf, Inf) +
geom_path(aes_string(x=df_ct$X1, y=df_ct$X0), color='red', size=1) +
scale_y_reverse("",
labels = c(min(df_ct$X0), rep("", length(seq(min(df_ct$X0), max(df_ct$X0), 5))-2),max(df_ct$X0)),
breaks = seq(min(df_ct$X0), max(df_ct$X0), 5),
expand = c(0,0)) +
theme(plot.margin = unit(c(5,5,5,5), "mm"),
axis.line.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
axis.line.y = element_blank(),
axis.ticks.y = element_line(size = 1),
axis.ticks.length = unit(5,'mm')) +
scale_x_continuous("")
g_ct
ggsave('test.png', height=5, width = 2, units = 'in')
一些数据:
df_ct <- data.frame(X0 = 0:100)
df_ct$X1 = sin(df_ct$X0) +rnorm(101)
和一张背景图片:
https://i.stack.imgur.com/aEG7I.jpg
@dww 对答案的补充。
如果您需要将图像恰好覆盖(或更确切地说“置于”下方)在数据点上,那么而不是
annotation_custom(g, -Inf, Inf, -Inf, Inf)
使用
annotation_custom(g, minX, maxX, minY, maxY)
minX..maxY 是数据上图像角所在位置的左下角到右上角。
然后您还可以使用 xlim(), ylim()
自由缩放您的数据,而不会丢失图像-数据位置关系。
示例(每个 this SO 问题的图片下载)
download.file("https://upload.wikimedia.org/wikipedia/commons/b/b9/Sinusoidal_projection_SW.jpg",
destfile="tmp.jpg", mode="wb")
world_image <- jpeg::readJPEG("tmp.jpg")
ggplot(FileWellsUsed, aes(y=Decimal.Latitude)) +
annotation_custom(rasterGrob(world_image,
width = unit(1,"npc"),
height = unit(1,"npc")),
-180, 180, -90, 90)+
ggtitle("Sinusoidal projection") +
xlim(c(-180,180)) +ylim(c(-60,75))+
coord_fixed() +
...yourdata.....
另请参阅 this 问题,该问题使用 rasterGrid 而不是 rasterGrob。
我正在尝试调整显示在背景图像上的绘图。由于清晰度的损失,我无法过度拉伸图像。因此,我必须将绘图放在比绘图薄得多的背景图像上。我不知道怎么做。请看附图:
这是示例 R 代码:
library(ggplot2)
library(readxl)
library(jpeg)
library(grid)
# find the ".jpg" image files and parse them to get the depth ranges for each image
setwd('~/R/Image_Example')
image_file <- "C1_9195-9197.jpg"
# read in the image file
img <- readJPEG(image_file)
g <- rasterGrob(img, interpolate = FALSE)
# read in the CT data
df_ct <- read_excel("CT_Doris25_short.xlsx", col_names = FALSE)
g_ct <- ggplot(data=df_ct) +
annotation_custom(g, xmin=min(df_ct$X1), xmax=max(df_ct$X1), ymin=-Inf, ymax=Inf) +
geom_path(aes_string(x=df_ct$X1, y=df_ct$X0), color='cyan') +
scale_y_reverse() +
theme(plot.margin = unit(c(0,0,0,0), "lines"))
g_ct
如您所见,
我正在尝试调整 annotation_custom 中的 xmin 和 xmax。有没有一种方法可以让 'cyan' 颜色的绘图完全适合背景图像的 'width'?我不介意图表是否更薄并且未显示 X 轴。事实上,当我使用 gridExtra 包 assemble 与许多其他地块一起绘制时,这就是我所做的。
我想在显示的图像顶部显示起始深度 9195,在图像底部显示结束深度 9197。然后我不需要 Y 轴。我知道如何抑制 X 轴和 Y 轴标签的显示。所以这不是问题。我打开它们以进行澄清。可以通过编程方式完成吗?
如您所见,沿 Y 轴的刻度以 0.5 为步长变化,即 9195、9195.5、9196 等。我想让它们以 0.1 而不是 0.5 的步长上升(或下降)。另外,我不想显示 Y 轴标签,只显示刻度线。图像顶部(9195)和底部(9197)的深度足够。
所以它看起来应该类似于下图所示:
请无视左边的彩图,那是一个单独的图,我不能去掉,否则无法显示'ticks'。它是使用 MatLab 完成的。我正在尝试用 R 图替换 MatLab 图。 Matlab 使用的是 TIFF 图像,它更重但也更清晰。我要使用可接受的 JPEG。
感谢您的宝贵时间。
您可以将 rasterGrob
中的宽度和高度参数都设置为 1 "npc",这将强制图像填充绘图区域。然后在保存图像时指定图像的高度和宽度以获得您想要的纵横比。主题和 scale_y_reverse 选项可用于控制轴的外观,如下所示。请注意,我们还可以使用 expand
参数来确保坐标轴不会比图像或数据延伸得更远。
g <- rasterGrob(img, width=unit(1,"npc"), height=unit(1,"npc"), interpolate = FALSE)
g_ct <- ggplot(data=df_ct) +
annotation_custom(g, -Inf, Inf, -Inf, Inf) +
geom_path(aes_string(x=df_ct$X1, y=df_ct$X0), color='red', size=1) +
scale_y_reverse("",
labels = c(min(df_ct$X0), rep("", length(seq(min(df_ct$X0), max(df_ct$X0), 5))-2),max(df_ct$X0)),
breaks = seq(min(df_ct$X0), max(df_ct$X0), 5),
expand = c(0,0)) +
theme(plot.margin = unit(c(5,5,5,5), "mm"),
axis.line.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
axis.line.y = element_blank(),
axis.ticks.y = element_line(size = 1),
axis.ticks.length = unit(5,'mm')) +
scale_x_continuous("")
g_ct
ggsave('test.png', height=5, width = 2, units = 'in')
一些数据:
df_ct <- data.frame(X0 = 0:100)
df_ct$X1 = sin(df_ct$X0) +rnorm(101)
和一张背景图片:
https://i.stack.imgur.com/aEG7I.jpg
@dww 对答案的补充。
如果您需要将图像恰好覆盖(或更确切地说“置于”下方)在数据点上,那么而不是
annotation_custom(g, -Inf, Inf, -Inf, Inf)
使用
annotation_custom(g, minX, maxX, minY, maxY)
minX..maxY 是数据上图像角所在位置的左下角到右上角。
然后您还可以使用 xlim(), ylim()
自由缩放您的数据,而不会丢失图像-数据位置关系。
示例(每个 this SO 问题的图片下载)
download.file("https://upload.wikimedia.org/wikipedia/commons/b/b9/Sinusoidal_projection_SW.jpg",
destfile="tmp.jpg", mode="wb")
world_image <- jpeg::readJPEG("tmp.jpg")
ggplot(FileWellsUsed, aes(y=Decimal.Latitude)) +
annotation_custom(rasterGrob(world_image,
width = unit(1,"npc"),
height = unit(1,"npc")),
-180, 180, -90, 90)+
ggtitle("Sinusoidal projection") +
xlim(c(-180,180)) +ylim(c(-60,75))+
coord_fixed() +
...yourdata.....
另请参阅 this 问题,该问题使用 rasterGrid 而不是 rasterGrob。