Introduction to R and Positron

Getting started with R

14 October 2026

This workshop…

Assumes you are an absolute beginner.

Will teach you the fundamentals of working in R by walking through a ‘typical’ bioinformatics workflow.

We will work slowly and there will be repetition. You will build good habits through experience.

At the end of this course you will grasp the fundamentals and be in a good position to work with google, llms, supervisors and colleagues to solve specific problems and challenges.

Workshop aims

Chapter 2 “Whole game”

We will:

  • Introduce Positron as an IDE for code writing and to help manage all our files.

  • Import data into Positron.

  • Clean and tidy the data.

  • Visualise the data for ourselves.

  • Carry out “data wrangling” (getting the data into the shapes and formats we need).

  • Visualise the data for presentation.

Objectives for the course

  • Learn how to use Positron and Workspaces to keep work organised.

  • Learn the fundamentals of the R programming language: functions, objects and packages.

  • Develop the habit of writing readable, reproducible code.

  • Be able to interpret errors and warnings.

  • Understand the format of data in R.

  • Use the dplyr functions for data preparation and processing (“wrangling”).

  • Be able to create basic visualisations of your data.

On the topic of LLMS

  • We do not know where LLMs will be in five years.

  • We can not anticipate the price of tokens in the future.

  • Currently, LLMs are very capable of writing code.

  • Code is usually good, though not excellent.

  • Knowledge of coding remains valuable for:

    • Interpreting code

    • Phrasing questions and workflows

  • Learning new workflows/interfaces is a skill.

  • “Loss of ownership” is a very real problem.

The R programming language

  • Created in 1993 by Dr. Ross Ihaka and Dr. Robert Gentleman at the University of Auckland, Aotearoa New Zealand.
  • Widely used in statistics and biological sciences.
  • Free, flexible, supported by the community.
  • Base R was used to build packages that accomplish specific tasks.
  • Base R packages includes a mix of styles and formats.
    • Challenging to learn!

The tidyverse dialect

  • A series of packages designed from the ground up to work together.
  • Uses a consistent and logical style with a shared format.
  • Human readable, intuitive, easy to learn.
  • Highly popular, well documented, many resources available.
  • Designed by programmers for non-programmers.

The tidyverse style

Each variable stored in a column.

Each observation is stored in a row.


penguins[1:3,1:6]
  species    island bill_len bill_dep flipper_len body_mass
1  Adelie Torgersen     39.1     18.7         181      3750
2  Adelie Torgersen     39.5     17.4         186      3800
3  Adelie Torgersen     40.3     18.0         195      3250

Working with an IDE: Positron

Motivation & learning objectives

Motivation

  • An IDE brings code, output, plots and documentation together in one place
  • Positron, built on VS Code, offers one homogeneous environment for R (and Python)
  • Workspaces and good defaults support reproducible research

Learning objectives

  • Get to know Positron and its four areas
  • Apply recommended settings and discover hidden features
  • Set up a new workspace
  • Install and manage packages

Overview

Introduction

What is Positron?

Positron is a free, open-source IDE (Integrated Development Environment) built by Posit that integrates R and Python in a single tool.

Installation and setup

To participate in this course, ensure you have the following software installed and configured:

  • R
  • Positron (needs R and Python installed first)
  • Git

For detailed installation instructions, refer to the installation and setup guide.

Features

  • Workspaces to ease files organisation
  • Console to run R or Python, with syntax highlighter
  • Full support for Quarto docs & chunks
  • Viewer for data / plots / website
  • Package management pane, including devtools shortcuts for building and testing
  • Autocompletion using TAB
  • Cheatsheets
  • Git integration for versioning
  • Inline outputs (optional Quarto notebook mode)
  • Keyboard shortcuts
  • Integrated Terminal
  • Multiple, simultaneous R and Python sessions

Positron’s four areas

Four areas

Activity Bar & Explorer (left)

  • file Explorer, Search, and Extensions
  • Source Control for git integration
  • Packages management pane
  • Help and Viewer panes (for HTML output and websites)

Editor Area (top center)

  • Your main window for code development
  • Should be a Quarto doc
  • Tabs are great
  • Split the editor into columns for additional files

Panel Area (bottom center)

  • Console (R or Python), Terminal and Output tabs
  • Console output could be hidden with inline Quarto outputs
  • optional, embed a nice Terminal tab

Secondary Side Bar (right)

  • Variables, display loaded objects and their str()
  • Session, manage and switch R/Python interpreters
  • History of past commands
  • database Connections interface
  • Plots pane for graphics output

Reproducibility

Code must be reproducible over the complete process.

  • Global environments should not be saved
  • Rendering Quarto files (.qmd) solves this issue

