Inserting an image to ggplot2 - r

Is it possible to insert a raster image or a pdf image underneath a geom_line() on a ggplot2 plot?
I wanted to be quickly able to plot data over a previously calculated plot that takes a long time to generate as it uses a large amount of data.
I read through this example. However, as it is over one year old I thought there might be a different way of doing this now.

try ?annotation_custom in ggplot2
example,
library(png)
library(grid)
img <- readPNG(system.file("img", "Rlogo.png", package="png"))
g <- rasterGrob(img, interpolate=TRUE)
qplot(1:10, 1:10, geom="blank") +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_point()

Could also use the cowplot R package (cowplot is a powerful extension of ggplot2). It will also need the magick package. Check this introduction to cowplot vignette.
Here is an example for both PNG and PDF background images.
library(ggplot2)
library(cowplot)
library(magick)
# Update 2020-04-15:
# As of version 1.0.0, cowplot does not change the default ggplot2 theme anymore.
# So, either we add theme_cowplot() when we build the graph
# (commented out in the example below),
# or we set theme_set(theme_cowplot()) at the beginning of our script:
theme_set(theme_cowplot())
my_plot <-
ggplot(data = iris,
mapping = aes(x = Sepal.Length,
fill = Species)) +
geom_density(alpha = 0.7) # +
# theme_cowplot()
# Example with PNG (for fun, the OP's avatar - I love the raccoon)
ggdraw() +
draw_image("https://i.stack.imgur.com/WDOo4.jpg?s=328&g=1") +
draw_plot(my_plot)
# Example with PDF
ggdraw() +
draw_image(file.path(R.home(), "doc", "html", "Rlogo.pdf")) +
draw_plot(my_plot)
Also, as #seabass20 asked in the comment below, we can also give a custom position and scale to the image. Below is an example inspired from help(draw_image). One needs to fine tune the parameters x, y, and scale until gets the desired output.
logo_file <- system.file("extdata", "logo.png", package = "cowplot")
my_plot_2 <- ggdraw() +
draw_image(logo_file, x = 0.3, y = 0.4, scale = .2) +
draw_plot(my_plot)
my_plot_2
Created on 2020-04-15 by the reprex package (v0.3.0)

Just adding an update from the terrific Magick package:
library(ggplot2)
library(magick)
library(here) # For making the script run without a wd
library(magrittr) # For piping the logo
# Make a simple plot and save it
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
ggtitle("Cars") +
ggsave(filename = paste0(here("/"), last_plot()$labels$title, ".png"),
width = 5, height = 4, dpi = 300)
# Call back the plot
plot <- image_read(paste0(here("/"), "Cars.png"))
# And bring in a logo
logo_raw <- image_read("http://hexb.in/hexagons/ggplot2.png")
# Scale down the logo and give it a border and annotation
# This is the cool part because you can do a lot to the image/logo before adding it
logo <- logo_raw %>%
image_scale("100") %>%
image_background("grey", flatten = TRUE) %>%
image_border("grey", "600x10") %>%
image_annotate("Powered By R", color = "white", size = 30,
location = "+10+50", gravity = "northeast")
# Stack them on top of each other
final_plot <- image_append(image_scale(c(plot, logo), "500"), stack = TRUE)
# And overwrite the plot without a logo
image_write(final_plot, paste0(here("/"), last_plot()$labels$title, ".png"))

Following up on #baptiste's answer, you don't need to load the grob package and convert the image if you use the more specific annotation function annotation_raster().
That quicker option could look like this:
# read picture
library(png)
img <- readPNG(system.file("img", "Rlogo.png", package = "png"))
# plot with picture as layer
library(ggplot2)
ggplot(mapping = aes(1:10, 1:10)) +
annotation_raster(img, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf) +
geom_point()
Created on 2021-02-16 by the reprex package (v1.0.0)

Related

Convert ggplot to greyscale with stat_summary

