Complete list of ggplot2's primitives is given by geom_*: blank(), path(), ribbon(), polygon(), segment(), rect(), text(), and point(). Every primitive starts with geom_* but not every geom_* is a primitive. In fact, the better odds stands for quite the opposite.
More or less, geom_blank() seems to be the simplest of the primitives. Calling it right after setting ggplot() will display a blank plot with axis already adjusted. It's mostly used to check axes limits given by data itself. Maybe you can find it useful for another task; suit yourself.
Other primitives may work in a similar way. That is the case for geom_path(), geom_ribbon(), and geom_polygon() functions. The first one draws lines between coordinates, second one looks like the first but thicker, requiring additional aes() arguments (ymin and ymax). Last function draws filled polygons.
By setting only the starting and ending points, geom_segment() adds a segment line. geom_rect() adds a rectangle to the plot, requiring four corners to do so (xmin, xmax, ymin, and ymax). geom_text() add texts to the given coordinates. Some graphics displays only texts for each observations instead of points, also a good way to display additional information.
The remaining primitive is geom_point(). It's the only primitive direct called so far, it plot points at given coordinates. Two important points must be highlighted here. One, getting to know the primitives might give you an idea about which function you will require the most and which one the least, but that is not all that ggplot2 is capable of doing. Primitives are nothing but the building blocks used by other functions.
For the second point, as the previous recipe stated earlier, you can stack as many layers as you feel like. That is not less true for primitives functions, but it's good to know how they interact with one another. For example, calling geom_blank() after geom_point() may not override the points with a blank space.
After loading ggplot2 and setting base aes(), step 1 is creating a simple plot with lines and markers. While geom_point() displays the markers, geom_path() draws the lines between them. Note that the last function draws lines following the order given by data set rows, so we can call this function order-sensitive.
For many situations, reordering data will improve viz. This may be the case for dot, box, violin, bar plots, and others. If you want paths to be ordered within the x variable, geom_line() does that by itself, though it is not a primitive.
To this particular plot, the lines attach no meaning; they actually mislead. Lines are better designated to indicate some sort of order within the data, like chronological order. The only reason they were used was to demonstrate how primitives could be stacked to originate different viz from the one done before.
Step 2 is drawing a plot similar to the one crafted by step 1 but using ggvis instead. libray() loads the package while the ggvis() function is used to map the basic aesthetics. Following function (layer_points()) sets up the points to work as our markers and layer_paths() draws the lines between them.
Earlier section argued that ggvis is very similar to ggplot2 in the ways of coding graphics. This section actually demonstrated that. First, the function gets the data set and the variables are inputted as arguments. Pipe operators (%>%) are used instead of plus sign to stack up the layers, and layer_* works in a very similar way as geom_* does.
By step 3, a similar plotly graphic is crafted. Same function responsible for setting basic aesthetic mapping (plot_ly()) is also dealing geometries. Arguments type and mode set the geometries, both inputted with strings. These two arguments are meant to work together.
Setting type = 'scatter' enables the lines and markers modes. Each type has a whole particular convoy of modes attached to it; consult the reference manual to catch them all. The way we wanted to is to use markers and lines at same time so we built a string containing those two elements separated by the plus sign ('lines+markers'), and assigned it to mode argument.
mode = 'lines+markers' works as good as mode = 'markers+lines'. Modes can be stacked and order does not matter.
Figures 1.4 to 1.6 five resembles much a time series, but they aren't and it may give the wrong intuition. There are observations for two variables and neither one is time. Notice how for some speeds values there are up to 4 different distances to stop. Note that the cars data frame is ordered first by speed and then by distance, paths obey the row order showed by data while for point geometry order doesn't really matter.
Adding path geometry was misleading, geom_point() would be enough. Goal here was to demonstrate primitives interaction and not to give a meaningful figure. Next, let's build fictional data and draw a graphic that tells the story the right way. Picture a small classroom with only 7 students. The teacher builds a data frame with studying hours and grades for each student.
Data can be created like this:
> allnames <- c('Phill','Ross','Kate','Patrice','Peter','James','Monica')
> classr <- data.frame(names = allnames)
> classr$hours <- c(4, 16, 8, 11, 6, 14, 8)
> classr$grades <- c(4, 9.5, 6, 4, 6, 9, 7.5)
geom_text() primitive could be used to summon a meaningful graphic:
> library(ggplot2)
> plot2 <- ggplot( classr, aes(x = hours, y = grades))
> plot2 + geom_text( aes( labels = names))
The result would be like shown in the following figure 1.7:
Figure 1.7 - Plotting grades and hours as texts using ggplot2's primitive.
Related ggvis and plotly codes are shown next:
> library(ggvis)
> ggvis(classr, x = ~hours, y = ~grades, text := ~names) %>% layer_text()
> library(plotly)
> plot_ly(classr, x = ~hours, y = ~grades, type = 'scatter', mode = 'text', text = ~names)
This last brief example illustrates how to brew graphics using only primitives in a more meaningful way. It's very important to think about it. The better graphic is the one that tells the right story objectively and not the one with many layers.