Base Plotting in R. Using the base plotting system in R can... | by Jesse Libra | Towards Data Science

Base plotting in R can be intimidating. It takes a canvas approach to plot construction, allowing you to paint layer after layer of detail onto your graphics. As a result, there is a seemingly endless number of functions and attributes to learn, but there’s no need to panic or jump straight to ggplot. This article highlights the versatility of the base plot() function while giving you some quick tricks to create beautiful plots.
Throughout this article, I use Edgar Anderson’s Iris dataset, so you can copy the code and see it in action. We will use this dataset to create and compare four graphs:
The most basic plot you can create in R, an XY scatterplotA plot using color to subset a scatterplot of the iris dataset by speciesA plot with customized fonts, colors, and sizes, andA plot with a background-color and grid.
The most basic plot you can create in R, an XY scatterplot
A plot using color to subset a scatterplot of the iris dataset by species
A plot with customized fonts, colors, and sizes, and
A plot with a background-color and grid.
To load the dataset package and learn a little bit about the Iris dataset, enter the following code in your RStudio console:
library(datasets)help(iris)
Above, I used base R plotting to graph petal width vs. petal length. The graph on the left is the most basic graph you can create in R: a scatter plot with an x and y variable.
The graph on the right communicates more information, subsetting the data by species using color. It also looks a little nicer, with axis labels, a title, color, and a legend. Color is applied based on the iris species using ifelse(). It only takes a couple of seconds longer to write code for this level of detail, and adds information and clarity.
You can recreate both of these graphs in R using this code:
##par lets us set global parameters for our graphs.par(mfrow = c(1,2), mar = c(5,5,4,1))##Simple plot (left)plot (iris$Petal.Length,iris$Petal.Width)##Plot showing species subsets (right)plot(iris$Petal.Length, iris$Petal.Width,      xlab = "Petal Length",     ylab = "Petal Width",     main = "Petal Width vs Petal Length",     pch = 20,     col=ifelse(iris$Species == "setosa","coral1",                 ifelse(iris$Species == "virginica","cyan4",                        ifelse(iris$Species ==  "versicolor",                              "darkgoldenrod2", "grey"))))##legendlegend("bottomright", c("setosa","virginica", "versicolor"),       col = c("coral1","cyan4", "darkgoldenrod2"), pch=20)
The code for the species subsets can be divided into three sections:
ParametersPlot attributesThe legend
Parameters
Plot attributes
The legend
The parameter section fixes the settings for all your plots. Here we haven’t added many arguments. We have mfrow which is specifying that we have one row and two columns of plots — that is, two plots side by side. The mar attribute is a vector of our margin widths, with the first value indicating the margin below the plot (5), the second indicating the margin to the left of the plot(5), the third, the top of the plot(4), and the fourth to the left (1).
par(mfrow = c(1,2), mar = c(5,5,4,1))
The second section is the meat of the plot. You can see that by just adding five arguments to our plot() function we have improved the look and usefulness of our graph. These arguments are:
xlab: specifies the x-axis label of the plot
ylab: specifies the y-axis label
main: titles your graph
pch: specifies the symbology of your graph
col: specifies the colors for your graph.
##Plot with some customizationplot(iris$Petal.Length, iris$Petal.Width,      xlab = "Petal Length",     ylab = "Petal Width",     main = "Petal Width vs. Petal Length",     pch = 20,     col=ifelse(iris$Species == "setosa","coral1",                 ifelse(iris$Species == "virginica","cyan4",                        ifelse(iris$Species ==  "versicolor",                              "darkgoldenrod2", "grey"))))
The argument that will make the biggest difference to the look of your graph is col. When you’re starting out, I recommend memorizing the names of three to four colors that look good together from the cheat sheet at the end of this article.
legend("bottomright", c("setosa","virginica", "versicolor"),       col = c("coral1","cyan4", "darkgoldenrod2"), pch= c(20))
The legend function allows users to define its location, the strings that appear as labels, and the symbols that appear next to each. Creating legends like this is a double-edged sword: the fact that it is not automatic gives you a huge amount of control over how your legend looks, but it is also easy to mislabel your symbols, so ojo.
This level of customization could be necessary if you are creating graphics for general circulation or for an organization that has strict branding guidelines. The code looks a lot longer because I included a second graph of Sepal Length to show the application of the global parameters, but the code essentially has the same three sections: the parameters, the plot, and the legend. You can see that I didn’t make any major changes with respect to the plots, I just added attributes to customize the colors, fonts, and font sizes of my graph.
One important change between these graphs and the ones in the first section is in the par() function at the beginning. Adding attributes to specify the font, font size, and color here creates ‘global’ settings for your plot, allowing all your following graphs to shed that crunchy 1980’s R look. The attributes I’ve added are:
font: font in the par() expression changes the font for items outside of the plot function. In this case, it is applying to the legend but it will also apply to any margin text you may have.
font.axis: the font of the axis value labels.
fg: the color of the foreground, meaning text and graph outlines.
col.axis: the color of the axis ticks and text.
cex.axis: the size of the axis ticks and text, relative to the default value of 1.
I also added a few similar attributes to the plot section of the code:
font.lab: specifies the font of your labels
col.lab: specifies the color of your labels
font.main: specifies the font of your main title
col.main: specifies the color of your main title
These attributes are specified exactly how their parent attributes (col and font) are specified. Easy, right?
I didn’t make any changes to the legend; the par() function did that for me.
##global settingspar(mfrow = c(1,2), mar = c(5,5,4,1),font = 7,font.axis = 7,     fg = "azure4",  col.axis = "azure4", cex.axis = .75)## First plot   plot(iris$Petal.Length, iris$Petal.Width,        xlab = "Petal Length",        ylab = "Petal Width",        font.lab = 7,       col.lab = "azure4",       main = "Petal Width vs Petal Length",       font.main = 7,       col.main = "black",       pch = 20,       col=ifelse(iris$Species == "setosa","coral1",                 ifelse(iris$Species == "virginica","cyan4",                        ifelse(iris$Species ==  "versicolor",                              "darkgoldenrod2", "grey"))))  ##legend  legend("bottomright", c("setosa","virginica", "versicolor"),       col = c("coral1","cyan4", "darkgoldenrod2"), pch=20)##Second plot   plot(iris$Sepal.Length, iris$Sepal.Width,      xlab = "Sepal Length",     ylab = "Sepal Width",     font.lab = 7,     col.lab = "azure4",     main = "Sepal Width vs Sepal Length",     font.main=7,     col.main = "black",     pch = 17,     col=ifelse(iris$Species == "setosa","coral1",                 ifelse(iris$Species == "virginica","cyan4",                        ifelse(iris$Species ==  "versicolor",                              "darkgoldenrod2", "grey"))))  ##legend  legend("bottomright", c("setosa","virginica", "versicolor"),       col = c("coral1","cyan4", "darkgoldenrod2"), pch=17)
Backgrounds for your charts are tricky using base plotting in R. The par() function has a background attribute, bg, but it colors the whole area of your chart the background color. For example:
par(mfrow = c(1,1), mar = c(5,5,4,1),bg = "grey") plot(iris$Petal.Length, iris$Petal.Width)
Not what we want.
In base R there is no easy way of just coloring in the background of your plot. You can use the rect function to draw a rectangle that aligns with your axis, or you can use abline. The abline function is very versatile, and using it to create a background for our graph forces us to create our plot a little differently.
We’ll build off of the work in the previous sections, adding a colored background with gridlines to our plot of petal width vs. petal length.
##global parameterspar(mfrow = c(1,1), mar = c(5,5,4,1),font = 7,font.axis = 7,    fg = "azure4",  col.axis = "azure4", cex.axis = .75) ##Create the empty plotplot(NULL, ylim=c(0,2.5),xlim=c(0,7),      xlab = "Petal Length",      ylab = "Petal Width",      font.lab = 7,     main = "Petal Width vs. Petal Length",     font.main = 7,     col.main = "black",)##Add the background colorabline(v = 0:7, col = "aliceblue", lwd = 200)abline(v = 0:7, col = "white")abline(h=0:2.5, col = "white")##Add the data pointspoints(iris$Petal.Length, iris$Petal.Width,        pch = 20,       cex = 1.5,       col=ifelse(iris$Species == "setosa","coral1",                   ifelse(iris$Species == "virginica","cyan4",                          ifelse(iris$Species ==  "versicolor",                                "darkgoldenrod2", "grey"))))##legendlegend("bottomright", c("setosa","virginica", "versicolor"),       col = c("coral1","cyan4", "darkgoldenrod2"), pch=20)
If you look at the code for this graph, you can see that it approaches plot creation a bit differently. First, it sets up an empty plot and then draws on layers of information, starting with the background color, then the data points, then the legend. The background color is created using thick ab-lines for the solid color and thin white ones for the grid:
##Add the background colorabline(v = 0:7, col = "aliceblue", lwd = 200)abline(v = 0:7, col = "white")abline(h=0:2.5, col = "white")
You can see that we’ve moved our point attributes, (the dataset, pch, and col) to the points() function, but we haven’t changed them. I did add the attribute cex to increase the size of the points.
Graphs are one of the most effective ways of communicating analysis results to any audience. Additions as simple as proper labels, subsetting data by colors or symbols, and font adjustments add both information and clarity, yet consistently we see graphics coming out of R that look like they were created thirty years ago. After putting time into cleaning, summarizing, and analyzing your data, it makes sense to spend a minute on your plots.
Below are some nice cheat sheets to help you with your customizations.
There are many ways to approach fonts in R, but here is a basic cheat sheet for the numerical values associated with different fonts using font = x.
All the code used for this article can be found here.