I'm trying to plot a graph of a linear profile with integrated pictures of drilling cores at certain points and hights in the profile. I have a directory with 22 .png images of the drilling cores, each has a length of 1 m, and a .csv file with the x and z (z_korrig in .csv file) positions of the top center of each image. Since I'm a novice when it comes to R, I'm stuck at the point where I assign the coordinates to the raster images and actually integrate them into the plot.

Here is my code so far with the output scatter plot:

#import coordinates
coord <- read.csv("Bohrungen Höhe.csv", sep = ";", header = TRUE)

#plot to check csv
plot(coord$x, coord$z_korrig, 
     xlab = "length in m",
     ylab = "heigth in m",
     main = "profile 1")

enter image description here

The raster images should be positioned with their top center at the points in the scatter plot (images have the names B01.png..., corresponding to the ID with the coordinates in the .csv file), showing the actual profile. I also feel like it would be beneficial for visualisation to double the width of the images.

This is the content of my .csv file:

    ID   x    z z_korrig
1  B01 100 4.77     3.32
2  B02 110 4.83     3.38
3  B03 120 4.96     3.51
4  B04 130 5.28     3.83
5  B05  80 4.69     3.24
6  B06 140 5.69     4.24
7  B07 150 6.03     4.58
8  B08 160 6.25     4.80
9  B09 170 6.38     4.93
10 B10 180 6.48     5.03
11 B11 190 6.64     5.19
12 B12 200 6.82     5.37
13 B13 210 6.97     5.52
14 B14  70 4.81     3.36
15 B15  60 4.94     3.49
16 B16  50 5.05     3.60
17 B17  40 5.19     3.74
18 B18  30 5.33     3.88
19 B19  20 5.46     4.01
20 B20  10 5.82     4.37
21 B21   0 5.65     4.20
22 B22  90 4.72     3.27

EDIT: This is what I was hoping to achive: enter image description here

  • Why does this need to be done in R? Of course there is a way to do this in base plot or ggplot2 but, the "right tool for the right job". The required code and fiddling outweights the benefits of doing this in R. Simply, export as image files (eg., jpeg) and then simply use a photo editor to do what you are after. I do all of my publication graphics in graphic design software. Aside what comes with windows there are plenty of free and powerful graphic and photo editing software out there (GIMP, Pixlr, Paint.NET, Krita, ...). Jul 20, 2022 at 15:10
  • @JeffreyEvans I have used GIMP to scale/cut my images beforehand but got stuck when I tried to design a graph that is actually true to the measurements. That's why I tried to combine the two. You don't have a link to a tutorial on how to do this in a gaphics design software like GIMP, by any chance? Jul 20, 2022 at 15:16
  • As I understand it you want to take that plot you've shown in the Q and put 22 images on top of it? What is the size (pixels across/down) of the image? How are you going to fit them onto the plot so they don't overlap? The rasterImage function can put a PNG onto a base graphics plot.
    – Spacedman
    Jul 20, 2022 at 15:54
  • @Spacedman With help from a friend I've done it with a design software now. However, I would be curious, if this could be somehow automated. I was hoping, that it would be possible to size the images according to the scale of the graph (they are 1 m long each). I'll add an image of the profile we've done with inkscape to better illustrate what I'm trying to do. Jul 20, 2022 at 23:17

1 Answer 1


I'll do an example for six images. Test data created like this:

set.seed(1234) # fix random numbers
d = data.frame(ID=paste0("B0",1:6))
d$x = sample(1:6) *10
d$z = runif(6, 4, 7)

> head(d)
   ID  x        z
1 B01 40 4.697652
2 B02 20 5.998251
3 B03 50 5.542753
4 B04 10 6.080774
5 B05 60 5.634925
6 B06 30 4.848201

Then assuming files B01.png to B06.png exist in the current directory, read them into a list object as arrays:

ims = lapply(d$ID, function(ID){readPNG(paste0(ID,".png"))})
names(ims) <- d$ID

We want the images to be this many units wide and this many units high, on the scale of the data:

w = 4
h = 1

Our plot needs a bit of extra width either side of the data points:

xmin = min(d$x) - w
xmax = max(d$x) + w

And needs to extend above the images. At this point I realise I've put the images with their bottom on the data point, but I'll leave it as an exercise for you to change things so they align with the top.

ymin = min(d$z)
ymax = max(d$z) + h

Now I can set up a blank plot with that range:

plot(d$x, d$z, xlim=c(xmin, xmax), ylim=c(ymin, ymax), type="n")

And loop over the rows of the data putting the images down. You'll need to adjust this to get the images below the data point. Sorry, but working out how to do that might be insightful:

for(n in 1:nrow(d)){
    xl = d$x[n]-w/2
    yl = d$z[n]
                xl, yl,
                xl+w, yl+h

Which gives:

enter image description here

You could also add the text label you've got at the top of the image with the text function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.