Site icon R-bloggers

Quick dataViz techniques for nicer line charts with ggplot

[This article was first published on Albert Rapp, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

  • Line charts are one of the most fundamental chart type out there. That’s why there’s a lot of tips for line charts out there. Today, I’m going to walk you through a couple of techniques that you can use to make your line chart nicer. Here, I’ll provide you with all the code chunks. All explanations can be found in my corresponding YT video:

    < section id="get-the-data" class="level2">

    Get the data

    library(tidyverse)
    sp500_data_wide <- gt::sp500 |>
      select(date, open, close) |> 
      filter(year(date) == 2014, month(date) == 1)
    sp500_data_wide
    ## # A tibble: 21 × 3
    ##    date        open close
    ##    <date>     <dbl> <dbl>
    ##  1 2014-01-31 1791. 1783.
    ##  2 2014-01-30 1777. 1794.
    ##  3 2014-01-29 1790. 1774.
    ##  4 2014-01-28 1783  1792.
    ##  5 2014-01-27 1791. 1782.
    ##  6 2014-01-24 1827. 1790.
    ##  7 2014-01-23 1842. 1828.
    ##  8 2014-01-22 1845. 1845.
    ##  9 2014-01-21 1841. 1844.
    ## 10 2014-01-17 1844. 1839.
    ## # ℹ 11 more rows
    < section id="bring-into-a-nice-format-for-ggplot" class="level2">

    Bring into a nice format for ggplot

    sp500_data <- sp500_data_wide |> 
      pivot_longer(
        cols = -date,
        names_to = 'type',
        values_to = 'price'
      )
    < section id="create-a-basic-line-chart" class="level2">

    Create a basic line chart

    sp500_data |> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25)

    < section id="apply-a-theme" class="level2">

    Apply a theme

    sp500_data |> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank()
      )

    < section id="use-nicer-colors" class="level2">

    Use nicer colors

    sp500_data |> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank()
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) 

    < section id="use-meaningful-labels" class="level2">

    Use meaningful labels

    sp500_data |> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank()
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) +
      labs(
        x = element_blank(), 
        y = element_blank(),
        title = 'SP500 Prices in January 2014'
      ) 

    < section id="make-labels-into-currency" class="level2">

    Make labels into currency

    sp500_data |> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank()
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) +
      labs(
        x = element_blank(), 
        y = element_blank(),
        title = 'SP500 Prices in January 2014'
      ) +
      scale_y_continuous(
        labels = scales::label_dollar()
      )

    < section id="use-direct-labels-instead-of-legend" class="level2">

    Use direct labels instead of legend

    sp500_data |> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25) +
      geom_text(
        data = sp500_data |> slice_head(n = 1, by = type),
        aes(label = type),
        hjust = 0,
        vjust = 0,
        family = 'Source Sans Pro',
        size = 10,
        nudge_x = 0.1
      ) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank(),
        legend.position = 'none'
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) +
      labs(
        x = element_blank(), 
        y = element_blank(),
        title = 'SP500 Prices in January 2014'
      ) +
      scale_y_continuous(
        labels = scales::label_dollar()
      ) +
      scale_x_date(
        limits = c(
          make_date(2014, 1, 1), 
          make_date(2014, 2 ,3)
        )
      )

    < section id="make-nicer-labels" class="level2">

    Make nicer labels

    sp500_data_with_nicer_labels <- sp500_data |> 
      mutate(
        type = if_else(
          type == 'open',
          'Opening price',
          'Closing price'
        )
      ) 
    
    sp500_data_with_nicer_labels|> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25) +
      geom_text(
        data = sp500_data_with_nicer_labels |> 
          slice_head(n = 1, by = type),
        aes(label = type),
        hjust = 0,
        vjust = 0,
        family = 'Source Sans Pro',
        size = 10,
        nudge_x = 0.1
      ) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank(),
        legend.position = 'none'
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) +
      labs(
        x = element_blank(), 
        y = element_blank(),
        title = 'SP500 Prices in January 2014'
      ) +
      scale_y_continuous(
        labels = scales::label_dollar()
      ) +
      scale_x_date(
        limits = c(
          make_date(2014, 1, 1), 
          make_date(2014, 2, 8)
        )
      )

    < section id="place-labels-closer-to-the-lines" class="level2">

    Place labels closer to the lines

    sp500_data_with_nicer_labels |> 
      ggplot(aes(date, price, col = type)) +
      geom_line(linewidth = 1.25) +
      geomtextpath::geom_textline(
        data = sp500_data_with_nicer_labels |> 
          filter(type == 'Opening price'),
        aes(label = type),
        hjust = 0.76,
        vjust = 0,
        family = 'Source Sans Pro',
        size = 8
      ) +
      geomtextpath::geom_textline(
        data = sp500_data_with_nicer_labels |> 
          filter(type == 'Closing price'),
        aes(label = type),
        hjust = 0.77,
        vjust = 1,
        family = 'Source Sans Pro',
        size = 8,
        text_smoothing = 40,
        offset = unit(-14, 'mm')
      ) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank(),
        legend.position = 'none'
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) +
      labs(
        x = element_blank(), 
        y = element_blank(),
        title = 'SP500 Prices in January 2014'
      ) +
      scale_y_continuous(
        labels = scales::label_dollar()
      ) 

    < section id="highlight-area-between-lines." class="level2">

    Highlight area between lines.

    sp500_data_with_nicer_labels |> 
      ggplot(aes(date, price, col = type)) +
      ggbraid::geom_braid(
        data = sp500_data_wide, 
        aes(
          y = NULL, ## Overwrite the inherited aes from ggplot()
          col = NULL, 
          ymin = open, 
          ymax = close, 
          fill = open < close
        ), 
        alpha = 0.6
      ) +
      geom_line(linewidth = 1.25) +
      geomtextpath::geom_textline(
        data = sp500_data_with_nicer_labels |> 
          filter(type == 'Opening price'),
        aes(label = type),
        hjust = 0.76,
        vjust = 0,
        family = 'Source Sans Pro',
        size = 8
      ) +
      geomtextpath::geom_textline(
        data = sp500_data_with_nicer_labels |> 
          filter(type == 'Closing price'),
        aes(label = type),
        hjust = 0.77,
        vjust = 1,
        family = 'Source Sans Pro',
        size = 8,
        text_smoothing = 40,
        offset = unit(-14, 'mm')
      ) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank(),
        legend.position = 'none'
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) +
      scale_fill_manual(
        values = c('TRUE' = '#0072B2', 'FALSE' = '#D55E00')
      ) +
      labs(
        x = element_blank(), 
        y = element_blank(),
        title = 'SP500 Prices in January 2014'
      ) +
      scale_y_continuous(
        labels = scales::label_dollar()
      ) 
    ## `geom_braid()` using method = 'line'

    < section id="add-a-callout-label-box" class="level2">

    Add a callout label box

    sp500_data_with_nicer_labels |> 
      ggplot(aes(date, price, col = type)) +
      ggbraid::geom_braid(
        data = sp500_data_wide, 
        aes(
          y = NULL, ## Overwrite the inherited aes from ggplot()
          col = NULL, 
          ymin = open, 
          ymax = close, 
          fill = open < close
        ), 
        alpha = 0.6
      ) +
      geom_line(linewidth = 1.25) +
      geomtextpath::geom_textline(
        data = sp500_data_with_nicer_labels |> 
          filter(type == 'Opening price'),
        aes(label = type),
        hjust = 0.76,
        vjust = 0,
        family = 'Source Sans Pro',
        size = 8
      ) +
      geomtextpath::geom_textline(
        data = sp500_data_with_nicer_labels |> 
          filter(type == 'Closing price'),
        aes(label = type),
        hjust = 0.77,
        vjust = 1,
        family = 'Source Sans Pro',
        size = 8,
        text_smoothing = 40,
        offset = unit(-14, 'mm')
      ) +
      ggforce::geom_mark_circle(
        data = tibble(
          date = make_date(2014, 1, 24),
          price = 1820
        ),
        aes(
          col = NULL, 
          label = 'This area signals whether the\nclosing price or opening price was\nhigher on a given day'
        ),
        fill = 'white',
        color = 'grey20',
        alpha = 1,
        x0 = make_date(2014, 1, 13),
        y0 = 1805,
        label.family = 'Source Sans Pro',
        label.colour = 'grey20',
        label.hjust = 0,
        label.size = 12,
        label.face = 'plain',
        con.colour = 'grey20',
        con.cap = unit(1, 'mm'),
        expand = 0.011
      ) +
      theme_minimal(
        base_size = 20, 
        base_family = 'Source Sans Pro'
      ) +
      theme(
        panel.grid.minor = element_blank(),
        legend.position = 'none'
      ) +
      scale_color_manual(
        values = c('#0072B2', '#D55E00')
      ) +
      scale_fill_manual(
        values = c('TRUE' = '#0072B2', 'FALSE' = '#D55E00')
      ) +
      labs(
        x = element_blank(), 
        y = element_blank(),
        title = 'SP500 Prices in January 2014'
      ) +
      scale_y_continuous(
        labels = scales::label_dollar()
      ) 
    ## `geom_braid()` using method = 'line'

    To leave a comment for the author, please follow the link and comment on their blog: Albert Rapp.

    R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
    Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
  • Exit mobile version