Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
415 views
in Technique[技术] by (71.8m points)

r - Inserting an image to ggplot outside the chart area

Is it possible to add an image to ggplot chart which will be outside chart area?

I know it is possible to add images to the chart using annotate_raster and annotate_custom, however they both add images inside the chart. I need to add company logo in the upper right corner above the chart - at the title level.

Example of adding image using annotate_custom: Inserting an image to ggplot2

UPDATE: Following recommendations from user1317221_G, I'm able to put image outside.

library(png)
library(grid)
library(ggplot2)
img <- readPNG(system.file("img", "Rlogo.png", package="png"))

g <- rasterGrob(img, interpolate=TRUE)
plt <- qplot(1:10, 1:10, geom="blank") +
      opts(title = 'Title') + 
      geom_point() 
plt2 <- plt + annotation_custom(g, xmin=9, xmax=10, ymin=10.5, ymax=11.25)

gt <- ggplot_gtable(ggplot_build(plt2))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)

i would like to put image automatically - determine xmin/xmax and ymin/ymax automatically. Using traditional graphics i can call par('usr') and get chart parameters, but this is not applicable to ggplot charts. Is there an easy way to determine plot area in ggplot? For example get sizes of plt and plug the values for limits into plt2

UPDATE2: This method also doesn't really work if you use faceting. For example I would like to put logo in the right corner at title level, in the following chart, and I get errors if I use method above.

d <- ggplot(diamonds, aes(carat, price, fill = ..density..)) + 
     xlim(0, 2) + 
     stat_binhex(na.rm = TRUE) + 
     labs(title = 'Title') +
     theme(aspect.ratio = 1) + 
     facet_wrap(~ color, scales = "free_x")
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When faceting, annotation_custom draws the annotation in all panels. Therefore, annotation-custom might not be the best way to go. Here are two attempts using functions from the grid package. Neither is entirely automatic, but you might be able to adapt one or the other to meet your needs. They set up a 2 X 2 grid, shown using the grid.show.layout() command. In the first, the faceted plot fills the entire panel, and the top right viewport contains the logo. It just so happens that in your plot, there is clear space for the logo. Note how layout.pos.row and layout.pos.col give the rows and columns occupied by a viewport within the layout.

library(ggplot2)
library(png)
library(grid)

# Get the logo
img <- readPNG(system.file("img", "Rlogo.png", package="png"))
g <- rasterGrob(img)

# Set the size of the viewport to contain the logo
size = unit(2, "cm")

# Get the graph
d <- ggplot(diamonds, aes(carat, price)) + 
     xlim(0, 2) + 
     stat_binhex(na.rm = TRUE) + 
     labs(title = 'Title') +
     theme(aspect.ratio = 1) + 
     facet_wrap(~ color, scales = "free_x")

# Set up the layout for grid 
heights = unit.c(size, unit(1, "npc") - size)
widths = unit.c(unit(1, "npc") - size, size)
lo = grid.layout(2, 2, widths = widths, heights = heights)
# Show the layout
grid.show.layout(lo)

# Position the elements within the viewports
grid.newpage()
pushViewport(viewport(layout = lo))

    # The plot
pushViewport(viewport(layout.pos.row=1:2, layout.pos.col = 1:2))
print(d, newpage=FALSE)
popViewport()

    # The logo
pushViewport(viewport(layout.pos.row=1, layout.pos.col = 2))
print(grid.draw(g), newpage=FALSE)
popViewport()
popViewport()

# To save the object
g = grid.grab()

grid.newpage()
grid.draw(g)

The title does not entirely align with the logo. One fix is to remove the title from the ggplot, draw a separate textGrob that contains the title, then position the textGrob in the top left viewport beside the viewport that contains the logo.

# Get the logo
img <- readPNG(system.file("img", "Rlogo.png", package="png"))
g <- rasterGrob(img)

# Set the size of the viewport to contain the logo
size = unit(2, "cm")

# Get the graph
d <- ggplot(diamonds, aes(carat, price)) + 
     xlim(0, 2) + 
     stat_binhex(na.rm = TRUE) + 
     # labs(title = 'Title') +
     theme(aspect.ratio = 1) + 
     facet_wrap(~ color, scales = "free_x")

# and the title
title = textGrob("Title", gp = gpar(face = "bold", cex = 2))

# Set up the layout for grid 
heights = unit.c(size, unit(1, "npc") - size)
widths = unit.c(unit(1, "npc") - 1.5*size, size)
lo = grid.layout(2, 2, widths = widths, heights = heights)
# Show the layout
grid.show.layout(lo)

# Position the elements within the viewports
grid.newpage()
pushViewport(viewport(layout = lo))

    # The plot
pushViewport(viewport(layout.pos.row=2, layout.pos.col = 1:2))
print(d, newpage=FALSE)
popViewport()

    # The logo
pushViewport(viewport(layout.pos.row=1, layout.pos.col = 2))
print(grid.draw(g), newpage=FALSE)
popViewport()

    # The title
pushViewport(viewport(layout.pos.row=1, layout.pos.col = 1))
print(grid.draw(title), newpage=FALSE)
popViewport()
popViewport()

# To save the object
g = grid.grab()

grid.newpage()
grid.draw(g)

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...