How to Make Stunning Line Charts in R: A Complete Guide with ggplot2

By:
Dario Radečić
December 15, 2020

<h2><span data-preserver-spaces="true">ggplot2 Line Charts</span></h2>
<em><strong>Updated</strong>: June 2, 2022.</em>

<span data-preserver-spaces="true">Are your visualizations an eyesore? The 1990s are over, pal. Today you'll learn how to make impressive <code>ggplot2</code> line charts with R. Terrible-looking visualizations are no longer acceptable, no matter how useful they might otherwise be. Luckily, there's a lot you can do to quickly and easily enhance the aesthetics of your visualizations. </span>

Read more on our ggplot series:
<ul><li><a title="How to Make Stunning Bar Charts with R" href="https://wordpress.appsilon.com/ggplot2-bar-charts/" target="_blank" rel="noopener noreferrer">Bar Charts with R</a></li><li><a href="https://appsilon.com/ggplot-scatter-plots/" target="_blank" rel="noopener noreferrer">Scatter Plots with R</a></li><li><a href="https://appsilon.com/ggplot2-boxplots/" target="_blank" rel="noopener noreferrer">Boxplots with R</a></li></ul>
<span data-preserver-spaces="true">This article demonstrates how to make an aesthetically-pleasing line chart for any occasion. After reading, visualizing time series and similar data should become second nature. </span><span data-preserver-spaces="true">Today you'll learn how to:</span>
<ul><li><a href="#first-bar-chart">Make your first line chart</a></li><li><a href="#color-line-marker">Change color, line type, and add markers</a></li><li><a href="#title-subtitle-caption">Add titles, subtitles, and captions</a></li><li><a href="#axis-labels">Edit and style axis labels</a></li><li><a href="#multiple-lines">Draw multiple lines on a single chart</a></li><li><a href="#labels">Add labels</a></li><li><a href="#area-fill">Add conditional area fill</a></li></ul>

<hr />

<h2 id="first-bar-chart"><span data-preserver-spaces="true">Make Your First ggplot2 Line Chart</span></h2>
<span data-preserver-spaces="true">R has a <code>gapminder</code> package you can download. It contains data on life expectancy, population, and GDP between 1952 and 2007. It's a time-series dataset, which is excellent for line-based visualizations.</span>

<span data-preserver-spaces="true">Here's how to load it (and other libraries):</span>
<pre><code class="language-r">library(dplyr)
library(ggplot2)
library(gapminder)
<br>head(gapminder)</code></pre>
<span data-preserver-spaces="true">Calling the <code>head()</code> function outputs the first six rows of the dataset. Here's how they look:</span>

<img class="size-full wp-image-6220" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b27078adeb0800875a3f31_1-2.webp" alt="Image 1 - Head of Gapminder dataset" width="842" height="278" /> <em>Image 1 - Head of Gapminder dataset</em>

<span data-preserver-spaces="true">R's widely used package for data visualization is <code>ggplot2</code>. It's based on the layering principle. The first layer represents the data, and after that comes a visualization layer (or layers). These two are mandatory for any chart type, and line charts are no exception. You'll learn how to add additional layers later.</span>

<span data-preserver-spaces="true">Your first chart will show the population over time for the United States. Columns <code>year</code> and <code>pop</code> are placed on X-axis and Y-axis, respectively:</span>
<pre><code class="language-r">usa &lt;- gapminder %&gt;%
 filter(continent == "Americas", country == "United States")
<br>ggplot(usa, aes(x = year, y = pop)) +
 geom_line()</code></pre>
<span data-preserver-spaces="true">Here's the corresponding visualization:</span>

<img class="size-full wp-image-6221" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b27079c6e8a966546ee785_2-2.webp" alt="Image 2 - Population growth over time in the United States" width="2312" height="1378" /> <em>Image 2 - Population growth over time in the United States</em>

<span data-preserver-spaces="true">The visualization is informative but as ugly as they come. The following sections will show you how to tweak the visuals.</span>
<h2 id="color-line-marker"><span data-preserver-spaces="true">Change Color, Line Type, and Add Markers to ggplot2 Line Charts</span></h2>
<span data-preserver-spaces="true">Keeping the default styling is the worst thing you can do. With the <code>geom_line()</code> layer, you can change the following properties:</span>
<ul><li><span data-preserver-spaces="true"><code>color</code> - line color</span></li><li><span data-preserver-spaces="true"><code>size</code> - line width</span></li><li><span data-preserver-spaces="true"><code>linetype</code> - maybe you want dashed lines?</span></li></ul>
<span data-preserver-spaces="true">Here's how to make a thicker dashed blue line:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = pop)) +
 geom_line(linetype = "dashed", color = "#0099f9", size = 2)</code></pre>
