Musings of a dad with too much time on his hands and not enough to do. Wait. Reverse that.

Tag: tools (Page 8 of 35)

Making timelines with Python

For many years, as I’ve trolled the intertubes, I would occasionally run across creative résumés that would include timelines depicting different work events in the lives of those professionals. As I would happen upon these graphics, I would think to myself, “self, I’m no artist: is there a way to programmatically generate such timelines?”

Well, thanks to this recent article, here’s a neat way to use Python and matplotlib to just that.

Step 1: Do your imports

import matplotlib.pyplot as plt
from datetime import date
import numpy as np

%matplotlib inline  # since I'm doing this work in a Jupyter Notebook

Step 2: Get your timeline data together

For simplicity, I’m just hard coding my dates and event labels in two different lists, but you could easily pull together data from a dataframe or other object. I’m also calculating a “minimum date” (min_date) where I get the earliest date from my dataset and subtract two years and a “maximum date” (max_date) where I get the newest date and add two years. I’m subtracting and adding years just to get some padding in my graphic. I’ll use these variables later on. (Note that I do use “\n” in my labels to wrap long text to a second line.)

# reference: https://mentalitch.com/key-events-in-rock-and-roll-history/
dates = [date(1954, 7, 19), date(1959, 2, 3), date(1964, 2, 9), date(1965, 7, 25), date(1967, 6, 1), date(1969, 8, 15)]
min_date = date(np.min(dates).year - 2, np.min(dates).month, np.min(dates).day)
max_date = date(np.max(dates).year + 2, np.max(dates).month, np.max(dates).day)

labels = ['Elvis appears on\nthe Ed Sullivan Show', 'Buddy Holly dies', 'The Beatles appear\non the Ed Sullivan Show', 
          'Bob Dylan goes electric', 'The Beatles release\nSgt. Pepper', 'Woodstock']
# labels with associated dates
labels = ['{0:%d %b %Y}:\n{1}'.format(d, l) for l, d in zip (labels, dates)]

Step 3: Set up my timeline and points

This is where it starts to get cool: I knew matplotlib had a horizontal line function, but it never occurred to me that I could use it as a timeline. Likewise, it never occurred to me to use the library’s scatter plot function to paint dots on a timeline.

fig, ax = plt.subplots(figsize=(15, 4), constrained_layout=True)
_ = ax.set_ylim(-2, 1.75)
_ = ax.set_xlim(min_date, max_date)
_ = ax.axhline(0, xmin=0.05, xmax=0.95, c='deeppink', zorder=1)

_ = ax.scatter(dates, np.zeros(len(dates)), s=120, c='palevioletred', zorder=2)
_ = ax.scatter(dates, np.zeros(len(dates)), s=30, c='darkmagenta', zorder=3)

Step 4: Add my labels

Next, I can use the text function to add my event labels to the timeline. I did have to play around with my y-axis offsets for my labels to be nicely positioned above and below the timeline. I used Python list slicing to position labels with an even index above the line and labels with an odd index below.

label_offsets = np.zeros(len(dates))
label_offsets[::2] = 0.35
label_offsets[1::2] = -0.7
for i, (l, d) in enumerate(zip(labels, dates)):
    _ = ax.text(d, label_offsets[i], l, ha='center', fontfamily='serif', fontweight='bold', color='royalblue',fontsize=12)

Step 5: Add lollipops

What a clever way to use matplotlib’s stem plot function! Here, we can create stems to link our labels to their associated dots on the timeline.

stems = np.zeros(len(dates))
stems[::2] = 0.3
stems[1::2] = -0.3    
markerline, stemline, baseline = ax.stem(dates, stems, use_line_collection=True)
_ = plt.setp(markerline, marker=',', color='darkmagenta')
_ = plt.setp(stemline, color='darkmagenta')

Step 6: Sundry cleanup and titling

# hide lines around chart
for spine in ["left", "top", "right", "bottom"]:
    _ = ax.spines[spine].set_visible(False)

# hide tick labels
_ = ax.set_xticks([])
_ = ax.set_yticks([])

_ = ax.set_title('Important Milestones in Rock and Roll', fontweight="bold", fontfamily='serif', fontsize=16, 
                 color='royalblue')

And now, we have a pretty cool timeline:

Timeline in Matplotlib

