# Visualizing An Infant's Schedule A newborn may only eat, sleep, and poop, but they sure do it a lot! Here is a sample of two weeks of an an infant's schedule visualized with matplotlib.

A while ago I came across a radial sleep schedule plot and thought it was a creative way to visualize this type of data.

Since my wife and I have been tracking data for use with the doctor already using the Baby Tracker app, and since it has a convenient exoprt to csv feature, I decided to make a similar chart.

To export the data from the Baby Tracker app go to Settings > Export Data to CSV. This will generate a csv.zip file that you can email to yourself. Unzipping the file gives one csv for each category: sleep, nursing, diaper, etc.

Using sleep as an example, we start by loading the data into a Pandas DataFrame:

This gives us the start time and duration of each period of sleep. Our matplotlib chart is a bar chart on a polar projection. Therefore, we need to define the center, thickness, width, bottom of each bar:

• center is the midpoint of the nap, or (end time - start time) / 2, which we then convert to polar coordinates and offset so midnight is at the bottom
• thickness is a constant, we use 1
• width is the duration of the nap converted to polar coordinates and rotated
• bottom is the radial position of the bar, which corresponds to the date since each "ring" on the chart is a day

Putting this together with some hour labels, we get a simple chart of baby's sleep pattern over two weeks: Nursing time has a similar duration, and different colored bars can be added in the same manner. Other data such as diapers are single events without a duration:

For these, we plot a simple point instead of a bar. Adding a nice legend and a some story time, we get the final chart: import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from matplotlib.lines import Line2D

def data_sleep(path):
parse_dates=)
sleep['DateTime'] = sleep['Time']
sleep['Date'] = sleep['DateTime'].dt.date
sleep['Time'] = sleep['DateTime'].dt.time

# get bottom
sleep['bottom'] = (sleep['Date']-min(sleep['Date'])).astype(str)
sleep['bottom'] = (sleep['bottom'].str.split(' ').str.get(0)).astype(int)

# get minutes
sleep['minutes'] = sleep['Time'].astype(str).str.split(':').apply(lambda x: int(x) * 60 + int(x))

return sleep

def data_nurse(path):
parse_dates=)
nurse['DateTime'] = nurse['Time']
nurse['Date'] = nurse['DateTime'].dt.date
nurse['Time'] = nurse['DateTime'].dt.time

# get duration
nurse['Total Duration'] = nurse['Left duration'] + nurse['Right duration']

# get bottom
nurse['bottom'] = (nurse['Date']-min(nurse['Date'])).astype(str)
nurse['bottom'] = (nurse['bottom'].str.split(' ').str.get(0)).astype(int)

# get minutes
nurse['minutes'] = nurse['Time'].astype(str).str.split(':').apply(lambda x: int(x) * 60 + int(x))

return nurse

def data_diaper(path):
parse_dates=)
diaper['DateTime'] = diaper['Time']
diaper['Date'] = diaper['DateTime'].dt.date
diaper['Time'] = diaper['DateTime'].dt.time

# get bottom
diaper['bottom'] = (diaper['Date']-min(diaper['Date'])).astype(str)
diaper['bottom'] = (diaper['bottom'].str.split(' ').str.get(0)).astype(int)

# get minutes
diaper['minutes'] = diaper['Time'].astype(str).str.split(':').apply(lambda x: int(x) * 60 + int(x))

return diaper

def data_story(path):
parse_dates=)
story = story[story['Other activity']=='Story Time']
story['DateTime'] = story['Time']
story['Date'] = story['DateTime'].dt.date
story['Time'] = story['DateTime'].dt.time

# get bottom
story['bottom'] = (story['Date']-min(story['Date'])).astype(str)
story['bottom'] = (story['bottom'].str.split(' ').str.get(0)).astype(int)

# get minutes
story['minutes'] = story['Time'].astype(str).str.split(':').apply(lambda x: int(x) * 60 + int(x))

return story

ax = plt.subplot(111, projection='polar')
ax.set_facecolor('#F8B55A') # awake time background

# turn axes off
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)

# sleep time
for row in range(sleep.shape):
duration = sleep.loc[sleep.index[row],'Duration(minutes)']
minutes  = sleep.loc[sleep.index[row],'minutes']
bottom   = sleep.loc[sleep.index[row],'bottom']
width = duration / 60 / 24 * 2 * np.pi
center = ( -(minutes+duration/2) / 60 / 24 * 2 * np.pi) - np.pi/2
bars = ax.bar(center, 1, width=width, bottom=bottom, color='#225282')