<img class="size-full wp-image-6222" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b39ca5a6b7fdabfb6a3df0_3-2.webp" alt="Image 3 - Changing line style, width, and color" width="2312" height="1378" /> <em>Image 3 - Changing line style, width, and color</em>

<span data-preserver-spaces="true">Better, but not quite there yet. Most line charts combine lines and points to make the result more appealing. Here's how to add points (markers) to yours:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = pop)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5)</code></pre>
<img class="size-full wp-image-6223" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b2707960ce4d025acdc64c_4-2.webp" alt="Image 4 - Line chart with markers" width="2312" height="1378" /> <em>Image 4 - Line chart with markers</em>

<span data-preserver-spaces="true">Now the charts are getting somewhere - but there's still a lot to do.</span>
<h2 id="title-subtitle-caption"><span data-preserver-spaces="true">Add Titles, Subtitles, and Captions to ggplot2 Line Charts</span></h2>
<span data-preserver-spaces="true">You can't have a complete chart without at least a title. A good subtitle can come in handy for extra information, and a caption is a good place to cite your sources. </span><span data-preserver-spaces="true">The most convenient way to add these is through a <code>labs()</code> layer. It takes in values for <code>title</code>, <code>subtitle</code>, and <code>caption</code>. </span>

<span data-preserver-spaces="true">Here's how to add all three, without styles:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = lifeExp)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 labs(
   title = "Average life expectancy in US",
   subtitle = "Data from 1952 to 2007",
   caption = "Source: Gapminder dataset"
 )</code></pre>
<img class="size-full wp-image-6224" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b2707a9551644329c1d861_5-2.webp" alt="IMAGE 5; Image 5 - Title, subtitle, and caption with default styles" width="2312" height="1378" /> <em>Image 5 - Title, subtitle, and caption with default styles</em>

<span data-preserver-spaces="true">But there's more to this story. You can customize all three in the same way - by putting styles to the <code>theme()</code> layer. Here's how to center title and caption, left align and italicize the caption, and make the title blue:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = lifeExp)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 labs(
   title = "Average life expectancy in US",
   subtitle = "Data from 1952 to 2007",
   caption = "Source: Gapminder dataset"
 ) +
 theme(
   plot.title = element_text(color = "#0099f9", size = 20, face = "bold", hjust = 0.5),
   plot.subtitle = element_text(size = 13, face = "bold", hjust = 0.5),
   plot.caption = element_text(face = "italic", hjust = 0)
 )</code></pre>
<img class="size-full wp-image-6225" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b39ca765310fcff06fdd80_6-2.webp" alt="Image 6 - Styling title, subtitle, and caption" width="2312" height="1378" /> <em>Image 6 - Styling title, subtitle, and caption</em>

<span data-preserver-spaces="true">That's all great, but what about the axis labels? Let's see how to tweak them next.</span>
<h2 id="axis-labels"><span data-preserver-spaces="true">Edit Axis Labels</span></h2>
<span data-preserver-spaces="true">Just take a look at the Y-axis for the previous year vs. population charts. The ticks look horrible. Scientific notation doesn't help make things easier to read. The following snippet puts "M" next to the number - indicates "Millions":</span>
<pre><code class="language-r">library(scales)
<br>ggplot(usa, aes(x = year, y = pop)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 scale_y_continuous(
   labels = unit_format(unit = "M", scale = 1e-6)
 )</code></pre>
<img class="size-full wp-image-6226" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270afdb0a4377ef3e4074_7-1.webp" alt="Image 7 - Changing axis ticks" width="2312" height="1378" /> <em>Image 7 - Changing axis ticks</em>

<span data-preserver-spaces="true">But what if you want a bit more space on top and bottom? You can specify where the axis starts and ends. Here's how:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = pop)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 expand_limits(y = c(125000000, 325000000)) +
 scale_y_continuous(
   labels = unit_format(unit = "M", scale = 1e-6)
 )</code></pre>
<img class="size-full wp-image-6227" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b2706d5f867c2801dc5711_8-1.webp" alt="Image 8 - Changing limits of the axis" width="2312" height="1378" /> <em>Image 8 - Changing limits of the axis</em>

<span data-preserver-spaces="true">The <code>labs()</code> layer takes in values for <code>x</code> and <code>y</code> - these determine the text shown on the X and Y axes, respectively. You can tweak the styles for axis labels the same way you did with the title, subtitle, and caption. The snippet below shows how:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = pop)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 scale_y_continuous(
   labels = unit_format(unit = "M", scale = 1e-6)
 ) +
 labs(
   x = "Year",
   y = "Population"
 ) +
 theme(
   axis.title.x = element_text(color = "#0099f9", size = 16, face = "bold"),
   axis.title.y = element_text(color = "#0099f9", size = 16, face = "italic")
 )</code></pre>
