如何在 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

如您所见,

  1. 我正在尝试调整 annotation_custom 中的 xmin 和 xmax。有没有一种方法可以让 'cyan' 颜色的绘图完全适合背景图像的 'width'?我不介意图表是否更薄并且未显示 X 轴。事实上,当我使用 gridExtra 包 assemble 与许多其他地块一起绘制时,这就是我所做的。

  2. 我想在显示的图像顶部显示起始深度 9195,在图像底部显示结束深度 9197。然后我不需要 Y 轴。我知道如何抑制 X 轴和 Y 轴标签的显示。所以这不是问题。我打开它们以进行澄清。可以通过编程方式完成吗?

  3. 如您所见,沿 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。