Caution

Jupyter Notebooks cache intermediate results and require more attention.

Positron’s default is already reproducible

Unlike RStudio, Positron does not save or restore your .RData workspace by default, and never prompts you about it.

No dialogue to disable

There is nothing to switch off: sessions always start from a clean environment unless you explicitly save one yourself.

Other settings of note

Base pipe with Ctrl+Shift+M (Windows/Linux) or Shift+Cmd+M (Mac)

Inserts |> by default. Switch to %>% via the positron.r.pipe setting (Gear icon > Settings, search “Pipe”).

Code diagnostics

Toggle live diagnostics with the positron.r.diagnostics.enable setting.

Not as granular as RStudio (yet)

Positron currently offers a single on/off switch rather than RStudio’s fine-grained checklist. Third-party linters such as lintr are not yet integrated into the language server.

Positron workspaces

Workspaces and git repos

Here we introduce you to two separate, but related, topics: workspaces and git repos.

  • A workspace is a folder that stores everything relating to the project. Positron has a system for managing this process.

  • A repo (short for “repository”) is an online version of the project, containing most but not all files (no raw data for privacy reasons, no intermediate data if it can be easily recomputed).

  • We want the workspace (local) and repo (online) to be linked, so that our changes are stored and versioned.

  • In this section we will introduce workspaces and repos, and you will set up a workspace and repo. We will write code in the workspace, and you will gain experience in keeping the linked repo up to date.

The workspace-oriented approach

  • Any coding, including testing, you conduct should happen in the context of a workspace.
  • A workspace in Positron is a folder — there is no required project file (no .Rproj needed).
  • The folder you open is the reference for all paths in your project (the working directory).
  • A good project name goes a long way.
    • Make it unique!
  • There are multiple ways to start a workspace
    • Positron’s New Folder wizard (from a template)
    • Open an already existing folder
    • Clone (checkout) an existing repository

Git repositories

  • Git is a system for code versioning, usually with a remote repository (options exist: github and gitlab).

  • We can create a repository (repo) via the online interface as a starting point.

  • Repos can be public or private.

  • Repos are cloned onto a local computer.

  • Disclaimer: I personally start all my projects with a github repo.

    • Must choose a proper title

    • Prompted to create a description

    • This pre-work effort is valuable

Creating and cloning a repo

Create a new repo

Clone a new repo

Cloning a repo from Positron

Create a new repo

Open the Command Palette: (Ctrl+Shift+P on Windows/Linux, Shift+Cmd+P on Mac)

Clone a new repo

It’s your turn!

  • Create a new github repo with the name “r_intro_day_1”.

  • Give this repo a description, select add README, and choose a license (GNU General Public v3.0).

  • Under “Code”, select SSH and copy the url.

    • If you did not correctly set up your SSH key, you can use HTTPS, but this is not a secure way to work going forward.
  • In Positron, open the command palette (Cmd + Shift + P for Mac, Ctrl + Shift + P for Windows), type “Clone” and select the drop-down option.

  • You should now see your repo name on the left-hand side under Explorer.

Creating a workspace

  • Open the Command Palette (Ctrl+Shift+P on Windows/Linux, Shift+Cmd+P on Mac) and run Workspaces: New Folder from Template
  • Pick the R Project (or Python Project) template
  • Name the folder properly
  • Choose whether to initialize git and a package environment (renv)

No .Rproj file

Positron folders are plain directories: opening the folder is opening the project. If you still have an old .Rproj file lying around, Positron happily ignores it — see the migration notes.

Initialization from scratch

Good practice

Use git when starting projects from scratch, either through the wizard’s checkbox or afterwards from the Source Control view in the Activity Bar.

Starting from scratch means:

  1. Create an empty folder
  2. Open it in Positron (File > Open Folder…)
  3. Initialize git and add sub-folders as you go

Working directory set up

Avoid using setwd() and absolute file paths

What’s wrong with setwd()?1

  • setwd() set the working directory to a specific folder through an absolute file path
setwd("C:/Users/veronica.codoni/Projects/Survival_Analysis")
  • What if this folder moved to /Downloads, or onto another machine?
setwd("C:/Users/veronica.codoni/Projects/Survival_Analysis")
Error in `setwd()`:
! cannot change working directory

This approach is neither self-contained nor portable!

Positron workspaces as alternative

Start a new research project/data analysis by opening a folder as a Positron workspace

  • it helps to keep all the files together
  • it sets automatically the working directory to the workspace folder
  • it helps resolve file path issues by using relative paths

Opening a folder as a workspace in Positron assures the project directory to be stand-alone and portable.