<img class="size-full wp-image-6228" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270a69c5dda5a10df4d60_9-1.webp" alt="Image 9 - Changing X and Y axis labels" width="2312" height="1378" /> <em>Image 9 - Changing X and Y axis labels</em>

<span data-preserver-spaces="true">And that's it for styling axes! Let's see how to show multiple lines on the same chart next.</span>
<h2 id="multiple-lines"><span data-preserver-spaces="true">Draw Multiple Lines on the Same Chart</span></h2>
<span data-preserver-spaces="true">Showing multiple lines on a single chart can be useful. We'll use it to compare average life expectancy between major North American countries - the United States, Canada, and Mexico.</span>

<span data-preserver-spaces="true">To display multiple lines, you can use the <code>group</code> attribute in the data aesthetics layer. Here's an example:</span>
<pre><code class="language-r">north_big &lt;- gapminder %&gt;%
 filter(continent == "Americas", country %in% c("United States", "Canada", "Mexico"))
<br>ggplot(north_big, aes(x = year, y = lifeExp, group = country)) +
 geom_line(aes(color = country), size = 2)</code></pre>
<img class="size-full wp-image-6229" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270a76ce2de24c51f767e_10-1.webp" alt="Image 10 - Average life expectancy among major North American countries" width="2312" height="1378" /> <em>Image 10 - Average life expectancy among major North American countries</em>

<span data-preserver-spaces="true">In case you're wondering how to add markers to multiple lines - the procedure is identical as it was for a single one. Take a look at the code snippet and image below:</span>
<pre><code class="language-r">ggplot(north_big, aes(x = year, y = lifeExp, group = country)) +
 geom_line(aes(color = country), size = 2) +
 geom_point(aes(color = country), size = 5)</code></pre>
<img class="size-full wp-image-6230" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270a847fb584fdd1d0b63_11-1.webp" alt="Image 11 - Adding markers to multiple lines" width="2312" height="1378" /> <em>Image 11 - Adding markers to multiple lines</em>

<span data-preserver-spaces="true">There's a legend right next to the plot because of multiple lines on a single chart. You wouldn't know which line represents what without it. Still, it's position on the right might be irritating for some use cases. Here's how to put it on the top:</span>
<pre><code class="language-r">ggplot(north_big, aes(x = year, y = lifeExp, group = country)) +
 geom_line(aes(color = country), size = 2) +
 geom_point(aes(color = country), size = 5) +
 theme(legend.position = "top")</code></pre>
<img class="size-full wp-image-6231" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d5cf376b1fc40b7399cd_117b517e_12-1.webp" alt="Image 12 - Changing the legend position" width="2312" height="1378" /> <em>Image 12 - Changing the legend position</em>

<span data-preserver-spaces="true">You've learned a lot until now, but there's still one important topic to cover - labels.</span>
<h2 id="labels"><span data-preserver-spaces="true">Adding Labels to ggplot2 Line Charts</span></h2>
<span data-preserver-spaces="true">If there aren't too many data points on a line chart, it can be useful to add labels showing the exact values. Be careful with them - they can make your visualization messy fast. </span>

<span data-preserver-spaces="true">Here's how to plot average life expectancy in the United States and show text on top of the line:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = lifeExp)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 geom_text(aes(label = lifeExp))</code></pre>
<img class="size-full wp-image-6232" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d5cfe4ab0fdeecf95b83_14efd318_13-1.webp" alt="Image 13 - Adding text" width="2312" height="1378" /> <em>Image 13 - Adding text</em>

<span data-preserver-spaces="true">A couple of problems, though. The labels are a bit small, and they are positioned right on top of the markers. The code snippet below makes the text larger and pushes them a bit higher:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = lifeExp)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 geom_text(
   aes(label = lifeExp),
   nudge_x = 0.25,
   nudge_y = 0.25,
   check_overlap = TRUE,
   size = 5
 )</code></pre>
<img class="size-full wp-image-6233" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270f06ce2de24c51fa832_14-1.webp" alt="Image 14 - Styling text" width="2312" height="1378" /> <em>Image 14 - Styling text</em>

<span data-preserver-spaces="true">Showing text might not be the cleanest solution every time. Maybe you want text wrapped inside a box to give your visualization a touch more style. You can do that by replacing <code>geom_text()</code> with <code>geom_label()</code>. That's the only change you need to make:</span>
<pre><code class="language-r">ggplot(usa, aes(x = year, y = lifeExp)) +
 geom_line(color = "#0099f9", size = 2) +
 geom_point(color = "#0099f9", size = 5) +
 geom_label(
   aes(label = lifeExp),
   nudge_x = 0.25,
   nudge_y = 0.25,
   check_overlap = TRUE
 )</code></pre>
