Transform data and create beautiful visualisation using ggplot2 | by Shubham Gupta | Towards Data Science

The purpose of creating visualisations is to explore data, find hidden trends and communicate trends. To create any visualisation we need a question that we wish to explore and we need the data which can help us answer the question. The question we will be exploring is “How has mobility pattern of people changed due to COVID-19?” and the data we will be using compares changes in baseline mobility trends at different places due to COVID-19 and is provided by Google here.
Following this tutorial will help you understand how to transform data in R and plot a stacked bar chart. Here’s the end result:
Description of columns of interest:
Country code — “country_region_code”Country name — “country_region”Change in Retail/Recreation spaces — “retail_and_recreation_percent_avg”Change in Grocery/Pharmacy spaces — “grocery_and_pharmacy_percent_avg”Change in Park spaces — “parks_percent_avg”Change in Transit station spaces — “transit_stations_percent_avg”Change in Workplace spaces — “workplaces_percent_avg”
If you are only interested in ggplot2 customisation's, please jump to Step 3.
Our data exploration journey begins:
# Importing librarieslibrary("dplyr")library("magrittr")library("plotly")library("ggplot2")library("tidyr")library("cowplot")
# Reading downloaded csvdata <- read.csv(file = 'Global_Mobility_Report.csv')# Print column names in dataframecolnames(data)
We will be creating visualisation for European countries hence we will have to filter other countries out.
# Required country codescountry_region_code <- c("GB","SK","SI","SE","RO","PT","PL","NO","NL","MT","LV","LU","LT","IT","IE","HU","HR","GR","FR","FI","ES","EE","DK","DE","CZ","BG","BE","AT")# Creating a subset using required country codessubset = data[data$country_region_code %in% country_region_code ,]# Check countries in subsetunique(subset$country_region)
In our data, we have changes in mobility trends listed for each day but we want to plot the change for entire period so we will have to aggregate data. We will do this by grouping using country_region_code and calculating mean for each of our mobility categories.
# Aggregating data to get average percent changeaggdata <- subset %>%group_by(country_region_code, country_region) %>%    summarize(retail_and_recreation_percent_avg = mean(retail_and_recreation_percent_change_from_baseline, na.rm = TRUE),              grocery_and_pharmacy_percent_avg = mean(grocery_and_pharmacy_percent_change_from_baseline, na.rm = TRUE),               parks_percent_avg = mean(parks_percent_change_from_baseline, na.rm = TRUE),               transit_stations_percent_avg = mean(transit_stations_percent_change_from_baseline, na.rm = TRUE),               workplaces_percent_avg = mean(workplaces_percent_change_from_baseline, na.rm = TRUE),               residential_percent_avg = mean(residential_percent_change_from_baseline, na.rm = TRUE))colnames(aggdata)
We will add another columns overall_mob_percent which will overall change in mobility percentage so that we can sort the data from countries with most affected mobility changes to least.
# Adding additional average change columnaggdata <- transform(aggdata, overall_mob_percent=(retail_and_recreation_percent_avg+grocery_and_pharmacy_percent_avg+      parks_percent_avg+transit_stations_percent_avg+    workplaces_percent_avg+residential_percent_avg))colnames(aggdata)
Currently our data is stored in wide format where each category of mobility change has separate column.
We will have to transform out data to long format before plotting using gather.
# Gathering dataaggdata_tsfm <- gather(aggdata, key = "parameter", value = "percent", -country_region_code, -country_region, -overall_mob_percent)colnames(aggdata_tsfm)
Ordering data.
# Sort based on overall_mob_percentaggdata_tsfm <- aggdata_tsfm[order(aggdata_tsfm$overall_mob_percent),]
Converting country_region to factor so that ordering is preserved in our plot.
# Converting to factor for preserving sequence in our visualisationaggdata_tsfm$country_region <- factor(aggdata_tsfm$country_region,  levels = unique(aggdata_tsfm$country_region))
Here, aggdata_tsfm is our dataframe, x axis has countries, y axis has percent change in mobility values and we will fill stacked bar chart with our different place categories. We’ve set position to stack to create a stacked bar chart. You could set position to dodge to create side by side bar chart. To give our bar blocks a black outline we’ve set color to black.
# Creating the plotmainplot <- ggplot(aggdata_tsfm, aes(width = 0.9, fill=parameter, y=percent, x=country_region)) +  geom_bar(position="stack", stat="identity", color="black")
Adding horizontal line to differentiate between -ve, +ve y axis since our data has positive as well as negative values along y axis.
# Adding line to differentiate -ve and +ve y axismainplot <- mainplot + geom_hline(yintercept=0, color = “white”, size=2)
Adding y ticks because by default the number of ticks is very less. Our ticks will scale from -250 to 100 increasing by 50.
# Adding y ticksmainplot <- mainplot + scale_y_continuous(breaks = round(seq(-250, max(100), by = 50),1))
We will customise legend of our plot to change color, label and order.
Instead of struggling to decide which colour palette to use, you can use ColorBrewer which provides nice colour palettes for both qualitative and quantitative data which are also optimised for colour blind people.
Once we have selected the colours, we can use them by setting values parameter. To change label names in our legend, we can set labels. To change sequence of our labels we use breaks to specify required order.
# Changes to legendmainplot <- mainplot + scale_fill_manual(name="Mobility categories",values = c("retail_and_recreation_percent_avg" = "#8dd3c7",  "grocery_and_pharmacy_percent_avg" = "#ffffb3",  "parks_percent_avg" = "#bebada",  "transit_stations_percent_avg" = "#fb8072",  "workplaces_percent_avg" = "#80b1d3",  "residential_percent_avg" = "#fdb462"),  labels=c("retail_and_recreation_percent_avg" = "Retail/Recreation",  "grocery_and_pharmacy_percent_avg" = "Grocery/Pharmacy",  "parks_percent_avg" = "Parks",  "transit_stations_percent_avg" = "Transit stations",  "workplaces_percent_avg" = "Workplaces",  "residential_percent_avg" = "Residential"),  breaks=c("residential_percent_avg", "workplaces_percent_avg",  "transit_stations_percent_avg",  "retail_and_recreation_percent_avg", "parks_percent_avg",  "grocery_and_pharmacy_percent_avg"))
Changing the title of our plot.
# plot titlemainplot <- mainplot + ggtitle(“Changes in movement of people due to COVID-19”)
Setting the subtitle and caption of our plot.
# plot subtitle, captionmainplot <- mainplot + ggtitle(“Changes in movement of people due to COVID-19”)
Setting x and y labels.
# Setting x and y labelsmainplot <- mainplot + xlab(“Countries”) + ylab(“Percent change in mobility rate across different activities”)
Since x axis has country names, we will rotate text to avoid overlap of text.
# x axis markings rotatedmainplot <- mainplot + theme(axis.text.x = element_text(angle = 90))
Changing the text size to improve readability.
# change text sizemainplot <- mainplot + theme(text = element_text(size=20))
Now we can plot the chart which we showed at the beginning.
# Plottingmainplot
Looking at the visualisation it’s easier to get inferences from data, like people’s movement at residential places has increased. Places with least negative mobility were groceries and pharmacy indicating that these places are still getting footfall but nothing like they used to.
If you wish to plot multiple charts in a grid, you can easily do it using cowplot's plot_grid. Plots resplo, parplot, recplot, groplot, traplot, andworplot are different plots for each of our categories created using same methods which we demonstrated in Step 3 above and we plot them in a grid.
# Plotting a grid of plotsplot_grid(resplot, parplot, recplot, groplot, traplot, worplot, ncol = 2, nrow = 3)
We have seen how easy it is to create powerful visualisation’s using ggplot2 and so many ways to customise your plot. We’ve barely explored ggplot2 and it has so much more to offer. I highly recommend exploring other charts and functionalities ggplot2 has to offer.
Thanks for reading.