Reputation: 1475
I'm trying to build a visualisation with both drawn shapes (e.g. using geom_circle) and images. In both cases, I want to be able to position them on the page specifically with coordinates, rather than using one of the built in chart types.
See update further down...
However, I can either get the circles with the correct aspect ratio (i.e. round not oval) or the images, but not both. In the example below, you can see the image is not shown as square when it is.
I have tried various things including coord_fixed, scale_size_identity and coord_cartesian, but to no avail. The overall output will be landscape, which is why I have set the cartesian limits as I have.
This is a simplified version. In the full version, I'll get the coordinates from the data (which I'm fine with).
images <-data.frame(url = c("https://upload.wikimedia.org/wikipedia/commons/d/de/Windows_live_square.JPG"))
ggplot(mpg) +
ggforce::geom_circle(aes(x0 = displ * 50 - 60, y0 = hwy, r=cty)) +
#scale_size_identity() +
# Add Image
ggimage::geom_image(data = images,
aes(x = 4, y = 20, image=url),
size = 0.4,
hjust = 0.0,
by="height"
) +
coord_cartesian(
xlim = c(0, 120),
ylim = c(0, 80),
expand = FALSE,
clip = "on"
)
Update following really helpful input from @tjebo and further investigation.
I have now found there are at least 4 ways to add images to plots, each with their own advantages and disadvantages. I've listed these below to help others on this search.
Draw basic shapes to which images can be added
g <- ggplot(mpg) +
ggforce::geom_circle(aes(x0 = displ * 50 - 60, y0 = hwy, r=cty))
Plot with ggtexture - multiple images - aspect defined by x and y max - min
https://rdrr.io/github/clauswilke/ggtextures/man/geom_textured_rect.html
g + ggtextures::geom_textured_rect(data = images,
aes(xmin = 20, xmax = 60,
ymin = 20, ymax = 60, image = url),
lty = "blank", # line type of blank to remove border
fill="white", # used to fill transparent areas of image
nrow = 1,
ncol = 1,
img_width = unit(1, "null"),
img_height = unit(1, "null"),
position = "identity") +
coord_equal() # A fixed scale coordinate system forces a specified ratio between the physical representation of data units on the axes.
Plot with ggimage - multiple images - aspect defined by device
g + ggimage::geom_image(data = images,
aes(x = 20, y = 40, image=url),
size = 0.2,
by="height"
)
Plot with cowplot - single image - freedom over aspect
Independent drawing surface and scale (0-1)
cowplot::ggdraw(g) +
cowplot::draw_image(images[[1, "url"]],
x = .5, y = .3, width = 0.5, height = 0.5)
Plot with annotation_custom (ggplot) - original aspect
Seems to use widest of width of height and centre on mid coordinates
image <- magick::image_read(images[[1, "url"]])
rasterImg <- grid::rasterGrob(image, interpolate = FALSE)
g + annotation_custom(rasterImg, xmin = 00, xmax =200, ymin = 10, ymax = 50)
Upvotes: 1
Views: 1693
Reputation: 23767
I strongly feel you may have seen this thread: Can geom_image() from the ggimage package be made to preserve the image aspect ratio? - this was asked and answered by ggplot2 gurus such as Claus Wilke, Baptiste and Marco Sandri - it seems that ggimage is scaling to the device. Thus if you would like a square, you need to save to a device of square dimensions. Or, if you don't have a square image, of course, dimensions relative to your image used.
I used see::geom_point2
(no weird border), because I got the strong feeling that you have not used ggforce::geom_circle
. Also mild changes where I added the aes
call.
library(ggimage)
#> Loading required package: ggplot2
images <-data.frame(url = c("https://upload.wikimedia.org/wikipedia/commons/d/de/Windows_live_square.JPG"))
# g <-
ggplot(mpg) +
see::geom_point2(aes(x = displ, y = hwy, size = cty), alpha = 0.2) +
scale_size_identity() +
# Add Image
geom_image(data = images,
aes(x = 4, y = 20, image=url),
size = 0.4,
hjust = 0.0,
by = "height"
)
Using reprex, with both fig width and height set to 3 inches
Created on 2021-02-13 by the reprex package (v1.0.0)
Upvotes: 2
Reputation: 23767
A different approach would be to not use ggimage - e.g., use cowplot for custom annotation, makes it super simple to add an image.
library(ggplot2)
library(cowplot)
p <- ggplot(mpg) +
see::geom_point2(aes(x = displ, y = hwy, size = cty), alpha = 0.2) +
scale_size_identity()
ggdraw(p) +
draw_image("https://upload.wikimedia.org/wikipedia/commons/d/de/Windows_live_square.JPG",
x = .5, y = .3, width = 0.5, height = 0.5)
Created on 2021-02-13 by the reprex package (v1.0.0)
Or, use the ggtextures
package, with a little tweak of the coordinate system
this discussion seems relevant
library(ggtextures)
library(ggplot2)
library(tibble)
img_df <- tibble(
xmin = 1, ymin = 1, xmax = 4, ymax = 4,
image = "https://upload.wikimedia.org/wikipedia/commons/d/de/Windows_live_square.JPG"
)
ggplot(mpg) +
see::geom_point2(aes(x = displ, y = hwy, size = cty), alpha = 0.2) +
geom_textured_rect(data = img_df,
aes(xmin = xmin, xmax = xmax,
ymin = ymin, ymax = ymax, image = image),
nrow = 1,
ncol = 1,
img_width = unit(1, "null"),
img_height = unit(1, "null"),
position = "identity") +
coord_equal() # this is then necessary...
Created on 2021-02-13 by the reprex package (v1.0.0)
Upvotes: 1