Cropping a plot in a non-rectangular way.

Hi. Suppose I have a plot that is a square containing four colors. Then I inscribe a square that is rotated 45 degrees so that the inscribed square contains those four colors. I want to crop the plot to only plot the inscribed square, with the colors maintained in the same order. I have accomplished this in the following code, but I did this by explicitly describing the colors, so the second plot is not really a crop. Is there a way to do this as more of a crop? In practice I want the original square to be an image, and I want to crop it at four specific points. # rectangle syntax: rect(xleft, ybottom, xright, ytop)
plot(x = c(0, 500), y = c(0, 500), type= "n", xlab = "", ylab = "")

outer square

rect(0, 0, 250, 250, col = "#E41A1C", border = "blue") # bottom left square
rect(250, 0, 500, 250, col = "yellow", border = "blue") # bottom right square
rect(0, 250, 250, 500, col = "cornsilk", border = "blue") # top left square
rect(250, 250, 500, 500, col = "cyan", border = "blue") # top right square

inscribed square

lines(c(0, 250), c(250, 500), col = "black", lwd = 2) # top left diagonal
lines(c(250, 500), c(500, 250), col = "black", lwd = 2) # top right diagonal
lines(c(500, 250), c(250, 0), col = "black", lwd = 2) # bottom right diagonal
lines(c(250, 0), c(0, 250), col = "black", lwd = 2) # bottom left diagonal

cropped inscribed square

plot(x = c(0, 500), y = c(0, 500), type= "n", xlab = "", ylab = "")
polygon(x = c(0, 250, 250, 0), y = c(250, 500, 250, 250), col ="cornsilk")
polygon(x = c(250, 500, 250, 250), y = c(500, 250, 250, 500), col = "cyan")
polygon(x = c(0, 250, 250, 0), y = c(250, 250, 0, 250), col = "#E41A1C")
polygon(x = c(250, 250, 500, 250), y = c(0, 250, 250, 0), col = "yellow")

To import and crop an actual image I would recommend to use the functions image_crop and image_rotate from the magick package.

To achieve a crop similar to your example without an external package, I would recommend to simply cover the crop region using the function polygon and the background color.

my idea would be to do an image mask

library(magick)

png(filename = "base.png",width = 500,height = 500)
par(mar = c(0, 0, 0, 0), oma = c(0, 0, 0, 0)) # Set margins and outer margins to zero
plot.new()
plot.window(xlim = c(0, 500), ylim = c(0, 500), xaxs = "i", yaxs = "i") # Use 'i' to remove axis space
par(mar = c(0, 0, 0, 0)) # Set margins to zero
rect(0, 0, 250, 250, col = "#E41A1C", border = "blue") # bottom left square
rect(250, 0, 500, 250, col = "yellow", border = "blue") # bottom right square
rect(0, 250, 250, 500, col = "cornsilk", border = "blue") # top left square
rect(250, 250, 500, 500, col = "cyan", border = "blue") # top right square
dev.off()



img <-  magick::image_read(path = "base.png") 

fig <- image_draw(image_blank(500, 500))
polygon(c(0,250,500,250), c(250,500,250,0), col = "black", border = "black")
dev.off()

im2 <- image_composite(img, fig, operator = 'copyopacity') |>
  image_background('white')

magick::image_write(image=im2,
                    path="mycroppedimage.png")

so first the image is made :
base
then a mask for clipping is made :
mask
the result of using the one on the other is
mycroppedimage

nirgrahamuk, this works, thank you. Would you please explain why it works. How does composing a black image on to of the original image achieve the desired effect?

Also, is it necessary that images be saved to the computer and read back into R for this to work?

Image masking of this kind is a long standing staple of computer graphics and digital photo editing in general(i.e. photoshop supports it). Its an industry convention that for a mask black is transparent and white is opaque/not transparent.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.