Plotting Colourful Graphs with R, RStudio and Ggplot2
The Aesthetics of Data Science
In this blog post, I demonstrate how to plot time series data and use colours to highlight a specific aspect of data. As almost all techniques, R and ggplot2 require practise and training, which I realised again today when I spent quite a bit of time struggling with getting a simple plot right.
Currently I am evaluating two systems I developed and I needed to visualize their storage and execution time demands in comparison. My goal was to create a plot for each non-functional property, the execution time and the storage demand, while each plot should depict both systems’ performance. Each system runs a set of operations, think of create, read, update and delete operations (CRUD). Now for visualizing which of these operations has the most effects on the system, I needed to colourise each operation within one graph. This is the easy part. What was more tricky is to provide for each graph a defined set of colours, which can be mapped to each instance of the variable. Things which have the same meaning in both graphs should visualized in the same way, which requires a little hack.
Install the following packages via apt
sudo apt-get install r-base r-recommended r-cran-ggplot2
and RStudio by downloading the deb – File from the project homepage.
As an example,we plan to evaluate the storage demand of two different systems and compare the results. Consider the following sample data.
# Set seed to get the same random numbers for this example set.seed(42); # Generate 200 random data records N <- 200 # Generate a random, increasing sequence of integers that we assume is the storage demand in some unit storage1 =sort(sample(1:100000, size = N, replace = TRUE),decreasing = FALSE) storage2 = sort(sample(1:100000, size = N, replace = TRUE),decreasing = FALSE) # Define the operations availabel and draw a random sample operationTypes = c('CREATE','READ','UPDATE','DELETE') operations = sample(operationTypes,N,replace=TRUE) # Create the dataframe df df id storage1 storage2 operations 1 1 24 238 CREATE 2 2 139 1755 UPDATE 3 3 158 1869 UPDATE 4 4 228 2146 READ 5 5 395 2967 DELETE 6 6 734 3252 CREATE 7 7 789 4049 DELETE 8 8 2909 4109 READ 9 9 3744 4835 CREATE 10 10 3894 4990 READ ....
We created a random data set simulating the characteristics of system measurement data. As you can see, we have a list of operations of the four types CREATE, READ, UPDATE and DELETE and a measurement value for the storage demand in both systems.
The Simple Plot
Plotting two graphs of thecolumns storage1 and storage2 is straight forward.
# Simple plot p1 <- ggplot(df, aes(x,y)) + geom_point(aes(x=id,y=storage1,color="Storage 1")) + geom_point(aes(x=id,y=storage2,color="Storage 2")) + ggtitle("Overview of Measurements") + xlab("Number of Operations") + ylab("Storage Demand in MB") + scale_color_manual(values=c("Storage 1"="forestgreen", "Storage 2"="aquamarine"), name="Measurements", labels=c("System 1", "System 2")) print(p1)
We assign for each point plot a color. Note that the color nme “Storage 1” for instance of course does not denote a color, but it assignes a level for all points of the graph. This level can be thought of as a category, which ensures that all the points which belong to the same category have the same color. As you can see at the definition of the color scale, we assign the actual color to this level there. This is the result:
A common task is to visualise categories or levels of measurement data. In this example, there are four different levels we could observe: CREATE, READ, UPDATE and DELETE.
# Plot with levels p1 <- ggplot(df, aes(x,y)) + geom_point(aes(x=id,y=storage1,color=operations)) + geom_point(aes(x=id,y=storage2,color=operations)) + ggtitle("Overview of Measurements") + labs(color="Measurements") + scale_color_manual(values=c("CREATE"="darkgreen", "READ"="darkolivegreen", "UPDATE"="forestgreen", "DELETE"="yellowgreen")) print(p1)
Instead of assigning two colours, one for each graph, we can also assign colours to the operations. As you can see in the definition of the graphs and the colour scale, we map the colours to the variable operations instead. As a result we get differently coloured points per operation, but we get these of course for both graphs in an identical fashion as the categories are the same for both measurements. The result looks like this:
Now this is obviously not what we want to achieve as we cannot differentiate between the two graphs any more.
Plotting the same Levels for both Graphs in Different Colours
This last part is a bit tricky, as ggplot2 does not allow assigning different colour schemes within one plot. There do exist some hacks for this, but the solution does not improve the readability of the code in my opinion. In order to apply different colour schemes for the two graphs while still using the categories, I appended two extra columns to the data set. If we append some differentiation between the two graphs and basically double the categories from four to eight, where each graph now uses its own four categories, we can also assign distinct colours to them.
df$operationsStorage1 <- paste(df$operations,"-Storage1", sep = '') df$operationsStorage2 <- paste(df$operations,"-Storage2", sep = '') p3 <- ggplot(df, aes(x,y)) + geom_point(aes(x=id,y=storage1,color=operationsStorage1)) + geom_point(aes(x=id,y=storage2,color=operationsStorage2)) + ggtitle("Overview of Measurements") + xlab("Number of Operations") + ylab("Storage Demand in MB") + labs(color="Operations") + scale_color_manual(values=c("CREATE-Storage1"="darkgreen", "READ-Storage1"="darkolivegreen", "UPDATE-Storage1"="forestgreen", "DELETE-Storage1"="yellowgreen", "CREATE-Storage2"="aquamarine", "READ-Storage2"="dodgerblue", "UPDATE-Storage2"="royalblue", "DELETE-Storage2"="turquoise")) print(p3)
We then assign the new column for each system individually as colour value. This ensures that each graph only considers the categories that we assigned in this step. Thus we can assign a different color scheme for wach graph and print the corresponding colours in the label (legend) next to the chart. This is the result:
Now we can see which operation was used at every measurement and still be able to distinguish between the two systems.