This chart is using the default matplotlib style. I did try using other styles like XKCD, as the author highlighted in the article, but my chart just didn’t look very good. Your mileage may vary.

But, wait…there’s more!

What if I want to do a vertical timeline instead? Well, you can do that, as well, with some adjustments.

Additional import

To help better center my event labels, I’ll import the timedelta function:

from datetime import timedelta

Use the axvline function

For my vertical timeline, I’ll use the axvline function. I’ve also made a few other code adjustments you can see:

fig, ax = plt.subplots(figsize=(6, 10), constrained_layout=True)
_ = ax.set_xlim(-20, 20)
_ = ax.set_ylim(min_date, max_date)
_ = ax.axvline(0, ymin=0.05, ymax=0.95, c='deeppink', zorder=1)

_ = ax.scatter(np.zeros(len(dates)), dates, s=120, c='palevioletred', zorder=2)
_ = ax.scatter(np.zeros(len(dates)), dates, s=30, c='darkmagenta', zorder=3)

Adjust the dates used to position the event labels

Without the timedelta adjustment, the label positioning still doesn’t look too bad, but subtracting about 90 days from each date helps sort-of vertically center the labels:

label_offsets = np.repeat(2.0, len(dates))
label_offsets[1::2] = -2.0
for i, (l, d) in enumerate(zip(labels, dates)):
    d = d - timedelta(days=90)
    align = 'right'
    if i % 2 == 0:
        align = 'left'
    _ = ax.text(label_offsets[i], d, l, ha=align, fontfamily='serif', fontweight='bold', color='royalblue',fontsize=12)

There doesn’t seem to be a stem function for horizontal lines

The documentation says you should be able to orient stem lines horizontally, but I never got that to work, so I opted to go with the hlines function, instead.

stems = np.repeat(2.0, len(dates))
stems[1::2] *= -1.0    
x = ax.hlines(dates, 0, stems, color='darkmagenta')

Apply the same sundry cleanup

# hide lines around chart
for spine in ["left", "top", "right", "bottom"]:
    _ = ax.spines[spine].set_visible(False)

# hide tick labels
_ = ax.set_xticks([])
_ = ax.set_yticks([])

_ = ax.set_title('Important Milestones in Rock and Roll', fontweight="bold", fontfamily='serif', fontsize=16, 
                 color='royalblue')

And now you have a vertical timeline!

Access Denied

After I finished installing Docker on my Windows 10 Home machine, I started up the application and was promptly greeted with a friendly message:

Access Denied

The message included a statement that my account needed to be part of the docker-users group in order to use Docker.

No problem. I logged into my machine with my admin account and opened up Computer Management to access the Local Users and Groups section so that I could add my developer account to the group. Only…the Local Users and Groups section wasn’t there! Er, what?

It turns out this option isn’t available through the Computer Management user interface on a Windows 10 Home system. Fortunately, it is available at the command line (here’s a nicer walkthrough about halfway down the page).

All I had to do was open a command shell as administrator and run the following:

net localgroup "docker-users" "brad" /add

After a restart, my Docker application ran as expected.

Docker and WSL 2

I clearly missed the announcement: Docker Desktop for Windows will now run on Windows Subsystem for Linux (WSL) version 2.

Up until a few days ago, I had understood that I would only be able to run Docker for Windows if I spent the $100-$200 to upgrade my operating system from Windows 10 Home to Windows 10 Pro, since Pro includes virtualization features needed for Docker that Home does not. At work, I run Docker Desktop for Windows and hoped I could leverage that work experience in some of my home projects.

So, I had resigned myself to learning about the docker/linux experience at home while enjoying the Windows-based experiences at work.

Over the weekend, I upgraded to WSL 2–a surprisingly easy upgrade–and then for kicks, installed Windows Terminal. Then, I prepared for disappointment as I started researching the Docker install on WSL. And then I clicked on the link from the Microsoft article and read this:

Docker Desktop for Windows is available for free.

Requires Microsoft Windows 10 Professional or Enterprise 64-bit, or Windows 10 Home 64-bit with WSL 2.

Awesome! So I can get the full Docker Windows experience without having to upgrade to Win10 Pro. Exciting!

The install went smoothly, so I’ll hopefully have one or two Docker-type posts in the future.

« Older posts Newer posts »

© 2024 DadOverflow.com

Theme by Anders NorenUp ↑