Visualising data is useful not only to explore the data and identify
the relationship between different variables, but also to communicate
the result of the analysis. The ggplot2 package allows
us you to generate high quality plots in just a few lines of code. Any
ggplot plot will have at least 3 components: the data,
a coordinate system and a geometry
(the visual representation of the data) and will be built in layers.
Let’s start by making plots!
First layer: the area of the graphic
The main function of ggplot2 is precisely ggplot()
,
which allows us to start the graph and also to define the global
characteristics. The first argument of this function will be the data we
want to visualize, always in a data.frame. In this case we use
penguins
.
The second argument is called mapping
because it’s where
we define how columns of the data “map” to visual properties of the
geometries. This mapping is defined by the aes()
function.
In this case we indicate that in the x axis we want to plot the variable
bill_length_mm
and in the y-axis the variable
bill_depth_mm
.
But this alone is not enough, it only generates the first layer: the
area of the graph.
ggplot(data = penguins, mapping = aes(x = bill_length_mm, y = bill_depth_mm))
Second layer: geometries
We need to add a new layer to our chart, the geometric elements or
“geoms” that will represent the data. To do this we add a geom function,
for example if we want to represent the data with points we will use
geom_point()
.
ggplot(data = penguins, mapping = aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point()
We have our first plot!
You may have noticed that the dots are clustered in groups. Perhaps
some other variable explains this behaviour.
To include information from other variables in our plot we can take
advantage of the aesthetic characteristics of the geometries. In this
case, we can “paint” the points according to the penguin species.
ggplot(data = penguins, mapping = aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = species))
Again, we use the aes()
function to map a variable in
our data to an element of the plot. And aha! Each species of penguins
has different characteristics!
Adding geometries
Very often it is not enough to look at the raw data to identify the
relationship between variables; it is necessary to use some statistical
transformation to highlight those relationships, either by fitting a
model or calculating some statistics.
For this, ggplot2 has geoms that calculate some common statistical
transformations. Let’s try with geom_smoth()
to fit a
linear model to each species.
ggplot(data = penguins, mapping = aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = species)) +
geom_smooth(aes(color = species), method = "lm")
By default geom_smooth()
fits the data using the loess
method (local linear regression) when there are less than 1000 data. But
it is very common that you want to fit a global linear regression. In
that case, you have to set method = "lm"
.
Let’s talk about the look of the plot
For now we used the default ggplot look. We could change the look of
your plot to match the style of the institution where we work, of the
journal where we are going to publish it or simply to make it more
eye-catching.
Let’s start with colour. To change the aesthetic appearance of a plot
element, we add a new layer with the scale_*
function. In
this case we’ll use scale_color_manual()
to choose the
colours of the points manually. We could also use previously defined
colour palettes like Viridis or Color Brewer.
We’ll need 3 colors for the 3 species, let’s use
"darkorange"
, "purple"
and
"cyan4"
following the beautiful visualizations made by
Allison Horst.
ggplot(data = penguins, mapping = aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = species)) +
geom_smooth(aes(color = species), method = "lm") +
scale_color_manual(values = c("darkorange","purple","cyan4"))
We are getting there! Now, let’s add some text elements with a new
ggplot layer: labs()
.
ggplot(data = penguins, mapping = aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = species)) +
geom_smooth(aes(color = species), method = "lm") +
scale_color_manual(values = c("darkorange","purple","cyan4")) +
labs(title = "Penguin bill dimensions",
subtitle = "Bill length and depth for Adelie, Chinstrap and Gentoo, Penguins at Palmer Station LTER",
x = "Bill length (mm)",
y = "Bill depth (mm)",
color = "Penguin species",
shape = "Penguin species")
Now the axes labels are more legible and we have a title and subtitle
that explains what the plot is about.
We could keep changing this endlessly but we’ll finish with the
general look of your plot.
The overall look of a plot is defined by its theme. ggplot2 has many
themes available and for all tastes. But there are also other packages
that extend the possibilities, for example ggthemes. By default ggplot2
uses theme_grey()
, let’s try
theme_minimal()
:
ggplot(data = penguins, mapping = aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point(aes(color = species)) +
geom_smooth(aes(color = species), method = "lm") +
scale_color_manual(values = c("darkorange","purple","cyan4")) +
labs(title = "Penguin bill dimensions",
subtitle = "Bill length and depth for Adelie, Chinstrap and Gentoo, Penguins at Palmer Station LTER",
x = "Bill length (mm)",
y = "Bill depth (mm)",
color = "Penguin species",
shape = "Penguin species") +
theme_minimal()
Now it’s your turn. Choose a theme you like and try it out. Also, if
you can think of a better title, modify it!
LS0tCnRpdGxlOiAiUGxvdHRpbmcgRGF0YSIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IGZhbHNlCiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFCikKbGlicmFyeSh0aWR5dmVyc2UpCgpwZW5ndWlucyA8LSByZWFkX2NzdigiZGF0YS9wZW5ndWlucy5jc3YiKQpgYGAKClZpc3VhbGlzaW5nIGRhdGEgaXMgdXNlZnVsIG5vdCBvbmx5IHRvIGV4cGxvcmUgdGhlIGRhdGEgYW5kIGlkZW50aWZ5IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBkaWZmZXJlbnQgdmFyaWFibGVzLCBidXQgYWxzbyB0byBjb21tdW5pY2F0ZSB0aGUgcmVzdWx0IG9mIHRoZSBhbmFseXNpcy4gVGhlICoqZ2dwbG90MioqIHBhY2thZ2UgYWxsb3dzIHVzIHlvdSB0byBnZW5lcmF0ZSBoaWdoIHF1YWxpdHkgcGxvdHMgaW4ganVzdCBhIGZldyBsaW5lcyBvZiBjb2RlLiBBbnkgZ2dwbG90IHBsb3Qgd2lsbCBoYXZlIGF0IGxlYXN0IDMgY29tcG9uZW50czogdGhlICoqZGF0YSoqLCBhICoqY29vcmRpbmF0ZSBzeXN0ZW0qKiBhbmQgYSAqKmdlb21ldHJ5KiogKHRoZSB2aXN1YWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIGRhdGEpIGFuZCB3aWxsIGJlIGJ1aWx0IGluIGxheWVycy4KCkxldCdzIHN0YXJ0IGJ5IG1ha2luZyBwbG90cyEKCiMjIEZpcnN0IGxheWVyOiB0aGUgYXJlYSBvZiB0aGUgZ3JhcGhpYwoKVGhlIG1haW4gZnVuY3Rpb24gb2YgZ2dwbG90MiBpcyBwcmVjaXNlbHkgYGdncGxvdCgpYCwgd2hpY2ggYWxsb3dzIHVzIHRvIHN0YXJ0IHRoZSBncmFwaCBhbmQgYWxzbyB0byBkZWZpbmUgdGhlIGdsb2JhbCBjaGFyYWN0ZXJpc3RpY3MuIFRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGlzIGZ1bmN0aW9uIHdpbGwgYmUgdGhlIGRhdGEgd2Ugd2FudCB0byB2aXN1YWxpemUsIGFsd2F5cyBpbiBhIGRhdGEuZnJhbWUuIEluIHRoaXMgY2FzZSB3ZSB1c2UgYHBlbmd1aW5zYC4KClRoZSBzZWNvbmQgYXJndW1lbnQgaXMgY2FsbGVkIGBtYXBwaW5nYCBiZWNhdXNlIGl0J3Mgd2hlcmUgd2UgZGVmaW5lIGhvdyBjb2x1bW5zIG9mIHRoZSBkYXRhICJtYXAiIHRvIHZpc3VhbCBwcm9wZXJ0aWVzIG9mIHRoZSBnZW9tZXRyaWVzLiBUaGlzIG1hcHBpbmcgaXMgZGVmaW5lZCBieSB0aGUgYGFlcygpYCBmdW5jdGlvbi4gSW4gdGhpcyBjYXNlIHdlIGluZGljYXRlIHRoYXQgaW4gdGhlIHggYXhpcyB3ZSB3YW50IHRvIHBsb3QgdGhlIHZhcmlhYmxlIGBiaWxsX2xlbmd0aF9tbWAgYW5kIGluIHRoZSB5LWF4aXMgdGhlIHZhcmlhYmxlIGBiaWxsX2RlcHRoX21tYC4KCkJ1dCB0aGlzIGFsb25lIGlzIG5vdCBlbm91Z2gsIGl0IG9ubHkgZ2VuZXJhdGVzIHRoZSBmaXJzdCBsYXllcjogdGhlIGFyZWEgb2YgdGhlIGdyYXBoLgoKYGBge3J9CmdncGxvdChkYXRhID0gcGVuZ3VpbnMsIG1hcHBpbmcgPSBhZXMoeCA9IGJpbGxfbGVuZ3RoX21tLCB5ID0gYmlsbF9kZXB0aF9tbSkpIApgYGAKCiMjIFNlY29uZCBsYXllcjogZ2VvbWV0cmllcwoKV2UgbmVlZCB0byBhZGQgYSBuZXcgbGF5ZXIgdG8gb3VyIGNoYXJ0LCB0aGUgZ2VvbWV0cmljIGVsZW1lbnRzIG9yICJnZW9tcyIgdGhhdCB3aWxsIHJlcHJlc2VudCB0aGUgZGF0YS4gVG8gZG8gdGhpcyB3ZSBhZGQgYSBnZW9tIGZ1bmN0aW9uLCBmb3IgZXhhbXBsZSBpZiB3ZSB3YW50IHRvIHJlcHJlc2VudCB0aGUgZGF0YSB3aXRoIHBvaW50cyB3ZSB3aWxsIHVzZSBgZ2VvbV9wb2ludCgpYC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zLCBtYXBwaW5nID0gYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJpbGxfZGVwdGhfbW0pKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKV2UgaGF2ZSBvdXIgZmlyc3QgcGxvdCEgCgpZb3UgbWF5IGhhdmUgbm90aWNlZCB0aGF0IHRoZSBkb3RzIGFyZSBjbHVzdGVyZWQgaW4gZ3JvdXBzLiBQZXJoYXBzIHNvbWUgb3RoZXIgdmFyaWFibGUgZXhwbGFpbnMgdGhpcyBiZWhhdmlvdXIuIAoKVG8gaW5jbHVkZSBpbmZvcm1hdGlvbiBmcm9tIG90aGVyIHZhcmlhYmxlcyBpbiBvdXIgcGxvdCB3ZSBjYW4gdGFrZSBhZHZhbnRhZ2Ugb2YgdGhlIGFlc3RoZXRpYyBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIGdlb21ldHJpZXMuIEluIHRoaXMgY2FzZSwgd2UgY2FuICJwYWludCIgdGhlIHBvaW50cyBhY2NvcmRpbmcgdG8gdGhlIHBlbmd1aW4gc3BlY2llcy4gCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBwZW5ndWlucywgbWFwcGluZyA9IGFlcyh4ID0gYmlsbF9sZW5ndGhfbW0sIHkgPSBiaWxsX2RlcHRoX21tKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gc3BlY2llcykpCmBgYAoKQWdhaW4sIHdlIHVzZSB0aGUgYGFlcygpYCBmdW5jdGlvbiB0byBtYXAgYSB2YXJpYWJsZSBpbiBvdXIgZGF0YSB0byBhbiBlbGVtZW50IG9mIHRoZSBwbG90LiBBbmQgYWhhISBFYWNoIHNwZWNpZXMgb2YgcGVuZ3VpbnMgaGFzIGRpZmZlcmVudCBjaGFyYWN0ZXJpc3RpY3MhCgojIyBBZGRpbmcgZ2VvbWV0cmllcwoKVmVyeSBvZnRlbiBpdCBpcyBub3QgZW5vdWdoIHRvIGxvb2sgYXQgdGhlIHJhdyBkYXRhIHRvIGlkZW50aWZ5IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYWJsZXM7IGl0IGlzIG5lY2Vzc2FyeSB0byB1c2Ugc29tZSBzdGF0aXN0aWNhbCB0cmFuc2Zvcm1hdGlvbiB0byBoaWdobGlnaHQgdGhvc2UgcmVsYXRpb25zaGlwcywgZWl0aGVyIGJ5IGZpdHRpbmcgYSBtb2RlbCBvciBjYWxjdWxhdGluZyBzb21lIHN0YXRpc3RpY3MuIAoKRm9yIHRoaXMsIGdncGxvdDIgaGFzIGdlb21zIHRoYXQgY2FsY3VsYXRlIHNvbWUgY29tbW9uIHN0YXRpc3RpY2FsIHRyYW5zZm9ybWF0aW9ucy4gTGV0J3MgdHJ5IHdpdGggYGdlb21fc21vdGgoKWAgdG8gZml0IGEgbGluZWFyIG1vZGVsIHRvIGVhY2ggc3BlY2llcy4gCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBwZW5ndWlucywgbWFwcGluZyA9IGFlcyh4ID0gYmlsbF9sZW5ndGhfbW0sIHkgPSBiaWxsX2RlcHRoX21tKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gc3BlY2llcykpICsKICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBzcGVjaWVzKSwgbWV0aG9kID0gImxtIikKYGBgCgpCeSBkZWZhdWx0IGBnZW9tX3Ntb290aCgpYCBmaXRzIHRoZSBkYXRhIHVzaW5nIHRoZSBsb2VzcyBtZXRob2QgKGxvY2FsIGxpbmVhciByZWdyZXNzaW9uKSB3aGVuIHRoZXJlIGFyZSBsZXNzIHRoYW4gMTAwMCBkYXRhLiBCdXQgaXQgaXMgdmVyeSBjb21tb24gdGhhdCB5b3Ugd2FudCB0byBmaXQgYSBnbG9iYWwgbGluZWFyIHJlZ3Jlc3Npb24uIEluIHRoYXQgY2FzZSwgeW91IGhhdmUgdG8gc2V0IGBtZXRob2QgPSAibG0iYC4KCiMjIExldCdzIHRhbGsgYWJvdXQgdGhlIGxvb2sgb2YgdGhlIHBsb3QgIAoKRm9yIG5vdyB3ZSB1c2VkIHRoZSBkZWZhdWx0IGdncGxvdCBsb29rLiBXZSBjb3VsZCBjaGFuZ2UgdGhlIGxvb2sgb2YgeW91ciBwbG90IHRvIG1hdGNoIHRoZSBzdHlsZSBvZiB0aGUgaW5zdGl0dXRpb24gd2hlcmUgd2Ugd29yaywgb2YgdGhlIGpvdXJuYWwgd2hlcmUgd2UgYXJlIGdvaW5nIHRvIHB1Ymxpc2ggaXQgb3Igc2ltcGx5IHRvIG1ha2UgaXQgbW9yZSBleWUtY2F0Y2hpbmcuIAoKTGV0J3Mgc3RhcnQgd2l0aCBjb2xvdXIuIFRvIGNoYW5nZSB0aGUgYWVzdGhldGljIGFwcGVhcmFuY2Ugb2YgYSBwbG90IGVsZW1lbnQsIHdlIGFkZCBhIG5ldyBsYXllciB3aXRoIHRoZSBgc2NhbGVfKmAgZnVuY3Rpb24uIEluIHRoaXMgY2FzZSB3ZSdsbCB1c2UgYHNjYWxlX2NvbG9yX21hbnVhbCgpYCB0byBjaG9vc2UgdGhlIGNvbG91cnMgb2YgdGhlIHBvaW50cyBtYW51YWxseS4gV2UgY291bGQgYWxzbyB1c2UgcHJldmlvdXNseSBkZWZpbmVkIGNvbG91ciBwYWxldHRlcyBsaWtlIFZpcmlkaXMgb3IgQ29sb3IgQnJld2VyLiAKCldlJ2xsIG5lZWQgMyBjb2xvcnMgZm9yIHRoZSAzIHNwZWNpZXMsIGxldCdzIHVzZSBgImRhcmtvcmFuZ2UiYCwgYCJwdXJwbGUiYCBhbmQgYCJjeWFuNCJgIGZvbGxvd2luZyB0aGUgYmVhdXRpZnVsIHZpc3VhbGl6YXRpb25zIG1hZGUgYnkgQWxsaXNvbiBIb3JzdC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zLCBtYXBwaW5nID0gYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJpbGxfZGVwdGhfbW0pKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzcGVjaWVzKSkgKwogIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IHNwZWNpZXMpLCBtZXRob2QgPSAibG0iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtvcmFuZ2UiLCJwdXJwbGUiLCJjeWFuNCIpKSAKYGBgCgpXZSBhcmUgZ2V0dGluZyB0aGVyZSEgTm93LCBsZXQncyBhZGQgc29tZSB0ZXh0IGVsZW1lbnRzIHdpdGggYSBuZXcgZ2dwbG90IGxheWVyOiBgbGFicygpYC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zLCBtYXBwaW5nID0gYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJpbGxfZGVwdGhfbW0pKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzcGVjaWVzKSkgKwogIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IHNwZWNpZXMpLCBtZXRob2QgPSAibG0iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtvcmFuZ2UiLCJwdXJwbGUiLCJjeWFuNCIpKSArCiAgbGFicyh0aXRsZSA9ICJQZW5ndWluIGJpbGwgZGltZW5zaW9ucyIsCiAgICAgICBzdWJ0aXRsZSA9ICJCaWxsIGxlbmd0aCBhbmQgZGVwdGggZm9yIEFkZWxpZSwgQ2hpbnN0cmFwIGFuZCBHZW50b28sICBQZW5ndWlucyBhdCBQYWxtZXIgU3RhdGlvbiBMVEVSIiwKICAgICAgIHggPSAiQmlsbCBsZW5ndGggKG1tKSIsCiAgICAgICB5ID0gIkJpbGwgZGVwdGggKG1tKSIsCiAgICAgICBjb2xvciA9ICJQZW5ndWluIHNwZWNpZXMiLAogICAgICAgc2hhcGUgPSAiUGVuZ3VpbiBzcGVjaWVzIikgCmBgYAoKTm93IHRoZSBheGVzIGxhYmVscyBhcmUgbW9yZSBsZWdpYmxlIGFuZCB3ZSBoYXZlIGEgdGl0bGUgYW5kIHN1YnRpdGxlIHRoYXQgZXhwbGFpbnMgd2hhdCB0aGUgcGxvdCBpcyBhYm91dC4gCgpXZSBjb3VsZCBrZWVwIGNoYW5naW5nIHRoaXMgZW5kbGVzc2x5IGJ1dCB3ZSdsbCBmaW5pc2ggd2l0aCB0aGUgZ2VuZXJhbCBsb29rIG9mIHlvdXIgcGxvdC4gCgpUaGUgb3ZlcmFsbCBsb29rIG9mIGEgcGxvdCBpcyBkZWZpbmVkIGJ5IGl0cyB0aGVtZS4gZ2dwbG90MiBoYXMgbWFueSB0aGVtZXMgYXZhaWxhYmxlIGFuZCBmb3IgYWxsIHRhc3Rlcy4gQnV0IHRoZXJlIGFyZSBhbHNvIG90aGVyIHBhY2thZ2VzIHRoYXQgZXh0ZW5kIHRoZSBwb3NzaWJpbGl0aWVzLCBmb3IgZXhhbXBsZSBnZ3RoZW1lcy4gQnkgZGVmYXVsdCBnZ3Bsb3QyIHVzZXMgYHRoZW1lX2dyZXkoKWAsIGxldCdzIHRyeSBgdGhlbWVfbWluaW1hbCgpYDoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zLCBtYXBwaW5nID0gYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJpbGxfZGVwdGhfbW0pKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzcGVjaWVzKSkgKwogIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IHNwZWNpZXMpLCBtZXRob2QgPSAibG0iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtvcmFuZ2UiLCJwdXJwbGUiLCJjeWFuNCIpKSArCiAgbGFicyh0aXRsZSA9ICJQZW5ndWluIGJpbGwgZGltZW5zaW9ucyIsCiAgICAgICBzdWJ0aXRsZSA9ICJCaWxsIGxlbmd0aCBhbmQgZGVwdGggZm9yIEFkZWxpZSwgQ2hpbnN0cmFwIGFuZCBHZW50b28sICBQZW5ndWlucyBhdCBQYWxtZXIgU3RhdGlvbiBMVEVSIiwKICAgICAgIHggPSAiQmlsbCBsZW5ndGggKG1tKSIsCiAgICAgICB5ID0gIkJpbGwgZGVwdGggKG1tKSIsCiAgICAgICBjb2xvciA9ICJQZW5ndWluIHNwZWNpZXMiLAogICAgICAgc2hhcGUgPSAiUGVuZ3VpbiBzcGVjaWVzIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCj4gTm93IGl0J3MgeW91ciB0dXJuLiBDaG9vc2UgYSB0aGVtZSB5b3UgbGlrZSBhbmQgdHJ5IGl0IG91dC4gQWxzbywgaWYgeW91IGNhbiB0aGluayBvZiBhIGJldHRlciB0aXRsZSwgbW9kaWZ5IGl0IQo=