Skip to content

Instantly share code, notes, and snippets.

@Kobold
Last active September 12, 2023 12:40
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kobold/a242190ea0b9263ce4d5b5b0e8fb3502 to your computer and use it in GitHub Desktop.
Save Kobold/a242190ea0b9263ce4d5b5b0e8fb3502 to your computer and use it in GitHub Desktop.
A Jupyter notebook to explore variations of xkcd's "Is it worth the time?" comic.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Is it worth the time, at work?\n",
"\n",
"There's a lovely XKCD comic, [Is It Worth the Time?](https://xkcd.com/1205/):\n",
"\n",
"![comic](https://imgs.xkcd.com/comics/is_it_worth_the_time.png)\n",
"\n",
"<br>\n",
"\n",
"However, as pointed out in [this forum thread](http://forums.xkcd.com/viewtopic.php?t=101756#p3340931), there are a bunch of assumptions going into the chart that are not necessarily true:\n",
"\n",
"> Great table, but I have to disagree with the numbers:\n",
"> \n",
"> It seems like the calculation assumes 24-hour days and 365-day years, so the conversion from time saved t and frequency of task f to time worth spending T is\n",
"> \n",
"> T = t \\* f \\* 5 years\n",
"> \n",
"> with the straight unit conversion\n",
"> \n",
"> 1 year = 365 days \n",
"> 1 week = 7 days \n",
"> 1 day = 24 hours\n",
"> \n",
"> etc. However, most people don't work 24 hours/day, either when they are doing the repetitive task or when they are working to streamline it. So the conversions depend on what you consider a full day. If you consider your waking time, then the conversions should be more like\n",
"> \n",
"> 1 year = 365 days \n",
"> 1 week = 7 days \n",
"> 1 day = 16 hours\n",
"> \n",
"> If you want to use this chart for work, then the conversions should be more like\n",
"> \n",
"> 1 year = 250 days \n",
"> 1 week = 5 days \n",
"> 1 day = 8 hours\n",
"> \n",
"> in which case the chart looks quite different. For example, for a 1-hour task done weekly, one should invest 16 days (if considering waking hours) or 1 month (if considering working hours), rather than the 10 days indicated by the chart.\n",
"\n",
"I'd like to use the chart for work.\n",
"\n",
"Let's first replicate XKCD's chart, then update it with conversion assumptions more appropriate for work."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Some Tools\n",
"\n",
"Let's first define units. We use the units library natu."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from natu.units import s\n",
"\n",
"# Traditional timespan definitions.\n",
"minute = 60 * s\n",
"hour = 60 * minute\n",
"day = 24 * hour\n",
"week = 7 * day\n",
"month = 30 * day\n",
"year = 365 * day\n",
"\n",
"# Work timespans.\n",
"work_day = 8 * hour\n",
"work_week = 5 * work_day\n",
"work_year = 250 * work_day"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's also put together some utilities to display our table of times nicely."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"class ListTable(list):\n",
" \"\"\"\n",
" Lovely table formatting snippet.\n",
" via http://calebmadrigal.com/display-list-as-table-in-ipython-notebook/\n",
" \"\"\"\n",
" def _repr_html_(self):\n",
" html = ['<table style=\"margin: 10px auto\">']\n",
" for row in self:\n",
" html.append(\"<tr>\")\n",
" for col in row:\n",
" html.append(\"<td>{0}</td>\".format(col))\n",
" html.append(\"</tr>\")\n",
" html.append(\"</table>\")\n",
" return ''.join(html)\n",
"\n",
"def display_time(time, display_units):\n",
" \"Converts a natu time to a string, using units from `display_units`.\"\n",
" for unit, suffix in display_units:\n",
" if time / unit >= 1.0:\n",
" return u'{:.1f} {}'.format(time / unit, suffix)\n",
" \n",
" return u'{:.1f} seconds'.format(time / s)\n",
"\n",
"# These hierarchies are used to convert into the most appropriate\n",
"# units with `display_time`.\n",
"xkcd_display_units = [\n",
" (year, 'years'),\n",
" (month, 'months'),\n",
" (week, 'weeks'),\n",
" (day, 'days'),\n",
" (hour, 'hours'),\n",
" (minute, 'minutes'),\n",
"]\n",
"\n",
"work_display_units = [\n",
" (work_year, 'work years'),\n",
" (work_week, 'work weeks'),\n",
" (work_day, 'work days'),\n",
" (hour, 'hours'),\n",
" (minute, 'minutes'),\n",
"]"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"Now, let's build a function to actually calculate the table."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def worth_it_table(frequency, time_saved, amortized_over, display_units):\n",
" \"Calculuate a 'Worth It?' table.\"\n",
" def display(time):\n",
" return display_time(time, display_units)\n",
"\n",
" table = ListTable()\n",
" table.append([' ', '50/day', '5/day', '1/day', '1/week', '12/year', '1/year'])\n",
" for t in time_saved:\n",
" row = [\n",
" display(amortized_over * t * f) if t * f < 1.0 else ''\n",
" for f in frequency\n",
" ]\n",
" table.append([display(t)] + row)\n",
" return table"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Verify Our Solution\n",
"\n",
"Let's verify that it works with the original parameters."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<table style=\"margin: 10px auto\"><tr><td> </td><td>50/day</td><td>5/day</td><td>1/day</td><td>1/week</td><td>12/year</td><td>1/year</td></tr><tr><td>1.0 seconds</td><td>1.1 days</td><td>2.5 hours</td><td>30.4 minutes</td><td>4.3 minutes</td><td>1.0 minutes</td><td>5.0 seconds</td></tr><tr><td>5.0 seconds</td><td>5.3 days</td><td>12.7 hours</td><td>2.5 hours</td><td>21.7 minutes</td><td>5.0 minutes</td><td>25.0 seconds</td></tr><tr><td>30.0 seconds</td><td>1.1 months</td><td>3.2 days</td><td>15.2 hours</td><td>2.2 hours</td><td>30.0 minutes</td><td>2.5 minutes</td></tr><tr><td>1.0 minutes</td><td>2.1 months</td><td>6.3 days</td><td>1.3 days</td><td>4.3 hours</td><td>1.0 hours</td><td>5.0 minutes</td></tr><tr><td>5.0 minutes</td><td>10.6 months</td><td>1.1 months</td><td>6.3 days</td><td>21.7 hours</td><td>5.0 hours</td><td>25.0 minutes</td></tr><tr><td>30.0 minutes</td><td></td><td>6.3 months</td><td>1.3 months</td><td>5.4 days</td><td>1.2 days</td><td>2.5 hours</td></tr><tr><td>1.0 hours</td><td></td><td>1.0 years</td><td>2.5 months</td><td>1.6 weeks</td><td>2.5 days</td><td>5.0 hours</td></tr><tr><td>6.0 hours</td><td></td><td></td><td>1.2 years</td><td>2.2 months</td><td>2.1 weeks</td><td>1.2 days</td></tr><tr><td>1.0 days</td><td></td><td></td><td></td><td>8.7 months</td><td>2.0 months</td><td>5.0 days</td></tr></table>"
],
"text/plain": [
"[[' ', '50/day', '5/day', '1/day', '1/week', '12/year', '1/year'],\n",
" [u'1.0 seconds',\n",
" u'1.1 days',\n",
" u'2.5 hours',\n",
" u'30.4 minutes',\n",
" u'4.3 minutes',\n",
" u'1.0 minutes',\n",
" u'5.0 seconds'],\n",
" [u'5.0 seconds',\n",
" u'5.3 days',\n",
" u'12.7 hours',\n",
" u'2.5 hours',\n",
" u'21.7 minutes',\n",
" u'5.0 minutes',\n",
" u'25.0 seconds'],\n",
" [u'30.0 seconds',\n",
" u'1.1 months',\n",
" u'3.2 days',\n",
" u'15.2 hours',\n",
" u'2.2 hours',\n",
" u'30.0 minutes',\n",
" u'2.5 minutes'],\n",
" [u'1.0 minutes',\n",
" u'2.1 months',\n",
" u'6.3 days',\n",
" u'1.3 days',\n",
" u'4.3 hours',\n",
" u'1.0 hours',\n",
" u'5.0 minutes'],\n",
" [u'5.0 minutes',\n",
" u'10.6 months',\n",
" u'1.1 months',\n",
" u'6.3 days',\n",
" u'21.7 hours',\n",
" u'5.0 hours',\n",
" u'25.0 minutes'],\n",
" [u'30.0 minutes',\n",
" '',\n",
" u'6.3 months',\n",
" u'1.3 months',\n",
" u'5.4 days',\n",
" u'1.2 days',\n",
" u'2.5 hours'],\n",
" [u'1.0 hours',\n",
" '',\n",
" u'1.0 years',\n",
" u'2.5 months',\n",
" u'1.6 weeks',\n",
" u'2.5 days',\n",
" u'5.0 hours'],\n",
" [u'6.0 hours',\n",
" '',\n",
" '',\n",
" u'1.2 years',\n",
" u'2.2 months',\n",
" u'2.1 weeks',\n",
" u'1.2 days'],\n",
" [u'1.0 days', '', '', '', u'8.7 months', u'2.0 months', u'5.0 days']]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# XKCD's \"How often?\" to row and \"Time shaved\" left column:\n",
"xkcd_frequency = [50/day, 5/day, 1/day, 1/week, 12/year, 1/year]\n",
"xkcd_time_saved = [1*s, 5*s, 30*s, 1*minute, 5*minute, 30*minute, 1*hour, 6*hour, 1*day]\n",
"\n",
"# XKCD amortizes it over 5 year.\n",
"worth_it_table(xkcd_frequency, xkcd_time_saved, 5 * year, xkcd_display_units)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Take a look at the original comic and compare:\n",
"\n",
"![comic](https://imgs.xkcd.com/comics/is_it_worth_the_time.png)\n",
"\n",
"<br>\n",
"\n",
"Looks good to me!\n",
"\n",
"## Is it worth the time, at work?\n",
"\n",
"Now let's try it with \"work\" definitions of time spans, and amortize over only 1 year."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<table style=\"margin: 10px auto\"><tr><td> </td><td>50/day</td><td>5/day</td><td>1/day</td><td>1/week</td><td>12/year</td><td>1/year</td></tr><tr><td>1.0 seconds</td><td>3.5 hours</td><td>20.8 minutes</td><td>4.2 minutes</td><td>50.0 seconds</td><td>12.0 seconds</td><td>1.0 seconds</td></tr><tr><td>5.0 seconds</td><td>2.2 work days</td><td>1.7 hours</td><td>20.8 minutes</td><td>4.2 minutes</td><td>1.0 minutes</td><td>5.0 seconds</td></tr><tr><td>30.0 seconds</td><td>2.6 work weeks</td><td>1.3 work days</td><td>2.1 hours</td><td>25.0 minutes</td><td>6.0 minutes</td><td>30.0 seconds</td></tr><tr><td>1.0 minutes</td><td>5.2 work weeks</td><td>2.6 work days</td><td>4.2 hours</td><td>50.0 minutes</td><td>12.0 minutes</td><td>60.0 seconds</td></tr><tr><td>5.0 minutes</td><td>26.0 work weeks</td><td>2.6 work weeks</td><td>2.6 work days</td><td>4.2 hours</td><td>1.0 hours</td><td>5.0 minutes</td></tr><tr><td>30.0 minutes</td><td></td><td>15.6 work weeks</td><td>3.1 work weeks</td><td>3.1 work days</td><td>6.0 hours</td><td>30.0 minutes</td></tr><tr><td>1.0 hours</td><td></td><td>31.2 work weeks</td><td>6.2 work weeks</td><td>1.2 work weeks</td><td>1.5 work days</td><td>60.0 minutes</td></tr><tr><td>6.0 hours</td><td></td><td></td><td>37.5 work weeks</td><td>7.5 work weeks</td><td>1.8 work weeks</td><td>6.0 hours</td></tr><tr><td>1.0 work days</td><td></td><td></td><td></td><td>10.0 work weeks</td><td>2.4 work weeks</td><td>8.0 hours</td></tr></table>"
],
"text/plain": [
"[[' ', '50/day', '5/day', '1/day', '1/week', '12/year', '1/year'],\n",
" [u'1.0 seconds',\n",
" u'3.5 hours',\n",
" u'20.8 minutes',\n",
" u'4.2 minutes',\n",
" u'50.0 seconds',\n",
" u'12.0 seconds',\n",
" u'1.0 seconds'],\n",
" [u'5.0 seconds',\n",
" u'2.2 work days',\n",
" u'1.7 hours',\n",
" u'20.8 minutes',\n",
" u'4.2 minutes',\n",
" u'1.0 minutes',\n",
" u'5.0 seconds'],\n",
" [u'30.0 seconds',\n",
" u'2.6 work weeks',\n",
" u'1.3 work days',\n",
" u'2.1 hours',\n",
" u'25.0 minutes',\n",
" u'6.0 minutes',\n",
" u'30.0 seconds'],\n",
" [u'1.0 minutes',\n",
" u'5.2 work weeks',\n",
" u'2.6 work days',\n",
" u'4.2 hours',\n",
" u'50.0 minutes',\n",
" u'12.0 minutes',\n",
" u'60.0 seconds'],\n",
" [u'5.0 minutes',\n",
" u'26.0 work weeks',\n",
" u'2.6 work weeks',\n",
" u'2.6 work days',\n",
" u'4.2 hours',\n",
" u'1.0 hours',\n",
" u'5.0 minutes'],\n",
" [u'30.0 minutes',\n",
" '',\n",
" u'15.6 work weeks',\n",
" u'3.1 work weeks',\n",
" u'3.1 work days',\n",
" u'6.0 hours',\n",
" u'30.0 minutes'],\n",
" [u'1.0 hours',\n",
" '',\n",
" u'31.2 work weeks',\n",
" u'6.2 work weeks',\n",
" u'1.2 work weeks',\n",
" u'1.5 work days',\n",
" u'60.0 minutes'],\n",
" [u'6.0 hours',\n",
" '',\n",
" '',\n",
" u'37.5 work weeks',\n",
" u'7.5 work weeks',\n",
" u'1.8 work weeks',\n",
" u'6.0 hours'],\n",
" [u'1.0 work days',\n",
" '',\n",
" '',\n",
" '',\n",
" u'10.0 work weeks',\n",
" u'2.4 work weeks',\n",
" u'8.0 hours']]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"work_frequency = [50/work_day, 5/work_day, 1/work_day, 1/work_week, 12/work_year, 1/work_year]\n",
"work_time_saved = [1*s, 5*s, 30*s, 1*minute, 5*minute, 30*minute, 1*hour, 6*hour, 1*work_day]\n",
"\n",
"worth_it_table(work_frequency, work_time_saved, 1 * work_year, work_display_units)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Interesting...\n",
"\n",
"Now go forth and make productive decisions!\n",
"\n",
"<br>"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.11"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment