Skip to content

Instantly share code, notes, and snippets.

@nitori
Last active January 8, 2023 01:57
Show Gist options
  • Save nitori/5c1945de90c97bd7bd54c67fc1bc0e0e to your computer and use it in GitHub Desktop.
Save nitori/5c1945de90c97bd7bd54c67fc1bc0e0e to your computer and use it in GitHub Desktop.
from __future__ import annotations
import math
import colorsys
from PIL import Image, ImageDraw, ImageFont
RowTuple = tuple[float, float] | None
def calc_lines(t_start: int, t_end: int) -> tuple[RowTuple, RowTuple, RowTuple]:
"""
Assume 24 hours are split over three rows, with 8 columns each.
Return a tuple of three values, each corresponding a row.
If row is None, no line on this row, otherwise it's a (start, end)
tuple in the range [0..1].
:param t_start: start in military time e.g. 1530 for 15:30
:param t_end: same, but end of shift
:returns: tuple of three items: (start,end) or None
"""
t0_x = t_start % 800
t0_y = t_start // 800
t1_x = t_end % 800
t1_y = t_end // 800
rows: list[RowTuple] = []
for rowi in range(3):
if rowi < t0_y or rowi > t1_y:
rows.append(None)
continue
start = t0_x if rowi == t0_y else 0
end = t1_x if rowi == t1_y else 800
start = start / 800
end = end / 800
rows.append((start, end))
return rows[0], rows[1], rows[2]
def main():
time_ranges = [
(0, 620), (620, 645), (645, 920), (920, 1050), (1050, 1135), (1135, 1310),
(1310, 1445), (1445, 1500), (1600, 1700), (2200, 2300), (2300, 2400)
]
width, height = 1600, 900
font = ImageFont.FreeTypeFont('PressStart2P-Regular.ttf', 8) # Google Font
im = Image.new('RGB', (width, height), (0, 0, 0))
draw = ImageDraw.Draw(im)
wstep = width // 8
hstep = height // 3
for y in range(0, height, hstep):
for x in range(0, width, wstep):
draw.rectangle((x, y, x + wstep - 1, y + hstep - 1), outline=(255, 255, 255))
rows = {i: [] for i in range(3)}
for timei, (t0, t1) in enumerate(time_ranges):
for rowi, line in enumerate(calc_lines(t0, t1)):
if line is None:
continue
rows[rowi].append((line, timei, t0, t1))
rows = [(i, values) for i, values in sorted(rows.items())]
for row, values in rows:
for value_index, (line, time_index, t0, t1) in enumerate(values):
# get some color
hue = time_index / len(time_ranges)
r, g, b = colorsys.hsv_to_rgb(hue, 1, 1)
r, g, b = int(r * 255), int(g * 255), int(b * 255)
# calculate start/end x of the line
x0, x1 = line
x0 = math.floor(x0 * width)
x1 = math.floor(x1 * width)
# and the y coordinate
y = row * hstep
subrow_height = hstep // len(values)
middle = subrow_height // 2
y += subrow_height * value_index + middle
draw.line((x0, y, x1, y), fill=(r, g, b), width=5)
draw.text((x0 + 2, y + 6), f'{t0}-{t1}', fill=(r, g, b), font=font)
im.show()
# im.save('timeline.png')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment