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

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)

Related

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)

comfortable way to use unicode characters in a ggplot graph

Is there a good practice to insert unicode characters in a ggplot title and also save it as pdf?
I am struggling with expression, paste and sprintf to get a nice title...
So, what works is
ggtitle(expression(paste('5', mu, 'g')))
This will print an ugly greek mu. By ugly I mean a different font, but overall, it will be printed as pdf without problems. But the problems start, if you want to have new lines in the title. Or maybe I didn't found a solution for this.
My preferred solution would be to use sprintf with the unicode number, so for example
ggtitle(sprintf('5\u03BCg'))
It shows a nice result on the screen but it is not possible to save as pdf with ggsave. PNG works fine, but I would like to use the pdf save option.
Is there a possibility to plot the unicode characters with ggsave? I read about the cairo_pdf device, but this messes up the fonts and I can not save the plot properly.
Thanks in advance for any help.
EDIT:
Example PDF
I just uploaded an example PDF... So maybe my problem is somewhere else...
Try
library(ggplot2)
p <- ggplot(df, aes(x=date, y=value))
p <- p + geom_line()
p + ggtitle(sprintf('5\u03BCg'))
library(Cairo)
ggsave("newfile.pdf", device=cairo_pdf)
data
set.seed(42)
df <- data.frame(date = 1:10 , value = cumsum(runif(10 , max = 10)) )
Using the emojifont package fixes this issue for me.
library(emojifont)
I am sharing the tricks to have Unicode characters properly displayed on PDF files. I am currently running R-4.0.5 for Windows.
library(ggplot2)
library(gridExtra)
library(grid)
library(png)
#--- The trick to get unicode characters being printed on pdf files:
#--- 1. Create a temporary file, say "temp.png"
#--- 2. Create the pdf file using pdf() or cairo_pdf(), say "UnicodeToPDF.pdf"
#--- 3. Combine the use of grid.arrange (from gridExtra), rasterGrob (from grid), and readPNG (from png) to insert the
# temp.png file into the UnicodeToPDF.pdf file
test.plot = ggplot() +
geom_point(data = data.frame(x=1, y=1), aes(x,y), shape = "\u2191", size=3.5) +
geom_point(data = data.frame(x=2, y=2), aes(x,y), shape = "\u2020", size=3.5) +
geom_point(data = data.frame(x=1.2, y=1.2), aes(x,y), shape = -10122, size=3.5, color="#FF7F00") +
geom_point(data = data.frame(x=1.4, y=1.4), aes(x,y), shape = -129322, size=3.5, color="#FB9A99") +
geom_point(data = data.frame(x=1.7, y=1.7), aes(x,y), shape = -128515, size=5, color="#1F78B4") +
ggtitle(sprintf('5\u03BCg'))
ggsave("temp.png", plot = test.plot, width = 80, height = 80, units = "mm")
#--- Refer to http://xahlee.info/comp/unicode_index.html to see more unicode character integers
pdf("UnicodeToPDF.pdf")
grid.arrange(
rasterGrob(
readPNG(
"temp.png",
native=F
)
)
)
dev.off()
file.remove("temp.png")

ggplot 0.9.3 issue with facet_wrap, free scales and coord_flip - 2nd try