I have an R package as a back-end engine for a GUI (JASP). I want to be able to have people convert their images to greyscale (for publication printing). For most plots, I can use scale_colour_grey(), but that doesn't work when colors are specified within stats_summary. For example:
# simulate data
set.seed(1212)
y = rnorm(100)
g = sample(c("a", "b"), 100, T)
d = data.frame(y=y, g=g)
### create ggplot
plot = ggplot(data=d, aes(x=g, y=y)) +
geom_jitter() +
stat_summary(fun="mean", geom="point", size=3, color="red") +
stat_summary(geom="errorbar", size=3, color="red") +
theme_bw()
### converting to greyscale doesn't work
plot + scale_colour_grey()
After some research, I learned you can dissect the ggplot object then rebuilt it:
### can rebuilt ggplot object, but not ideal
q <- ggplot_build(plot)
q$data[[2]]$colour <- "black"
q$data[[3]]$colour <- "black"
q <- ggplot_gtable(q)
plot = ggplotify::as.ggplot(q)
plot
That works fine, but I try to include as few dependencies in my R packages as possible. Do I really have to resort to another package (ggplotify) in order to modify the color coming from stat_summary?
A few notes: I don't want to have to modify the original stat_summary statement. Let's just pretend that cannot be modified. Also, let's assume I cannot add another package (aside from ggplot2, which is already loaded). Remember, I'm a "guest" in the JASP framework and I don't want to have to add another package to the list of packages they have to store.
You can actually get at the ggplot object before it is built, reach into the layer that has the coloured object and change it. Here's a full reprex:
library(ggplot2)
# simulate data
set.seed(1212)
y = rnorm(100)
g = sample(c("a", "b"), 100, T)
d = data.frame(y=y, g=g)
### create ggplot
p <- ggplot(data=d, aes(x=g, y=y)) +
geom_jitter() +
stat_summary(fun="mean", geom="point", size=3, color="red") +
stat_summary(geom="errorbar", size=3, color="red") +
theme_bw()
p
p$layers[[3]]$aes_params$colour <- "gray50"
p
If you want a more general approach to change a particular geom's colour, you could do something like this function:
recolour_geom <- function(gg_plot, geom, colour = "gray50")
{
ss <- which(sapply(p$layers, function(l) {
paste(gsub("GEOM|GG|PROTO", "", toupper(class(l$geom))),
collapse = "")}) %in% toupper(geom))
if (length(ss) > 0)
{
for (i in ss)
{
p$layers[[i]]$aes_params$colour <- colour
}
}
p
}
Which allows you to do, for example
recolour_geom(p, "errorbar", "blue")
recolour_geom(p, "point", "green")
Be aware though that this changes the ggplot by reference, so p is changed as a side effect of the function.
Created on 2020-08-14 by the reprex package (v0.3.0)

How to set images as labels for bar chart in polar coordinates in R [duplicate]

I've tried to follow the answer's given already for adding images to plots, but they do not work when using coord_polar()
# install.packages("RCurl", dependencies = TRUE)
library(RCurl)
myurl <- "http://vignette2.wikia.nocookie.net/micronations/images/5/50/German_flag.png"
# install.packages("png", dependencies = TRUE)
library(png)
img <- readPNG(getURLContent(myurl))
# install.packages("ggplot2", dependencies = TRUE)
library(ggplot2)
ger <- grid::rasterGrob(img, interpolate=TRUE)
## works, adds the image to the plot
ggplot(mtcars, aes(x=mpg, y= cyl)) + geom_line() + annotation_custom(ger, 10, 15, 5)
## doesn't work
ggplot(mtcars, aes(x=mpg, y= cyl)) + geom_line() + annotation_custom(ger) + coord_polar()
> Error: annotation_custom only works with Cartesian coordinates
Ideally I'd like to be able to position the flag image within the center of the polar plot, and another image along the y-axis.
Is there anyway to add the image? It can be as-is, no transformation required.
I'm using ggplot2 version 2.0
Gregor's suggestion for using the cowplot library has got me there.
Following the introduction to cowplot you can use the draw_grob function to overlay images as you like. It takes a bit of tweaking as the position changes depending on the dimensions of the plot, but its possible.
Example:
# install.packages("RCurl", dependencies = TRUE)
library(RCurl)
myurl <- "http://vignette2.wikia.nocookie.net/micronations/images/5/50/German_flag.png"
# install.packages("png", dependencies = TRUE)
library(png)
img <- readPNG(getURLContent(myurl))
# install.packages("ggplot2", dependencies = TRUE)
library(ggplot2)
ger <- grid::rasterGrob(img, interpolate=TRUE)
g <- ggplot(mtcars, aes(x=mpg, y= cyl)) + geom_line() + coord_polar()
# install.packages("cowplot", dependencies = TRUE)
library(cowplot)
h <- ggdraw(g)
## tweak this to fit your plot
h + draw_grob(ger, 0.4, 0.48, 0.07, 0.07)

