Module 04: Intro to Matplotlib

September 23, 2026

Intro to Scientific Python

Content covered:

  1. Connecting to GitHub with gh
  2. Collaborating with Git
    1. Branches with git switch
    2. Remotes and git push
    3. A Minimal GitHub Workflow
  3. Building a Plot in Matplotlib
  4. Building Subplots in Matplotlib
Intro to Scientific Python

By the end of this class, you will be able to:

  • Log in to GitHub from the terminal with gh auth login
  • Push local commits to a remote with git push, and describe a minimal GitHub collaboration workflow
  • Create a branch and open a pull request
  • Build and customize a plot in Matplotlib
  • Build subplots in Matplotlib
Intro to Scientific Python

1. Connecting to GitHub with gh

Intro to Scientific Python

Why We Need to Log In

Pulling from the course repo works without logging in, because it's public. Pushing to your fork is different: GitHub needs to know it's you.

GitHub doesn't accept your account password from git. Instead, we'll use GitHub's command line tool, gh, to log in once through the browser.

Intro to Scientific Python

Installing gh

gh is on conda-forge, the same channel as the rest of our tools:

conda activate gsk
conda install gh
gh --version
Intro to Scientific Python

Logging in with gh auth login

gh auth login --hostname github.com --git-protocol https --web
  1. When asked Authenticate Git with your GitHub credentials?, answer Yes
  2. Copy the one-time code shown in the terminal
  3. Press Enter, and your browser opens GitHub. Paste the code and authorize gh
Intro to Scientific Python

Checking Your Login

gh auth status

This should say you're logged in to github.com with your username.

From now on, git uses this login whenever you push, so you won't be asked for a password.

Intro to Scientific Python

2. Collaborating with Git

Intro to Scientific Python

The main branch

When you first clone a repo, you will notice that there's usually a main branch that comes with your project.

We can think of a repository as a tree and the main branch as being the trunk.

For a repo, there's only one default branch, and this is usually designated as main. Historically, this branch was called master, and you might still see some projects called that, but new projects default to their main branch being called main.

Intro to Scientific Python

Branches

Branches are used when you want to try something out on your own and you want to have your own copy of files and edits.

This is useful when you are making major edits to a project or if you want to try a new set of analyses but you aren't ready to share or commit them to the main project.

To create a new branch and switch to it:

git switch -c new_branch
Intro to Scientific Python

Branches, cont.

To switch between existing branches, drop the -c:

git switch main
git switch new_branch

git branch lists your branches and marks the one you're on with a *.

You'll also see git checkout -b new_branch in older tutorials. It does the same thing. git switch is the newer command that only deals with branches, just as git restore only deals with files.

Intro to Scientific Python

Keep main in Sync with the Course

From now on, main only holds what's in the course repo. Your own work goes on a branch.

  • main: updated only with git pull upstream main
  • personal: your in-class notes, exercises, and assignments
  • yearbook_firstname_lastname: your yearbook entry, later in class

If you commit your work on main, it no longer matches the course repo, and git pull will refuse to update it.

Intro to Scientific Python

Moving Your Work off main

If you committed Assignment 1 on main, let's move it onto personal:

git fetch upstream
git switch personal
git rebase main
git branch -f main upstream/main
git switch main

Your commits are safe on personal. When you switch back to main, your notebook disappears from the folder. It's still on personal: git switch personal brings it back.

Intro to Scientific Python

Getting Today's Module

Recall from Module 3: upstream is the course repo, and git pull brings its updates into your local clone.

cd ~/workspace/gsk-intro-scientific-python-course
git switch main
git pull upstream main
Intro to Scientific Python

git push

To send your local commits to your fork on GitHub:

git push origin personal

This pushes the commits on your local personal branch to a branch of the same name on origin, your fork.

Go to your fork on GitHub and choose personal from the branch dropdown. Your commits and your notebooks are there now.

Intro to Scientific Python

Practice (5 min)

Let's work on these questions:

  1. Run git branch to see your branches, and git log personal to see your commits.
  2. Push them to your fork with git push origin personal.
  3. Find your commits on GitHub under the personal branch of your fork.