An old code that used to work perfectly no longer works with 0.9.3. The issue is related to the use of facets, free scales and coord flip.
Here is a way to reproduce:
data set: d.csv:
"Priority","Owner","Project"
"Medium","owner7","Team4"
"Medium","owner1","Team1"
"Low","","Team3"
"High","owner6","Team3"
"Medium","","Team4"
"Medium","owner3","Team1"
"Medium","owner2","Team1"
"Medium","owner5","Team2"
"Low","owner4","Team2"
"Critical","","Team2"
"Medium","owner2","Team1"
"High","","Team4"
Code:
data <- read.csv(file="d.csv",head=TRUE)
attach(data)
p3 <- ggplot(data,aes(x=Owner,fill=Priority))+
geom_bar(aes(y=..count..)) +
facet_wrap(~ Project, nrow=2, scales="free") +
opts(legend.position="none")
This creates a faceted plot but I need the axes flipped. Previously, adding a coord_flip() did the trick but now the new ggplot does not permit using free scales and coord_flip together. Is there any other way to turn the facet axes around? The free scales are important to me. Thanks for any pointers.
This is the second or third time I have run into this problem myself. I have found that I can hack my own solution by defining a custom geom.
geom_bar_horz <- function (mapping = NULL, data = NULL, stat = "bin", position = "stack", ...) {
GeomBar_horz$new(mapping = mapping, data = data, stat = stat, position = position, ...)
}
GeomBar_horz <- proto(ggplot2:::Geom, {
objname <- "bar_horz"
default_stat <- function(.) StatBin
default_pos <- function(.) PositionStack
default_aes <- function(.) aes(colour=NA, fill="grey20", size=0.5, linetype=1, weight = 1, alpha = NA)
required_aes <- c("y")
reparameterise <- function(., df, params) {
df$width <- df$width %||%
params$width %||% (resolution(df$x, FALSE) * 0.9)
OUT <- transform(df,
xmin = pmin(x, 0), xmax = pmax(x, 0),
ymin = y - .45, ymax = y + .45, width = NULL
)
return(OUT)
}
draw_groups <- function(., data, scales, coordinates, ...) {
GeomRect$draw_groups(data, scales, coordinates, ...)
}
guide_geom <- function(.) "polygon"
})
This is just copying the geom_bar code from the ggplot2 github and then switching the x and y references to make a horizontal barplot in the standard Cartesian coordinators.
Note that you must use position='identity' and possibly also stat='identity' for this to work. If you need to use a position other than identity then you will have to eddit the collide function for it to work properly.
Update per late 2016: This bug with coord_flip, facet_grid and scales="free" has been fixed in the development version of ggplot2. You can install it with
install.packages("devtools")
devtools::install_github("hadley/ggplot2")
Note, try both free_x and free_y depending on your needs, because it is not always clear what x and y mean when you have flipped the coordinates.
It seems like what you are requesting (if I understand the question correctly) has been raised to the developers before and they will not implement it. See here:
https://github.com/hadley/ggplot2/issues/95
So I guess you need to find a workaround. Here's a quick idea that should work:
Use facet_grid instead of "facet_wrap", then coord_flip() should work. Then save the picture as a pdf (or svg) and rearrange the plots in some kind of vector graphic software - I'd suggest Inkscape...

gwidgets ggraphics cutting edge of ggplot

This may be something really obvious, but I am struggling to find a good resource explaining how to use features of gwidgets. With some help I have this script which creates checkboxes which alter a list of file names which are then used to create a plot of the checked files using ggplot. The problem is that the plot is getting cut off at the right edge and I have no idea how to fix this.
EDIT: I see some of you have been busy down-rating me, but now this should work if you run it with the file I provided. I have a suspicion that the problem arises from cairoDevice and the way ggraphics renders the plot.
read.table("foo.csv", header = TRUE, sep = ",", row.names=1)
ggplot(MeanFrameMelt, aes(x=variable, y=value, color=Legend, group=Legend))+
geom_line()+
theme(panel.background = element_rect(fill='NA', colour='black', size = 1),
legend.position = "none")+
ylab("Tag Density (mean coverage/bp)")+
xlab("Distance from reference side (bp)")+
scale_x_discrete(breaks=c("V1", "V200", "V400"), labels=c("-10000", "0", "10000"))+
GraphFiles <- FileNamesOrig
w <- gwindow("Tag Density Checkboxes", width = 1000)
g <- ggroup(container = w, horizontal = FALSE)
add(g, ggraphics())
lyt <- glayout(container = g, horizontal = FALSE)
print(p)
foo.cvs (this is the MeanFrameMelt)
EDIT 2:
This is what the graph looks like for me. I don't know what is going on, I am exporting the data.frame with this command:
write.table(MeanFrameMelt, file="test.cvs", sep=",", col.names=TRUE)
but then when I run it with the exported file I get exactly what agstudy got. The files are supposed to be identical.
EDIT 3:
Tested it with gput (thank you for the suggestion) and now its creating the correct plot:
New file
Use dget(file="test.txt")
I just reorganized your code, but I can't reproduce the problem. You have to call the plot actions inside a handelr to interact later with user(e.g zoom , mouse events). I show an example here.
First time you run you have the plot with an ugly axis. Then when you click in a region , the plot is refreshed and you have a nice axis.
## I define my plot
p <- ggplot(MeanFrameMelt, aes(x=variable, y=value, color=Legend, group=Legend))+
geom_line()+
theme(panel.background = element_rect(fill='NA', colour='black', size = 1),
legend.position = "none")+
ylab("Tag Density (mean coverage/bp)")+
xlab("Distance from reference side (bp)")
## init gwidgets
library(gWidgetsRGtk2)
w <- gwindow("Tag Density Checkboxes", width = 1000)
g <- ggroup(container = w, horizontal = FALSE)
gg <- ggraphics(container=g)
lyt <- glayout(container = g, horizontal = FALSE)
## I plot it the first time
print(p)
## I add a handler
ID <- addHandlerChanged(gg, handler=function(h,...) {
p <- p + scale_x_discrete(breaks=c("V1", "V200", "V400"),
labels=c("-1000", "0", "1000"))
print(p)
})
print(p)

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