tableGrob: resizing a table (changing font size) drawn on top of ggplot using annotation_custom

I'm having some issues resizing the text in a table drawn over a plot using tableGrob() and annotation_custom(). Essentially, I want the font size in the table to be smaller so that the overall table is smaller. I've checked the tableGrob() documentation and have followed it to the best of my ability, but I must be doing something wrong as it's throwing an error.
Here's a reproducible example:
library(ggplot2)
library(grid)
library(gridExtra)
df <- data.frame(x=seq(1,10),y=seq(11,20))
table <- data.frame(x=seq(1,3),y=seq(4,6))
ggplot(df,aes(x=x,y=y)) + geom_point() +
annotation_custom(tableGrob(table,rows=NULL),xmin=0,xmax=3,ymin=15,ymax=20) # plot drawn successfully without text resizing
ggplot(df,aes(x=x,y=y)) + geom_point() +
annotation_custom(tableGrob(table,rows=NULL,gpar.coretext = gpar(col = "black", cex = 0.8)),xmin=0,xmax=3,ymin=15,ymax=20)
# error when attempting to resize text following tableGrob documentation
This is the error I get when I run the second ggplot() command:
Error in gtable_table(d, name = "core", fg_fun = theme$core$fg_fun, bg_fun = theme$core$bg_fun, :
unused argument (gpar.coretext = list(col = "black", cex = 0.8))
Any help is much appreciated!
If you just want all the text to be smaller in your table, use base_size in ttheme_default:
library(ggplot2)
library(grid)
library(gridExtra)
df <- data.frame(x=seq(1,10),y=seq(11,20))
table <- data.frame(x=seq(1,3),y=seq(4,6))
ggplot(df,aes(x=x,y=y)) +
geom_point() +
annotation_custom(tableGrob(table,rows=NULL, theme = ttheme_default(base_size = 8)),
xmin=0,xmax=3,ymin=15,ymax=20)
Created on 2020-03-05 by the reprex package (v0.3.0)

How to add an in memory png image to a plot?

I have a png image that is generated automatically in memory as opposed to loading it from disk. I could of course save it first to disk but I'd rather not do it. I'd like to display that image somewhere in a ggplot2 plot but can't find the right package/function to do that.
The image I have in memory is e.g.
x <- "data:image/png;base64,..."
UPDATE a realistic use-case, and the error I get while trying to use Answer #1
library(qrencoder)
x <- qrencode_png("http://rud.is/b")
x
[1] "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAAAAACMfPpKAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAfElEQVQYlU2QWwrEMAwDR0vuf+XZj8qJSyjIyNYjAkAMQNFhkBCKzoNiin70kxKBN41ENuf7+9AZWQOGRx/2m4TeKy2YO0GyDpwszW5EUCs/ur78NZtGvSa8azdPDGttsonot8LtDFNnrs4yLSbuJk0ajnV3vevhCxUj4Q+R11n764g4WgAAAABJRU5ErkJggg=="
myImage <- png::readPNG(x)
> Error in png::readPNG(x) :
> unable to open
> data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAAAAACMfPpKAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAfElEQVQYlU2QWwrEMAwDR0vuf+XZj8qJSyjIyNYjAkAMQNFhkBCKzoNiin70kxKBN41ENuf7+9AZWQOGRx/2m4TeKy2YO0GyDpwszW5EUCs/ur78NZtGvSa8azdPDGttsonot8LtDFNnrs4yLSbuJk0ajnV3vevhCxUj4Q+R11n764g4WgAAAABJRU5ErkJggg==
I have also tried the following but I get different errors:
qrGrob <- grid::gTree(children=gList(grid::rasterGrob(x)))
or
qrGrob <- grid::gTree(children=gList(grid::rasterGrob(x)))
This might work:
Read an image from a vector
Render an image
Plot using blank ggplot2 geom
Code:
myImage <- png::readPNG(x)
myImage <- grid::rasterGrob(myImage, interpolate = TRUE)
library(ggplot2)
ggplot() +
geom_blank() +
annotation_custom(myImage, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf)
I could not find any way to load the PNG from memory. However, this other way works perfectly using the raster version:
library(ggplot2)
library(raster)
library(qrencoder)
library(grid)
qrGrob <- grid::rasterGrob(raster::as.raster(
qrencoder::qrencode_raster("http://rud.is/b"),
maxpixels=.Machine$integer.max,col=c("white", "black")),
interpolate=FALSE)
ggplot() + geom_blank() + annotation_custom(qrGrob,0,1,0,1)
Based on #SkyWalker , it works for me.
library(ggplot2)
library(raster)
library(qrencoder)
library(grid)
setwd("D:/WORK/R_Prj/OCR")
QRtxt <- paste0("Qt",round(runif(10)*10))
QR.in.Batch <- function(x){
qrGrob <- grid::rasterGrob(raster::as.raster(
qrencoder::qrencode_raster(x),
maxpixels=.Machine$integer.max,col=c("white", "black")),
interpolate=FALSE)
ggplot() + geom_blank() + annotation_custom(qrGrob,0,1,0,1)
}
lapply(QRtxt, QR.in.Batch)

How to add logo on ggplot2 footer

How to add image logo outside the plotting areas for ggplot2. Tried rasterGrob function from 'grid' package, but that keep's the image inside plot area.
Here is the starter script:
library(ggplot2)
library(png)
library(gridExtra)
library(grid)
gg <- ggplot(df1, aes(x = mpg, y = wt)) +
theme_minimal() +
geom_count() +
labs(title = "Title Goes Here", x = "", y = "")
img <- readPNG("fig/logo.png")
Here is the outcome I am looking for.
I can add the annotation on the right side, but the logo on the left is where I am getting challenged.
You can add the elements with annotation_custom but you need to turn off clipping for the images to show up when they're outside the plot area. I've changed your example slightly in order to make it reproducible.
library(ggplot2)
library(png)
library(gridExtra)
library(grid)
gg <- ggplot(mtcars, aes(x = mpg, y = wt)) +
theme_minimal() +
geom_count() +
labs(title = "Title Goes Here", x = "", y = "")
img = readPNG(system.file("img", "Rlogo.png", package="png"))
gg = gg +
annotation_custom(rasterGrob(img),
xmin=0.95*min(mtcars$mpg)-1, xmax=0.95*min(mtcars$mpg)+1,
ymin=0.62*min(mtcars$wt)-0.5, ymax=0.62*min(mtcars$wt)+0.5) +
annotation_custom(textGrob("Footer goes here", gp=gpar(col="blue")),
xmin=max(mtcars$mpg), xmax=max(mtcars$mpg),
ymin=0.6*min(mtcars$wt), ymax=0.6*min(mtcars$wt)) +
theme(plot.margin=margin(5,5,30,5))
# Turn off clipping
gt <- ggplot_gtable(ggplot_build(gg))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)
Another option is to use ggplot's caption feature to add the text footer, which saves some code:
gg = gg +
annotation_custom(rasterGrob(img),
xmin=0.95*min(mtcars$mpg)-1, xmax=0.95*min(mtcars$mpg)+1,
ymin=0.62*min(mtcars$wt)-0.5, ymax=0.62*min(mtcars$wt)+0.5) +
labs(caption="Footer goes here") +
theme(plot.margin=margin(5,5,15,5),
plot.caption=element_text(colour="blue", hjust=1.05, size=15))
# Turn off clipping
gt <- ggplot_gtable(ggplot_build(gg))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)
Jut adding an updated method from the terrific package Magick:
library(ggplot2)
library(magick)
library(here) # For making the script run without a wd
library(magrittr) # For piping the logo
# Make a simple plot and save it
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
ggtitle("Cars") +
ggsave(filename = paste0(here("/"), last_plot()$labels$title, ".png"),
width = 5, height = 4, dpi = 300)
# Call back the plot
plot <- image_read(paste0(here("/"), "Cars.png"))
# And bring in a logo
logo_raw <- image_read("http://hexb.in/hexagons/ggplot2.png")
# Scale down the logo and give it a border and annotation
# This is the cool part because you can do a lot to the image/logo before adding it
logo <- logo_raw %>%
image_scale("100") %>%
image_background("grey", flatten = TRUE) %>%
image_border("grey", "600x10") %>%
image_annotate("Powered By R", color = "white", size = 30,
location = "+10+50", gravity = "northeast")
# Stack them on top of each other
final_plot <- image_append(image_scale(c(plot, logo), "500"), stack = TRUE)
# And overwrite the plot without a logo
image_write(final_plot, paste0(here("/"), last_plot()$labels$title, ".png"))

Resources