Intro to Scientific Python

Pull Requests

A pull request (PR) is how you propose your changes to a project. You're asking the maintainers to pull your branch into their main.

On GitHub, after pushing a branch, you'll see a Compare & pull request button on your fork.

  • base repository / base: where your changes should go, the course repo (datalus-dev/...) and main
  • head repository / compare: where they come from, your fork and your branch

GitHub doesn't know our remote names, so you won't see origin or upstream there.

The maintainers can review, comment, and merge it.

Intro to Scientific Python

A Minimal GitHub Workflow

  1. git switch main and git pull upstream main: start from the latest version
  2. git switch -c my-branch: make a branch for your change
  3. Edit files, then git add and git commit
  4. git push origin my-branch: send your branch to your fork
  5. Open a pull request on GitHub
  6. After it's merged: git switch main and git pull upstream main

This is the same loop used on large open-source projects, like NumPy and Matplotlib.

Intro to Scientific Python

Contributing to the Yearbook

Let's all add an entry to this class yearbook. We will all submit a markdown file with our name firstname_lastname.md and it will contain a markdown message in its body.

First, let's create our branch from main, using your own name:

cd ~/workspace/gsk-intro-scientific-python-course
git switch main
git switch -c yearbook_firstname_lastname
Intro to Scientific Python

Contributing to the Yearbook, cont.

We can use the command touch to create an empty file.

touch yearbook/2026/firstname_lastname.md

Open the file in your editor and write a short message in Markdown. Recall the Markdown syntax from Module 3.

Intro to Scientific Python

Creating a commit (patch)

In terminal, we can stage the file we just created to git. This lets git know that a file was created and added to the project.

git add yearbook/2026/firstname_lastname.md
git commit -m "Adding Firstname Lastname to the yearbook"
Intro to Scientific Python

Pushing our Commit

To share our commit with the project, we need to push our branch with its new commit.

git push origin yearbook_firstname_lastname

Then, on GitHub, open a pull request from your branch to the course repo's main.

Intro to Scientific Python

Pulling down updates

Once the pull requests are merged, we will all sync our repos to accept the updated commits:

git switch main
git pull upstream main
Intro to Scientific Python

3. Building a Plot in Matplotlib

Intro to Scientific Python

Open Today's Notebook

We'll use this notebook, notebooks/module_04.ipynb, for the rest of class.

First, bring today's module into your personal branch. We'll look at how git rebase works in Module 5.

git switch personal
git rebase main
conda activate gsk
jupyter lab

In Jupyter Lab, open notebooks/module_04.ipynb. It has today's code and a cell for each practice question.

Intro to Scientific Python

Matplotlib is the main plotting library in Python.

It was used to generate the first image of a black hole!

🕳️🤯

Intro to Scientific Python

The most common submodule in matplotlib that you will use is pyplot. A submodule is a module that lives inside a package.

A common Python pattern for interacting with this submodule is:

import matplotlib.pyplot as plt

The keyword as works as an alias, which lets you map an import to another variable name.
We saw this when we imported numpy:

import numpy as np
Intro to Scientific Python

Let's bring together what we learned with numpy with some new functionality with matplotlib.

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
Intro to Scientific Python

Anatomy of Plotting

fig, ax = plt.subplots()
ax.plot([2, 4, 6, 8])

If only a single array is specified, plot defaults to the input array being the y-values and the x-values will default to range(len(input_array)), i.e. [0, 1, 2, 3].

Intro to Scientific Python

center

Intro to Scientific Python

Most Common Elements to Modify

  • Figure: the whole canvas
  • Axes: a single plot on the canvas
    • .plot()
    • .set_title()
    • .set_xlabel()
    • .set_ylabel()
    • .legend()
Intro to Scientific Python

Building a Plot, the Object-oriented Way

x = np.linspace(0, 2, 100)  # Sample data.

