How to add logo on ggplot2 footer - r

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"))

Related

Ggplotly missing text on bars [duplicate]

I am using plotly 4.8 with ggplot2 3.0.0, and trying to add and align text labels to my scatter plots. However, it seems the hjust parameter is being ignored by plotly in geom_text(aes(....), hjust = "left"). (Also tried hjust = 0.)
GGPLOT OUTPUT
See it renders fine in plot window as a ggplot with labels left aligned.
PLOTLY OUTPUT
But the alignment is lost in conversion, and the text is centered.
So the question, is fixing this alignment possible with plotly?
TEST EXAMPLE CODE
library(ggplot2)
library(data.table)
library(plotly)
data(mtcars)
plotdata <- as.data.table(mtcars)
plotdata$carname <- rownames(mtcars)
# take a small demo subset
plotdata <- plotdata[1:10,]
gg <- ggplot(plotdata, aes(x = wt, y = mpg, label = carname)) +
geom_point() + theme_minimal()
gg <- gg + geom_text(aes(label = carname),
size = 2,
hjust = "left")
print(gg)
# convert ggplot
p <- ggplotly(gg)
p
You just need to add text position textposition = "right":
ggplotly(p) %>% style(textposition = "right")
Output:
Ref: https://github.com/ropensci/plotly/issues/769

insert image in caption and adjust its size to fontsize

