library(ggplot2)
library(magrittr)
library(dplyr)
library(tidyr)
library(titanic)
library(faraway)
Make a cirle
library(grid)
my_circle <- circleGrob(x = 0.5, y = 0.5, r = 0.5,
gp = gpar(col = "gray", lty = 3))
grid.draw(my_circle)
Aesthetics that you can set by specifying a gpar object for the gp parameter of a grob include color (col), fill (fill), transparency (alpha), line type (lty), line width (lwd), line end and join styles (lineend and linejoin, respectively), and font elements (fontsize, fontface, fontfamily). See the helpfile for gpar for more on gpar objects.
You can edit a grob after you have drawn it using the grid.edit function.
my_circle <- circleGrob(name = "my_circle",
x = 0.5, y = 0.5, r = 0.5,
gp = gpar(col = "gray", lty = 3))
grid.draw(my_circle)
my_rect <- rectGrob(x = 0.5, y = 0.5, width = 0.8, height = 0.3)
grid.draw(my_rect)
grid.draw(my_circle)
grid.edit("my_circle", gp = gpar(col = "red", lty = 1))
you can use the grid.draw function from grid to write a ggplot object to the current graphics device. You can plot the circle right over this wc_plot now.
data(worldcup)
wc_plot <- ggplot(worldcup, aes(x = Time, y = Passes)) +
geom_point()
grid.draw(wc_plot)
grid.draw(my_circle)
You can edit individual parts of a ggplot by finding the element names. You need to find the exact names each time you plot something
wc_plot
grid.force()
grid.ls()
grid.edit("geom_point.points.1400", gp = gpar(col = "red"))
grid.edit("GRID.text.1419", gp = gpar(fontface = "bold"))
A gTree grob contains one or more “children” grobs. It can very useful for creating grobs that need to contain multiple elements
candy <- circleGrob(r = 0.1, x = 0.5, y = 0.6)
stick <- segmentsGrob(x0 = 0.5, x1 = 0.5, y0 = 0, y1 = 0.5)
lollipop <- gTree(children = gList(candy, stick))
grid.draw(lollipop)
This code creates a viewport using the viewport function, navigates into it using pushViewport, writes the grobs using grid.draw, and the navigates out of the viewport using popViewport.
In this code, the x and y parameters of the viewport function specify the viewport’s location, and the just parameter specifies how to justify the viewport in relation to this location. By default, these locations are specified based on a range of 0 to 1 on each side of the plotting area, so x = 0.5 and y = 0.5 specifies the center of the plotting area, while just = c(“left”, “bottom”) specifies that the viewport should have this location at its bottom left corner.
grid.draw(rectGrob())
sample_vp <- viewport(x = 0.5, y = 0.5,
width = 0.5, height = 0.5,
just = c("left", "bottom"))
pushViewport(sample_vp)
grid.draw(roundrectGrob())
grid.draw(lollipop)
popViewport()
If you wanted to place the viewport in the center of the plotting area, for example, you could run:
grid.draw(rectGrob())
sample_vp <- viewport(x = 0.5, y = 0.5,
width = 0.5, height = 0.5,
just = c("center", "center"))
pushViewport(sample_vp)
grid.draw(roundrectGrob())
grid.draw(lollipop)
popViewport()
The width and height parameters specify the size of the viewport, again based on default units that 1 is the full width of one side of the plotting area. For example, if you wanted to make the viewport smaller, you could run:
grid.draw(rectGrob())
sample_vp <- viewport(x = 0.75, y = 0.75,
width = 0.25, height = 0.25,
just = c("left", "bottom"))
pushViewport(sample_vp)
grid.draw(roundrectGrob())
grid.draw(lollipop)
popViewport()
You can only operate in one viewport at a time. Once you are in that viewport, you can write grobs within the viewport. If you want to place the next grob in a different viewport, you will need to navigate out of that viewport before you can do so.
grid.draw(rectGrob())
sample_vp_1 <- viewport(x = 0.75, y = 0.75,
width = 0.25, height = 0.25,
just = c("left", "bottom"))
pushViewport(sample_vp_1)
grid.draw(roundrectGrob())
grid.draw(lollipop)
popViewport()
sample_vp_2 <- viewport(x = 0, y = 0,
width = 0.5, height = 0.5,
just = c("left", "bottom"))
pushViewport(sample_vp_2)
grid.draw(roundrectGrob())
grid.draw(lollipop)
popViewport()
You can also nest viewports inside each other. In this case, a new viewport is defined relative to the current viewport. For example, if you are in a viewport and position a new viewport at x = 0.5 and y = 0.5, this viewport will be centered in your current viewport rather than in the overall plotting area.
grid.draw(rectGrob())
sample_vp_1 <- viewport(x = 0.5, y = 0.5,
width = 0.5, height = 0.5,
just = c("left", "bottom"))
sample_vp_2 <- viewport(x = 0.1, y = 0.1,
width = 0.4, height = 0.4,
just = c("left", "bottom"))
pushViewport(sample_vp_1)
grid.draw(roundrectGrob(gp = gpar(col = "red")))
pushViewport(sample_vp_2)
grid.draw(roundrectGrob())
grid.draw(lollipop)
popViewport(2) #to navigate back to the main plotting area. This is because we have navigated down to a viewport within a viewport, so we need to pop up two levels to get out of the viewports.
You can use the grid.ls function to list all the elements of the plot in the current graphics device, if it was created using grid graphics.
grid.ls()
For ggplot objects, you can also use grid.ls, but you should first run grid.force to set the grobs as they appear in the current graph (or as they will appear when you plot this specific ggplot object), so you can see child grobs in the listing:
worldcup %>%
ggplot(aes(x = Time, y = Passes)) +
geom_point()
grid.force()
grid.ls()
There are several units that can be used for coordinate systems, and you typically will use different units to place objects. For example, you may want to add points to a plot based on the current x- and y-scales in that plot region, in which case you can use native units. The native unit is often the most useful when creating extensions for ggplot2, for example. The npc units are also often useful in designing new plots- these set the x- and y-ranges to go from 0 to 1, so you can use these units if you need to place an object in, for example, the exact center of a viewport (c(0.5, 0.5) in npc units), or create a viewport in the top right quarter of the plot region. Grid graphics also allows the use of some units with absolute values, including inches (inches), centimeters (cm), and millimeters (mm).
You can specify the coordinate system you would like to use when placing an object by with the unit function (unit([numeric vector], units = “native”)). For example, if you create a viewport with the x-scale going from 0 to 100 and the y-scale going from 0 to 10 (specified using xscale and yscale in the viewport function), you can use native when drawing a grob in that viewport to base the grob position on these scale values.
ex_vp <- viewport(x = 0.5, y = 0.5,
just = c("center", "center"),
height = 0.8, width = 0.8,
xscale = c(0, 100), yscale = c(0, 10))
pushViewport(ex_vp)
grid.draw(rectGrob())
grid.draw(circleGrob(x = unit(20, "native"), y = unit(5, "native"),
r = 0.1, gp = gpar(fill = "lightblue")))
grid.draw(circleGrob(x = unit(85, "native"), y = unit(8, "native"),
r = 0.1, gp = gpar(fill = "darkred")))
popViewport()
The grid.arrange function from the gridExtra package makes it easy to create a plot with multiple grid objects plotted on it. For example, you can use it to write out one or more grobs you’ve created to a graphics device:
library(gridExtra)
grid.arrange(lollipop, circleGrob(),
rectGrob(), lollipop,
ncol = 2)
For example, say you wanted to create a plot that has two plots based on the World Cup data side-by-side.
time_vs_shots <- ggplot(worldcup, aes(x = Time, y = Shots)) +
geom_point()
player_positions <- ggplot(worldcup, aes(x = Position)) +
geom_bar()
grid.arrange(time_vs_shots, player_positions, ncol = 2)
You can use the layout_matrix parameter to specify different layouts. For example, if you want the scatterplot to take up one-third of the plotting area and the bar chart to take up two-thirds, you could specify that with a matrix with one “1” (for the first plot) and two “2s”, all in one row:
grid.arrange(time_vs_shots, player_positions,
layout_matrix = matrix(c(1, 2, 2), ncol = 3))
You can fill multiple rows in the plotting device. To leave a space blank, use NA in the layout matrix at that positions. For example:
grid.arrange(time_vs_shots, player_positions,
layout_matrix = matrix(c(1, NA, NA, NA, 2, 2),
byrow = TRUE, ncol = 3))
The gridExtra also has a function, tableGrob, that facilitates in adding tables to grid graphic objects. For example, to add a table with the average time and shots for players on the top four teams in the 2010 World Cup, you can create a table grob using tableGrob and then add it to a larger plot created using grid graphics:
worldcup_table <- worldcup %>%
filter(Team %in% c("Germany", "Spain", "Netherlands", "Uruguay")) %>%
group_by(Team) %>%
dplyr::summarize(`Average time` = round(mean(Time), 1),
`Average shots` = round(mean(Shots), 1)) %>%
tableGrob()
grid.draw(ggplotGrob(time_vs_shots))
wc_table_vp <- viewport(x = 0.22, y = 0.85,
just = c("left", "top"),
height = 0.1, width = 0.2)
pushViewport(wc_table_vp)
grid.draw(worldcup_table)
popViewport()