Your turn: Create a workspace

Use File > Open Folder…, or the Command Palette’s Workspaces: New Folder.

  • Always name the projects properly

  • Keeping names concise, no spaces

  • Once the folder is created, opening it is the project — Positron sets the working directory automatically.

Exercise

  • You can create a new folder called dummy-project
    • in a new folder
    • enable git
  • Create sub-folders data and R.
  • Standard practice is to include an R/ folder for code, similar to src and bin directories.

Learn to switch between workspaces

We will not use this directory in this course any more, hence the name.

How your project directory should not look like

├── analysis.R
├── analusis_2.R
├── analusis4.R
├── parse_data.sh
├── tools  #<< environment
│   ├── FACS.exe
│   ├── plink1.09
│   ├── plink1.7
│   ├── plink2.0
│   └── R2.9
├── mydata #<< see next lecture
│   ├── facs.xlsx
│   └── single-cells.txt
├── old_scripts/
│   ├── analysis_final.R
│   ├── analysis_final_2.R
│   ├── analysis_tmp.R
│   └── analysis_final_nature.R
├── Analysis-international_frontiers_biomedical-Machine_learning.R # IF 3.011!
├── Manuscript_2015-oct.docx
├── Manuscript_15-oct2.docx
├── Manuscript_15-oct2-PI.docx
└── Manuscript_Sept-2015.docx

Directory setup

A standard setup

├── .git/         #<< code versioning
├── .gitignore
├── R
│   ├── functions.R
│   └── utils.R
├── data/
├── renv/         #<< environment
├── renv.lock     #<< environment
├── README.md     #<< Project information
└── report.qmd    #<< Quarto (supersedes analysis.R)

Keeping things tidy

  • How to keep older versions of scripts?
  • How not to lose good, working code when changing things?
  • How to share code with others for collaboration?

Version control

Code versioning systems support you in all of these use cases.

Quarto documents for work and reporting

  • Quarto (.qmd) documents are where we write, test, and develop our code.

  • .qmd files make code more reproducible:

    • saveable

    • ‘renders’ into a document with embedded images

    • human readable, easy to work with

  • Quarto documents have a lot of functionality (e.g., this document was created with quarto), but we don’t have time to cover it here.

  • In this workshop we use .qmd files for storing our own code.

  • Use the command palette and search “New Quarto” to open a new .qmd file.

Packages

Reliable: packages are checked during submission process

install.packages("tidyverse")

Dedicated to biology research {limma} example

Requires dedicated package BiocManager for installation.

Typical install

# install.packages("BiocManager")
BiocManager::install("limma")

Install with the remotes package.

# install.packages("remotes")
remotes::install_github("tidyverse/readr")

Installing random packages from github can be a security issue

Package installation

CRAN install from Positron’s Packages pane (autocompletion)

CRAN install from Positron’s R console

Help pages

  • Two ways to access manual pages in R
?log
help(log)

In Positron, help page appears in a sidebar to the right.

  • Help pages can be cryptic or overly technical.

  • For clearer guidance, check:

Let’s write and run some R code

We will write and run code directly from the quarto document we just opened (with Cmd / Cntrl + Shift P, “New Quarto”).

We store all code in “chunks”. To add a chunk, put the cursor in the document (below the pairs of dashes). Then use Cmd + Shift + I (mac)

To run a code chunk, place the cursor anywhere on one of the lines you want to run and use Cmd + Return (mac) or Cntrl + Enter (windows).

Code chunks cont

We should see the code and the output appear in the console.

This is how we work in R: write code in a document, run the code, output is either displayed on the screen or saved as files.

It’s your turn!

Buttons are slow - use shortcuts!

Use either Cmd + Shift + i (Mac) or Ctrl + Alt + i (Windows) to add a new code chunk.

In the new chunk write:

6 + 6
[1] 12
4 * 12
[1] 48

Click anywhere on the line that says 6 + 6 and use command + return (Mac) or Ctrl + enter to run the code.


Save the file so that this code can be accessed later.

Committing our work to the repo I unsaved and uncommitted files

Committing our work to the repo II stage and message

Write a commit message.

Select files to stage via the +.

Once files are committed, they need to ‘synced’ or ‘pushed’ to the remote repo.

The bioinformatician’s workflow

Almost any project will include the following steps:

  • Import data

  • Exploratory analysis

  • Data wrangling

  • Visualisations and other outputs

Importing data

R is primarily used for handling ‘flat’ data: rows and columns.

The most common type of flat data file is the CSV (comma separated values).

Typically, the first row will contain column names and is referred to as the “header”. Rows underneath the header contain data for each column, with columns separated by commas.