<img class="size-full wp-image-6234" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270f06a0bfbbcc59fd3c2_15-1.webp" alt="Image 15 - Replacing text with labels" width="2312" height="1378" /> <em>Image 15 - Replacing text with labels</em>
<h2 id="area-fill">Add Conditional Area Fill to ggplot2 Line Charts</h2>
When dealing with multiple lines on a single chart, sometimes you'll want the area between the individual lines filled. The good news is - it's quite an easy thing to do with R and ggplot2. We'll show you a comparison of GDP per capita between Poland and Romania over time as individual lines, and we'll fill the area between the lines. Why? Well, it improves the overall aesthetics of the data visualization, and also makes differences easier to spot.

First things first, you'll have to install an additional R package. It extends the capabilities of ggplot2 by adding additional functions - one of them being <code>stat_difference()</code>:
<pre><code class="language-r">install.packages("ggh4x")</code></pre>
Now we'll have to do some magic with data formatting. It's a best practice to have a common feature in the dataset (year), and to represent data for each line as an individual column. In a nutshell, we'll have 3 columns - year, GDP for Poland, and GDP for Romania:
<pre><code class="language-r">pol_rom &lt;- gapminder %&gt;%
 filter(country %in% c("Poland", "Romania")) %&gt;%
 select(year, country, gdpPercap) %&gt;%
 pivot_wider(names_from = country, values_from = gdpPercap)
<br>head(pol_rom)</code></pre>
Here's what the dataset looks like:

<img class="size-full wp-image-13196" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b0215ae6755ca41b31696f_Screenshot-2022-06-02-at-09.42.37.webp" alt="Image 16 - Reformatted GDP dataset" width="386" height="304" /> Image 16 - Reformatted GDP dataset

Adding a conditional area fill is a child's play from this point:
<pre><code class="language-r">ggplot(pol_rom, aes(x = year)) +
 geom_line(aes(y = Poland, color = "Poland")) +
 geom_line(aes(y = Romania, color = "Romania")) +
 stat_difference(aes(ymin = Romania, ymax = Poland), alpha = 0.3)</code></pre>
<img class="size-full wp-image-13198" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b0215ba20f7e6672b81d9e_Screenshot-2022-06-02-at-09.34.07.webp" alt="Image 17 - ggplot2 line chart with filled area" width="2382" height="1602" /> Image 17 - ggplot2 line chart with a filled area

<span data-preserver-spaces="true">And that's all you really need to know about labels and line charts for today. Let's wrap things up next. </span>

<hr />

<h2><span data-preserver-spaces="true">Conclusion</span></h2>
<span data-preserver-spaces="true">Today you've learned how to make line charts and how to make them aesthetically pleasing. You've learned how to change colors, line width and type, titles, subtitles, captions, axis labels, and much more. </span><span data-preserver-spaces="true">You are now ready to include line charts in your reports and dashboards. You can expect more basic R tutorials weekly (usually on Sundays) and more advanced tutorials throughout the week. Fill out the subscribe form below so you never miss an update.</span>
<blockquote><strong>Are you completely new to R but have some programming experience? <a class="editor-rtfLink" href="https://wordpress.appsilon.com/r-for-programmers/" target="_blank" rel="noopener noreferrer">Check out our detailed R guide for programmers.</a></strong></blockquote>
Learn More:
<ul><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/how-i-built-an-interactive-shiny-dashboard-in-2-days-without-any-experience-in-r/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">How Our Project Leader Built Her First Shiny Dashboard with No R Experience</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/shiny-dashboard-ui-crash-course/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">A crash course in R Shiny UI</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/rapid-internationalization-of-shiny-apps-shiny-i18n-version-0-2/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">How to translate R Shiny dashboards</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/shiny-worker-package/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">How to make R Shiny faster</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/how-to-scale-a-shiny-dashboard/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">How to scale R Shiny dashboards</span></a></li></ul>

Have the latest in R/Shiny and data science delivered weekly in your inbox. Subscribe to our newsletter today.

Have questions or insights?

Engage with experts, share ideas and take your data journey to the next level!

Is Your Software GxP Compliant?

Download a checklist designed for clinical managers in data departments to make sure that software meets requirements for FDA and EMA submissions.
Explore Possibilities

Share Your Data Goals with Us

From advanced analytics to platform development and pharma consulting, we craft solutions tailored to your needs.

Talk to our Experts
r
data visualization
ggplot2
tutorials