It seems there is some padding around the title, which I can't figure out how to change, any thoughts?
xy <- data.frame(x=1:10, y=10:1)
plot <- ggplot(data = xy)+ geom_point(aes(x = x, y = y))
plot <- plot + opts(plot.background = theme_rect(colour = 'purple', fill = 'pink', size = 3, linetype='dashed'))
plot
plot + opts(title = 'Graph Title')
plot
If you run this, hold a piece of paper on your screen (old school, I know) in line with the top of the G and T from the title, then run the plot again, you'll see you have some grey above your paper. Which I can only presume is indicative of some padding around the title? Or likewise, if you run it without the title and hold the paper (above) in line with the end of the pink background, then run it with the title, the top of the G and T are below the paper.
Example is essentially from https://github.com/hadley/ggplot2/wiki/Graph-Panel-Attributes
This suggests there is a line height option but it appears to do nothing http://www.inside-r.org/packages/cran/ggplot2/docs/theme_text
So here is a hack:
p <- plot + opts(title = 'Graph Title')
p <- ggplot_gtable(ggplot_build(p))
p$heights[[2]] <- p$heights[[2]]-unit(0.5, "lines")
grid.draw(p)
This code remove the padding.
But I'd recommend to send a feature request: https://github.com/hadley/ggplot2/issues?milestone=
Related
I hope you can help me. I have the idea of visualizing segments within a plot with a rectangle that can be placed next to the y or x-axis which means that it would be outside of the plot area. It should look similar as in the image below:
I tried to reach the mentioned output by trying two different approaches:
I created two viewports with the grid package and put the plot in one viewport that I placed at the bottom and one viewport on top of that. The big problem here is that I need the coordinates from where the grey background panel of the ggplot starts so I can place the top viewport exactly there, so that the segments conincide with the x-axis length. My code looked like following:
container_viewport <- viewport(x=0,y=0,height=1,width=1,just = c("left","bottom"))
pushViewport(container_viewport)
grid.draw(rectGrob())
popViewport()
section_viewport <- viewport(x=0.055,y=0.99,height=0.085,width=0.935,just=c("left","top"))
pushViewport(section_viewport)
plot_obj <- ggplot_build(testplot)
plot_data <- plot_obj$data[[1]]
grid.draw(rectGrob(gp = gpar(col = "red")))
popViewport()
plot_viewport <- viewport(x=0,y=0,height=0.9,width=1,just=c("left","bottom"))
pushViewport(plot_viewport)
grid.draw(ggplotGrob(testplot))
popViewport()
This looks fine but I had to hardcode the coordinates of the viewport at the top.
I used grid.arrange() to arrange to stack the plots vertically (instead of a grob for the rectangle like in the other approach I create a ggplot instead for that). Here, basically the same problem exists, since I somehow need to put the plot representing the rectangle at the top in the right position on the x-axis. My code looked like following:
p1 <- plot_data %>%
ggplot()+
geom_rect(aes(xmin=-Inf,xmax=Inf,ymin=-Inf,ymax=Inf))
p2 <- testplot
test_plot <- grid.arrange(p1,p2,heights=c(1,10))
This approach does not work that good.
Since I would like to create a solution that can be applied generally, trial and error with the coordinates of the viewport is no option since the length of the y-axis label or tick labels can vary and therefore the length and coordinates of the background panel. When this step is done the segmentation of the rectangle should be no problem anymore.
Maybe this is just not possible but if then I would appreciate any help.
Thank you!
I would probably use patchwork here. Let's start by replicating your plot:
library(ggplot2)
library(patchwork)
p <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point(color = "red") +
labs(x = "test", y = "test")
p
That looks very similar. Now we define (in our own co-ordinates) where we want the section split to occur on the x axis.
section_split <- 5.25
Using just this number, we add rectangles and text annotations that cover a copy of our original plot, and remove its axis annotations using theme_void:
p2 <- p +
annotate("rect", xmin = c(-Inf, section_split), ymin = c(-Inf, -Inf),
xmax = c(section_split, Inf), ymax = c(Inf, Inf),
fill = c("#00a2e8", "#ff7f27")) +
annotate("text", label = c("Section A", "Section B"), size = 6,
y = rep(mean(layer_scales(p)$y$range$range), 2),
x = c((min(layer_scales(p)$x$range$range) + section_split)/2,
(max(layer_scales(p)$x$range$range) + section_split)/2)) +
theme_void()
Now we just draw this second plot above our first, adjusting the relative heights to about 1:10
p2/p + plot_layout(heights = c(1, 10))
The benefit of doing it this way is that, since we copied the original plot, the positional mapping of the x axis is identical between the two plots, and patchwork will automatically line up the panels.
Created on 2023-02-04 with reprex v2.0.2
I was wondering whether it is possible to add shapes to the legend for ggimage(). I found similar questions, but they either have 1) same picture with a different color in legend, or 2) same picture different colors. I used this link to add images to the legend that have color, but i can't figure out how to edit it so that image will be different. I tried this, but I am not advance enough to adjust the code to fit my case
d <- data.frame(x = rnorm(10),
y = rnorm(10),
image = sample(c("https://www.r-project.org/logo/Rlogo.png",
"https://jeroenooms.github.io/images/frink.png"),
size=10, replace = TRUE)
)
ggplot(d, aes(x, y)) + geom_image(aes(image=image, color=image), size=.05)
Solved by ussing ggdraw:
p2 os the ggplot() object where I ploted images in row (coordinates x=2, y = c(1,2) ) and added text (coordinates x=2.5, y=c(1,2))
ggdraw() +
draw_plot(p1) +
draw_plot(p2, x = 0.55, y = 0.6)
And then I just play around with the position of p2 as well as added xlim and ylim to p2 to make text and image together
I'm trying to find a way to insert an image into the corner of a ggplot panel, without specifying the coordinates manually each time.
In this instance, I'm attempting to place a graphic in the top right.
library(magick)
library(ggplot2)
library(datasets)
homer <- magick::image_read("http://icons.iconarchive.com/icons/jonathan-rey/simpsons/128/Homer-Simpson-04-Happy-icon.png")
g <- ggplot(mpg, aes(class)) +
geom_bar() +
labs(
title = "Count of Auto by Class",
subtitle = "Text to Create More Space")
g + annotation_custom(rasterGrob(homer, interpolate = TRUE),
xmax = Inf, ymax = Inf) +
coord_cartesian(clip = "off")
I have found some examples that come close to solving this:
Inserting an image to ggplot outside the chart area
Corner Labels in ggplot2
But neither quite get there. Specifying the exact location at which to place the image seems to require quite a bit of trial-and-error on each plot created, especially when x is categorical.
I would also like to maintain the size of my original image; the code I've used above seems to stretch it across the plot.
Thanks in advance...much appreciated.
try this
library(grid)
a <- rasterGrob(homer, interpolate = TRUE,
width=unit(1,'cm'),
x = unit(1,"npc"), y = unit(1,"npc"),
hjust = 1, vjust=1)
g + annotation_custom(grob = a)
I'm using ggplot2 to create some figures with titles, but finding that when titles have a descender (e.g., lowercase p, q, g, y) the actual size of the plot shrinks slightly to accommodate the larger space needed by the title.
Are there ways within normal ggplot functionality to fix the plot size so that figures are in 100% consistent position regardless of title?
Here's some quick sample code that shows the issue; folks might need to run code locally to clearly see the differences in the images.
library(ggplot2)
# No letters with descenders in title
ggplot(data=mtcars,aes(x=disp,y=mpg)) +
geom_point() + ggtitle("Scatter Plot")
# Title has a descender (lowercase 'p')
ggplot(data=mtcars,aes(x=disp,y=mpg)) +
geom_point() + ggtitle("Scatter plot")
you can set the relevant height in the gtable,
library(ggplot2)
p1 <- ggplot() + ggtitle("a")
p2 <- ggplot() + ggtitle("a\nb")
gl <- lapply(list(p1,p2), ggplotGrob)
th <- do.call(grid::unit.pmax, lapply(gl, function(g) g$heights[3]))
gl <- lapply(gl, function(g) {g$heights[3] <- th; g})
gridExtra::grid.arrange(grobs = gl, nrow=1)
Edit: here's how to edit one plot for simplicity
g = ggplotGrob(qplot(1,1) + ggtitle('title'))
g$heights[3] = grid::unit(3,"line")
grid.draw(g)
In my plot I have both legends and text annotations. For legends, I can specify
legend.justification=c(1,0), legend.position=c(1,0)
to locate the position relative to the plotting region (e.g. topright, bottomleft). However, when I put an annotate layer (http://docs.ggplot2.org/0.9.3.1/annotate.html), it seems that I can only specify the coordinates of the text
annotate("text", x = 8e-7, y = 1e-5, label=data.note, size = 5)
instead of the position of the plotting region (I want to put the text in the bottomleft corner). The length of the text (label) may vary for different plots. Is there a way to achieve this? Thanks!
You can use the fact that -Inf and Inf will get mapped to the extremes of the position scales without extending them to place it in the bottom left corner. hjust and vjust are needed to make the reference point the lower left corner of your text. [using jlhoward's mock data.]
set.seed(1)
df <- data.frame(x=rnorm(100),y=rnorm(100))
ggplot(df, aes(x,y)) +geom_point()+
annotate("text",x=-Inf,y=-Inf,hjust=0,vjust=0,label="Text annotation")
Is this what you're looking for??
set.seed(1)
df <- data.frame(x=rnorm(100),y=rnorm(100))
ggplot(df, aes(x,y)) +geom_point()+
annotate("text",x=min(df$x),y=min(df$y),hjust=.2,label="Text annotation")
There will probably be a bit of experimentation with hjust=... needed to get this exactly at the bottom left.
The "Inf" solution has problems when you want multi-line text. In addition, it there is no margin between the text and the panel edge, which is ugly. The other solution requires explicit mention of the data which is not good either.
The desired effect can be achieved nicely with annotation_custom (or in my example, the proto Geom directly). You have configurable margin, text and box justification.
The added bonus in the following code is that you can specify which facet to annotate with something like facets=data.frame(cat1='blue', cat2='tall').
library("ggplot2")
annotate_textp <- function(label, x, y, facets=NULL, hjust=0, vjust=0, color='black', alpha=NA,
family=thm$text$family, size=thm$text$size, fontface=1, lineheight=1.0,
box_just=ifelse(c(x,y)<0.5,0,1), margin=unit(size/2, 'pt'), thm=theme_get()) {
x <- scales::squish_infinite(x)
y <- scales::squish_infinite(y)
data <- if (is.null(facets)) data.frame(x=NA) else data.frame(x=NA, facets)
tg <- grid::textGrob(
label, x=0, y=0, hjust=hjust, vjust=vjust,
gp=grid::gpar(col=alpha(color, alpha), fontsize=size, fontfamily=family, fontface=fontface, lineheight=lineheight)
)
ts <- grid::unit.c(grid::grobWidth(tg), grid::grobHeight(tg))
vp <- grid::viewport(x=x, y=y, width=ts[1], height=ts[2], just=box_just)
tg <- grid::editGrob(tg, x=ts[1]*hjust, y=ts[2]*vjust, vp=vp)
inner <- grid::grobTree(tg, vp=grid::viewport(width=unit(1, 'npc')-margin*2, height=unit(1, 'npc')-margin*2))
layer(
data = NULL,
stat = StatIdentity,
position = PositionIdentity,
geom = GeomCustomAnn,
inherit.aes = TRUE,
params = list(
grob=grid::grobTree(inner),
xmin=-Inf,
xmax=Inf,
ymin=-Inf,
ymax=Inf
)
)
}
qplot(1:10,1:10) + annotate_text2('some long text\nx = 1', x=0.5, y=0.5, hjust=1)