The csv format

Importing data: setting up

First, store the data within a /data subdirectory.

Second, install and load packages for importing data.

It’s your turn!

Exercise: storing data

  • Go to https://tinyurl.com/penguinData2025. Use the download button to get a local copy of the file.

  • In your intro_to_r project directory, create a subdirectory called data.

  • Copy/move the penguin_dataset.csv file to the new data directory.

  • Then:

  • Open a new quarto document with the title “Intro to R Day 1”.

  • Save it as day_1.qmd

  • Type “## Setup” (this should appear as a heading).

  • Type “### Packages”

Packages

Packages are collections of additional data or functions that extend the R language.

We can equate packages with apps.

To use a package requires two steps:

  • Install the package from a remote repository (one-time only)

  • Load the package into Positron (every session)

Hex stickers

It’s your turn!

Install and load the tidyverse

Create a code block in your quarto doc, add the code below, and execute:

Install packages - run this the first time you work with a new package.

install.packages("tidyverse")

Load packages - run this every time you work with the package.

library(tidyverse)

Test this with (new code block):

tidyverse_packages()
 [1] "broom"         "conflicted"    "cli"           "dbplyr"       
 [5] "dplyr"         "dtplyr"        "forcats"       "ggplot2"      
 [9] "googledrive"   "googlesheets4" "haven"         "hms"          
[13] "httr"          "jsonlite"      "lubridate"     "magrittr"     
[17] "modelr"        "pillar"        "purrr"         "ragg"         
[21] "readr"         "readxl"        "reprex"        "rlang"        
[25] "rstudioapi"    "rvest"         "stringr"       "tibble"       
[29] "tidyr"         "xml2"          "tidyverse"    

Importing data

Our project dictates our current working directory. Files must be described relative to the project directory.

The read_csv function:

read_csv(file = "data/penguin_dataset.csv")

Reading the data into an object:

penguins <- read_csv(file = "data/penguin_dataset.csv")

Functions and objects

  • We can think of objects as being equivalent to files.
  • Functions do things:
    • Calculate the mean of a series of numbers.
    • Count the number of times a name has appeared in a list.
    • Rename or reorganise columns (variables) in a file.

It’s your turn!

Examine the penguins data object

There are many functions we can use to examine our data. Test these functions and draw some initial conclusions about your data.

penguins |> head()
penguins |> tail()
penguins |> View()
penguins |> summary()
penguins |> colnames()
penguins |> dim()

A small note on functions

We just saw the head() function. head() and tail() print the first, or last, six rows of the object.

head(penguins, 4)
# A tibble: 4 × 8
  species island    bill_len bill_dep flipper_len body_mass sex     year
  <chr>   <chr>        <dbl>    <dbl>       <dbl>     <dbl> <chr>  <dbl>
1 Adelie  Torgersen     39.1     18.7         181      3750 male    2007
2 Adelie  Torgersen     39.5     17.4         186      3800 female  2007
3 Adelie  Torgersen     40.3     18           195      3250 female  2007
4 Adelie  Torgersen     NA       NA            NA        NA <NA>    2007
  • Functions can be modified with arguments.

  • Most functions have defaults which are not shown. Be aware of function defaults!

The pipe

This works best if you read “|>” as “and then…”

penguins |> # Start with the penguin data AND THEN
  na.omit() |> # Remove the NAs AND THEN
  arrange(bill_len) |>  # Arrange (sort) the rows AND THEN
  head() # Keep just the head (top 6 rows)
# A tibble: 6 × 8
  species island    bill_len bill_dep flipper_len body_mass sex     year
  <chr>   <chr>        <dbl>    <dbl>       <dbl>     <dbl> <chr>  <dbl>
1 Adelie  Dream         32.1     15.5         188      3050 female  2009
2 Adelie  Dream         33.1     16.1         178      2900 female  2008
3 Adelie  Torgersen     33.5     19           190      3600 female  2008
4 Adelie  Dream         34       17.1         185      3400 female  2008
5 Adelie  Torgersen     34.4     18.4         184      3325 female  2007
6 Adelie  Biscoe        34.5     18.1         187      2900 female  2008

With the pipe we can “chain” together functions to achieve complex tasks. Notice how it is still (mostly) readable.

Write good code

What is good code?

  • Strict ‘style’: spaces around operators and commas.

  • Objects are named in lowercase and numbers, and use _ to separate.

  • One function per line (generally).

  • Pipes are at the end of a line and are preceded by spaces. After a pipe, indent (automatic).

  • Add comments! Document your work.

Errors and warnings