# hour marks
x = np.linspace(0,np.pi*2,num=25)
hr = ['6 pm','5 pm','4 pm','3 pm','2 pm','1 pm','12 pm',
'11 am','10 am','9 am','8 am','7 am','6 am',
'5 am','4 am','3 am','2 am','1 am','12 am',
'11 pm','10 pm','9 pm','8 pm','7 pm','']
for i in range(len(x)):
plt.plot([0,x[i]],[0,bottom+1],'k:',lw=.5,alpha=.5)
plt.text(x[i],bottom+2.5,hr[i],ha='center',va='center', color='grey',
fontsize=8, family='monospace')

# annotation
ax.annotate('Data collected with Baby Tracker app (v3.09)', xy=(0, 0),
xycoords='figure fraction', xytext=(0.0, -0.1), textcoords='axes fraction',
horizontalalignment='left', verticalalignment='center', fontsize=6, color='grey')

# legend
legend_elements = [Line2D(, , color='#F8B55A', lw=6, label='Awake'),
Line2D(, , color='#225282', lw=6, label='Sleeping')]
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(.85, .06), fontsize=6)

plt.title('Baby\'s Sleep Schedule', va='bottom')
plt.ylim(ymax=bottom+1)

ax = plt.subplot(111, projection='polar')
ax.set_facecolor('#F8B55A') # awake time background

# turn axes off
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)

# sleep time
for row in range(sleep.shape):
duration = sleep.loc[sleep.index[row],'Duration(minutes)']
minutes  = sleep.loc[sleep.index[row],'minutes']
bottom   = sleep.loc[sleep.index[row],'bottom']
width = duration / 60 / 24 * 2 * np.pi
center = ( -(minutes+duration/2) / 60 / 24 * 2 * np.pi) - np.pi/2
bars = ax.bar(center, 1, width=width, bottom=bottom, color='#225282')

# nurse time
for row in range(nurse.shape):
duration = nurse.loc[nurse.index[row],'Total Duration']
minutes  = nurse.loc[nurse.index[row],'minutes']
bottom   = nurse.loc[nurse.index[row],'bottom']
width = duration / 60 / 24 * 2 * np.pi
center = ( -(minutes+duration/2) / 60 / 24 * 2 * np.pi) - np.pi/2
bars = ax.bar(center, 1, width=width, bottom=bottom, color='#f85a9d')

# dirty diapers
for row in range(diaper.shape):
bottom   = diaper.loc[diaper.index[row],'bottom']
minutes  = diaper.loc[diaper.index[row],'minutes']
center = ( -minutes / 60 / 24 * 2 * np.pi) - np.pi/2
plt.plot(center, bottom+.5, marker='o', markersize=3, color="#825222",
markeredgecolor='white', markeredgewidth=.2)

# story time
for row in range(story.shape):
bottom   = story.loc[story.index[row],'bottom']
minutes  = story.loc[story.index[row],'minutes']
center = ( -minutes / 60 / 24 * 2 * np.pi) - np.pi/2
plt.plot(center, bottom+.5, marker='o', markersize=3, color="#5aecf8",
markeredgecolor='white', markeredgewidth=.2)

# hour marks
x = np.linspace(0,np.pi*2,num=25)
hr = ['6 pm','5 pm','4 pm','3 pm','2 pm','1 pm','12 pm',
'11 am','10 am','9 am','8 am','7 am','6 am',
'5 am','4 am','3 am','2 am','1 am','12 am',
'11 pm','10 pm','9 pm','8 pm','7 pm','']
for i in range(len(x)):
plt.plot([0,x[i]],[0,bottom+1],'k:',lw=.5,alpha=.5)
plt.text(x[i],bottom+2.5,hr[i],ha='center',va='center', color='grey',
fontsize=8, family='monospace')

# annotation
ax.annotate('Data collected with Baby Tracker app (v3.09)', xy=(0, 0),
xycoords='figure fraction', xytext=(0.0, -0.1), textcoords='axes fraction',
horizontalalignment='left', verticalalignment='center', fontsize=6, color='grey')

# legend
legend_elements = [Line2D(, , color='#F8B55A', lw=6, label='Awake'),
Line2D(, , color='#225282', lw=6, label='Sleeping'),
Line2D(, , color='#f85a9d', lw=6, label='Nursing'),
Line2D(, , marker='o', color='#825222', label='Diaper',
markeredgecolor='w', markersize=7),
Line2D(, , marker='o', color='#5aecf8', label='Story Time',
markeredgecolor='w', markersize=7)]
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(.85, .06), fontsize=6)

plt.title('Baby\'s Schedule', va='bottom')
plt.ylim(ymax=bottom+1)

sleep = data_sleep('Baby1_sleep.csv')
nurse = data_nurse('Baby1_nursing.csv')
diaper = data_diaper('Baby1_diaper.csv')
story = data_story('Baby1_other_activity.csv')


matplotlib  2.2.2