Problem
I would like to insert an image in between some text in the caption of my ggplot.
What I found on sofar is this solution using some gtable hacking.
But this solution is somewhat unviable for me, because I want to add text before and after the image. Besides, it doesn't resize the image to the actual fontsize of the caption.
library(tidyverse)
library(magick)
library(grid)
library(gtable)
ggplot(iris,
aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
theme(plot.caption = element_text(hjust=0,
size = 10)) +
labs(caption = "\uA9 *INSERT MY COMPANY LOGO HERE* My fabulous company, 2019")
my_logo <- image_read("https://upload.wikimedia.org/wikipedia/commons/3/3e/Phalaenopsis_JPEG.png")
print(my_logo)
Goal
What I want to achieve is this. Note that the logo's (my_logo) vertical size is equal to the fontsize of the caption.
The answer you link to provides all the ingredients,
library(ggplot2)
library(grid)
library(dplyr)
library(gtable)
lg <- textGrob(label = "\uA9", x = unit(0, "npc"), just = "left")
rg <- textGrob(label = "My fabulous company, 2019", x = unit(0, "npc"), just = "left")
mg <- png::readPNG(system.file("img", "Rlogo.png", package="png")) %>%
rasterGrob(interpolate = TRUE, height = grobHeight(rg))
p <- ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
labs(caption="") # to create space for title
# convert to grob
gt <- ggplotGrob(p)
# create new title as a tableGrob with separate cells for image & text
new.title <- gtable_row('caption', grobs = list(lg,mg,rg),
widths = unit.c(grobWidth(lg), grobWidth(mg), unit(1,"null")),
height=unit(1,"null")) %>%
# optional: adda fixed amt of space between image & text
gtable_add_col_space(width = unit(5, "pt"))
# assign new title back to gt
gt$grobs[[which(gt$layout$name == "caption")]] <- new.title
grid.newpage()
grid.draw(gt)

Blurry logo ggplot chart

I am trying to add my company logo under all of our charts. I managed to do so however the end result looks a bit disappointing. The logo looks all blurry despite me using high res image.
Is there any way I can improve this?
(Note that the R logo I use has the same resolution as my company logo's res. They are all 1000*1000px)
Below is my code:
library(ggplot2)
library(png)
library(gridExtra)
library(grid)
dev.off(dev.list()["RStudioGD"])
gg <- ggplot(mtcars, aes(x = mpg, y = wt)) +
theme_minimal() +
geom_count() +
labs(title = "Title Goes Here", x = "", y = "")
img <- readPNG("R-logo.png")
gg = gg +
annotation_custom(rasterGrob(img),
xmin=0.95*min(mtcars$mpg)-1, xmax=0.95*min(mtcars$mpg)+1,
ymin=0.6*min(mtcars$wt)-0.7, ymax=0.6*min(mtcars$wt)+0.5) +
theme(plot.margin=margin(5,10,40,5))
# Turn off clipping
gt <- ggplot_gtable(ggplot_build(gg))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
png('chart.png', width = 600, height = 500, units = "px",type='cairo',res=72)
grid.draw(gt)
dev.off()
Actually, I found the way to properly scale the logo before laying over the plot. The magick package works wonderfully.
library(magick)
img <- image_read("R-logo.png")
img <- image_scale(img, "50")

ggplot2: Using gtable to move strip labels to top of panel for facet_grid

I am creating a graphic using facet_grid to facet a categorical variable on the y-axis. I decided not to use facet_wrap because I need space = 'free' and labeller = label_parsed. My labels are long and I have a legend on the right so I would like to move the labels from the right of the panel to the top of the panel.
Here is an example to show where I'm getting stuck.
library(ggplot2)
library(gtable)
mt <- ggplot(mpg, aes(x = cty, y = model)) + geom_point() +
facet_grid(manufacturer ~ ., scales = 'free', space = 'free') +
theme_minimal() +
theme(panel.margin = unit(0.5, 'lines'), strip.text.y = element_text(angle = 0))
Now I would like to move the strip text from the right of each panel to the top of each panel. I can store the grobs for the strip labels and remove them from the plot:
grob <- ggplotGrob(mt)
strips.y <- gtable_filter(grob, 'strip-right')
grob2 <- grob[,-5]
But now I'm stuck when it comes to rbind-ing the grobs back so the labels go to the top of the panels.
Another possible solution would be to use facet_wrap and then re-size the panels as discussed in another question, but in that case I would have to manually change the labels on the facets because there is no labeller = label_parsed for facet_wrap.
I'd appreciate suggestions on either approach!
Thanks for reading,
Tom
This takes your first approach. It inserts a row above each of the panels, grabs the strip grobs (on the right), and inserts them into the new rows.
library(ggplot2)
library(gtable)
library(grid)
mt <- ggplot(mpg, aes(x = cty, y = model)) + geom_point() +
facet_grid(manufacturer ~ ., scales = 'free', space = 'free') +
theme(panel.spacing = unit(0.5, 'lines'),
strip.text.y = element_text(angle = 0))
# Get the gtable
gt <- ggplotGrob(mt)
# Get the position of the panels in the layout
panels <-c(subset(gt$layout, grepl("panel", gt$layout$name), se=t:r))
# Add a row above each panel
for(i in rev(panels$t-1)) gt = gtable_add_rows(gt, unit(.5, "lines"), i)
# Get the positions of the panels and the strips in the revised layout
panels <-c(subset(gt$layout, grepl("panel", gt$layout$name), se=t:r))
strips <- c(subset(gt$layout, grepl("strip-r", gt$layout$name), se=t:r))
# Get the strip grobs
stripText = gtable_filter(gt, "strip-r")
# Insert the strip grobs into the new rows
for(i in 1:length(strips$t)) gt = gtable_add_grob(gt, stripText$grobs[[i]]$grobs[[1]], t=panels$t[i]-1, l=4)
# Remove the old strips
gt = gt[,-5]
# For this plot - adjust the heights of the strips and the empty row above the strips
for(i in panels$t) {
gt$heights[i-1] = unit(0.8, "lines")
gt$heights[i-2] = unit(0.2, "lines")
}
# Draw it
grid.newpage()
grid.draw(gt)
OR, you can achieve the second approach using a facet_wrap_labeller function available from here.
library(ggplot2)
library(gtable)
mt <- ggplot(mpg, aes(x = cty, y = model)) + geom_point() +
facet_wrap(~ manufacturer, scales = "free_y", ncol = 1) +
theme(panel.margin = unit(0.2, 'lines'))
facet_wrap_labeller <- function(gg.plot, labels=NULL) {
require(gridExtra)
g <- ggplotGrob(gg.plot)
gg <- g$grobs
strips <- grep("strip_t", names(gg))
for(ii in seq_along(labels)) {
modgrob <- getGrob(gg[[strips[ii]]], "strip.text",
grep=TRUE, global=TRUE)
gg[[strips[ii]]]$children[[modgrob$name]] <- editGrob(modgrob,label=labels[ii])
}
g$grobs <- gg
class(g) = c("arrange", "ggplot",class(g))
return(g)
}
## Number of y breaks in each panel
g <- ggplot_build(mt)
N <- sapply(lapply(g$panel$ranges, "[[", "y.major"), length)
# Some arbitrary strip texts
StripTexts = expression(gamma[1], sqrt(gamma[2]), C, `A really incredibly very very very long label`, gamma[5], alpha[1], alpha[2], `Land Rover`, alpha[1], beta[2], gamma^2, delta^2, epsilon[2], zeta[3], eta[4] )
# Apply the facet_wrap_labeller function
gt = facet_wrap_labeller(mt, StripTexts)
# Get the position of the panels in the layout
panels <- gt$layout$t[grepl("panel", gt$layout$name)]
# Replace the default panel heights with relative heights
gt$heights[panels] <- lapply(N, unit, "null")
# Draw it
gt
I was struggling with a similar problem but putting the labels on the bottom. I've used a code adaptation of this answer. And recently found that
ggplot2 ver.2.2.1.0 (http://docs.ggplot2.org/current/facet_grid.html)
~facet_grid(.~variable,switch='x')
option which has worked beautifully for me.

Inserting an image to ggplot2

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)

Resources