Positron will (very) regularly provide you with two types of feedback:

  • Errors, which tell you something has failed and must be addressed.
    • Identify the error and change your code.
    • Initially you will make many spelling and typing errors - R is very fussy!
    • Alternatively, find a new approach.

Warnings

  • Warnings, which tell something has happened and you should be aware of it.
    • There is a new version of the software you are using.
    • Two packages you are using may contradict one another.
    • NAs were removed or ignored when performing a function.

It’s your turn!

Interpreting errors and warnings

Run the following functions and identify what the problem is and what you need to do to fix it.

library(heatmap)
penguins2 <- read_csv(file = "penguins_dataset.csv")
penguins |> mean(flipper_len)
my_variable <- 0983
my_varıable

Exploratory analysis

What do you do when you get new data?

Need to understand the format, shape, type.

Are numerical values normally distributed? Are there outliers? Do we have batch effects?

Exploring the penguins dataset

Use the glimpse() function to look at the penguins dataset.

What are the data types of each column? Which are categorical, which are numeric?

Use the count() function on one of the categorical variables.

Beyond numbers and words

“Far better an approximate answer to the right question, which is often vague, than an exact answer to the wrong question…”

      - John Tukey
      

“The simple graph has brought more information to the data analyst’s mind than any other device. It specializes in providing indications of unexpected phenomena”.

      - John Tukey
      

Data visualisation with ggplot


  • ggplot (“Grammar of Graphics”): work iteratively, build complexity.

  • Focus on the format.

  • Demonstrates a key loop in data analysis: visualise your data, make adjustments, transform the data and visualise again.

The ggplot format

The ggplot format has three parts:

Calling the ggplot function and specifying the data.

Mapping the data: what data is displayed on the x and y axis.

Plotting the data with a geom function - there are different geoms for different types of plots.

  • Note that the geom is a new function, which means we need to add a “+” to the previous line.

The ggplot format

ggplot(data = penguins, 
       mapping = aes(x = bill_len,
                     y = bill_dep)) +
  geom_point()

Exercise: What do you notice about the format of this code?

  • No pipes, instead objects and arguments are all inside the function bracket.

  • The “+” and/or there are two functions.

  • Comparing bill length and depth.

  • The format: indents, alignment, it’s very readable.

The ggplot format

Exercise: Interpret this graph, discuss your observations.

  • Does this data fit, approximately, with our expectations?

  • Do you observe sub-groups? If so, how many? What is a possible explanation?

It’s your turn!

Exercise: clear your screen of previous code

  • From memory, create a new plot using:

    • ggplot(), where data = penguins and

    • mapping = aes() with:

      • flipper_len on the x axis, body_mass on the y axis
    • geom_point()

    • Remember that after the ggplot() function add a “+” before geom_point()

Solution

ggplot(data = penguins,
       mapping = aes(x = flipper_len,
                     y = body_mass)) +
  geom_point()

What variable could explain the groups in this graph?

How do we address this question?

Mapping additional variables

mapping = aes() is used to map a variable to an axis.

Variables can also be mapped to axes other than x and y:

Colour, size, and shape are all axes we can map aesthetics to.

Mapping additional variables

ggplot(data = penguins,
       mapping = aes(x = bill_len,
                     y = bill_dep,
                     colour = sex)) +
  geom_point()

It’s your turn!

Exercise: Explain the sub-grouping

Using ggplot and mapping variables to colour, identify which of the categorical variables in penguins best explains the sub-grouping we observe in bill depth vs length.

Hints:

  • glimpse() and summary() are useful functions for looking at your data.

  • Even if you have found a variable that looks like it explains your data, did you check whether other variables also look like they explain the data?

Hypothesis: You cannot imagine a plot that can’t be made with ggplot

Challenge: I challenge you to clearly describe a plot or visualization that cannot be created in ggplot. There is a prize available.

Conditions:

  • You must be able to describe this clearly, to the point where we as a group all agree on what you are requesting.

  • This must be a plausible static visualization (i.e., no 3-dimensional, sound-producing scifi graph).

  • You must give us your description by the start of Day 2 at the latest, and you must give us your description as soon as you come up with it.

  • No LLMs.

  • If, by the end of our final day, I haven’t been able to build OR find a plot that represents data as per your description, you win.

Before we stop

You learned about:

  • Positron
    • Basic functionality
    • Recommended settings
    • Workspace setup
  • R and the tidyverse
  • Functions and objects
  • ggplot

Acknowledgments

  • Hadley Wickham (Posit)
  • Kevin Ushey (renv)
  • Romain François
  • Jenny Bryan (File organization)

Contributors

  • Tyler McInnes
  • Roland Krause
  • Aurélien Ginolhac
  • Veronica Codoni