# Note that even in the OO-style, we use `.pyplot.subplots` to create the Figure.
fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')
ax.plot(x, x, label='linear')  # Plot some data on the Axes.
ax.plot(x, x**2, label='quadratic')  # Plot more data on the Axes...
ax.plot(x, x**3, label='cubic')  # ... and some more.
ax.set_xlabel('x label')  # Add an x-label to the Axes.
ax.set_ylabel('y label')  # Add a y-label to the Axes.
ax.set_title("Simple Plot")  # Add a title to the Axes.
ax.legend()  # Add a legend.
Intro to Scientific Python

There's also a simpler way to plot but it's less explicit using the pyplot directly.

plt.plot(x, x**2)
plt.title("Simple Plot")

You might come across examples using it but for now, we will use the explicit way so that we have as much control over our plots.

Ref: Simple Plot

Intro to Scientific Python

Generating Data from a Normal Distribution

Recall from Module 3: the random number generator lets us simulate data.

Let's randomly sample four sets of 100 values from a standard Normal distribution:

rng = np.random.default_rng(seed=42)
data1, data2, data3, data4 = rng.standard_normal((4, 100))

Passing (4, 100) as the size gives a 4 × 100 array, and unpacking it gives us one row per variable.

Intro to Scientific Python

Styling

We can also style the Artists, the output of the plotting function.

Here, we are going to define the color, width, and style of different line plots.

fig, ax = plt.subplots(figsize=(5, 2.7))
x = np.arange(len(data1))
ax.plot(x, np.cumsum(data1), color='blue', linewidth=3, linestyle='--')
l, = ax.plot(x, np.cumsum(data2), color='orange', linewidth=2)
l.set_linestyle(':')

ax.plot returns a list of lines. The trailing comma in l, = unpacks its one line into l, so we can modify it afterwards.

Intro to Scientific Python

Other Plot Types

.plot() draws lines, but the Axes has methods for many other kinds of plots:

  • ax.scatter(x, y): a scatter plot
  • ax.bar(x, height): a bar chart
  • ax.hist(data, bins=20): a histogram
  • ax.axhline(y) / ax.axvline(x): a reference line across the plot
Intro to Scientific Python

Practice (5 min)

Let's work on these questions:

  1. Plot the cumulative sums of data1 through data4 on a single Axes.
  2. Give each line a unique color, linestyle, and a label.
  3. Add a title, axis labels, and a legend.
Intro to Scientific Python

4. Building Subplots in Matplotlib

Intro to Scientific Python

Subplots

plt.subplots() can create a grid of Axes by passing the number of rows and columns:

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(8, 3), layout='constrained')

axes is now a NumPy array of Axes objects, one for each subplot.

Intro to Scientific Python

Indexing Subplots

We index axes the same way we indexed arrays:

fig, axes = plt.subplots(1, 2, figsize=(8, 3), layout='constrained')
axes[0].plot(np.cumsum(data1))
axes[0].set_title('Random walk')
axes[1].hist(data2, bins=20)
axes[1].set_title('Histogram')

For a 2-d grid, e.g. plt.subplots(2, 2), use two indices: axes[0, 1] is the first row, second column.

Intro to Scientific Python

Subplots, cont.

  • sharex=True / sharey=True: the subplots share an axis range
  • fig.suptitle(): a title for the whole Figure
fig, axes = plt.subplots(2, 1, sharex=True, layout='constrained')
axes[0].plot(np.cumsum(data1))
axes[1].plot(np.cumsum(data2))
fig.suptitle('Two random walks')
Intro to Scientific Python

Saving a Figure

fig.savefig('random_walks.png', dpi=150)

The file type comes from the extension, e.g. .png, .pdf, .svg.

Saved figures are files like any other, so you can git add, git commit, and git push them too.

Intro to Scientific Python

Practice (5 min)

Let's work on these questions:

  1. Create a figure with two subplots side by side.
  2. In the first, create a lineplot and give it a unique color and linestyle.
  3. In the second, simulate 1,000 draws with rng.normal() and plot a histogram.
  4. Add a title to each subplot and to the figure, then save it with fig.savefig().
Intro to Scientific Python

Save Your Work

Commit and push your notebook and figures from today on your personal branch:

git add notebooks/module_04.ipynb notebooks/*.png
git commit -m "Module 4 plotting exercises"
git push origin personal
Intro to Scientific Python

That's it for today!

Intro to Scientific Python