-
-
Save shmulvad/54c00d5e998771515472adf412aa0016 to your computer and use it in GitHub Desktop.
Bar plot with multiple start and end points on a single date
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Check the following image to see output: | |
# https://i.imgur.com/miKLguL.png | |
# Answer to | |
# https://stackoverflow.com/questions/62376753/how-would-i-create-a-bar-plot-with-multiple-start-and-end-points-on-a-single-dat#62376753 | |
import pandas as pd | |
import numpy as np | |
import datetime as dt | |
import matplotlib.pyplot as plt | |
import matplotlib.dates as mdates | |
from matplotlib.collections import PolyCollection | |
import matplotlib.patches as mpatches | |
data = np.array([ | |
["Client", "Task", "Start Time", "End Time"], | |
["client-A", "task-a", "2020-06-10 11:10", "2020-06-10 11:25"], | |
["client-B", "task-b", "2020-06-10 11:30", "2020-06-10 13:54"], | |
["client-B", "task-a", "2020-06-10 17:34", "2020-06-10 18:00"], | |
["client-D", "task-e", "2020-06-11 08:05", "2020-06-11 12:45"], | |
["client-C", "task-d", "2020-06-11 15:15", "2020-06-11 17:01"], | |
["client-A", "task-a", "2020-06-11 19:10", "2020-06-11 20:18"], | |
["client-A", "task-c", "2020-06-11 20:18", "2020-06-11 21:36"], | |
["client-C", "task-a", "2020-06-12 08:02", "2020-06-12 08:25"], | |
["client-D", "task-e", "2020-06-12 08:45", "2020-06-12 09:55"], | |
["client-E", "task-d", "2020-06-12 10:00", "2020-06-12 11:07"], | |
["client-B", "task-c", "2020-06-12 11:11", "2020-06-12 12:30"] | |
]) | |
data = data[1:, :] # Remove header | |
# Get all unique days in a sorted list and make dictionary using this | |
days_list = sorted(list(set([date[:10] for date in data[:, 2]])))[::-1] | |
days = { day: i+1 for i, day in enumerate(days_list) } | |
# Make a colormapping based on which client | |
clients = sorted(list(set(data[:, 0]))) | |
colormapping = { client: f"C{i}" for i, client in enumerate(clients) } | |
# Save just the start time and end time for each entry as datetime | |
start_times = [dt.datetime.strptime(date[11:], "%H:%M") for date in data[:, 2]] | |
end_times = [dt.datetime.strptime(date[11:], "%H:%M") for date in data[:, 3]] | |
# Go through all data points and add corresponding vertices | |
verts, colors, texts = [], [], [] | |
for i, d in enumerate(data): | |
client, task, date_str = d[0], d[1], d[2] | |
day_num = days[date_str[:10]] | |
start_date = mdates.date2num(start_times[i]) | |
end_date = mdates.date2num(end_times[i]) | |
v = [(start_date, day_num - .4), | |
(start_date, day_num + .4), | |
(end_date, day_num + .4), | |
(end_date, day_num - .4), | |
(start_date, day_num - .4) | |
] | |
verts.append(v) | |
colors.append(colormapping[client]) | |
texts.append((start_date, day_num, task[-1].upper())) | |
# Make PolyCollection and scale | |
bars = PolyCollection(verts, facecolors=colors, edgecolors=("black",)) | |
fig, ax = plt.subplots() | |
ax.add_collection(bars) | |
ax.autoscale() | |
# Set ticks to show every 30 minutes and in specific format | |
xticks = mdates.MinuteLocator(byminute=[0, 30]) | |
ax.xaxis.set_major_locator(xticks) | |
ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M")) | |
fig.autofmt_xdate() | |
# Set y-axis to be dates | |
ax.set_yticks(range(1, len(days_list) + 1)) | |
ax.set_yticklabels(days_list) | |
# Add task text to plot | |
for (start_date, day_num, task) in texts: | |
plt.text(start_date+.003, day_num-.03, task, color="w") | |
# Create legend based on clients | |
plt.legend(handles=[mpatches.Patch(color=color, label=client) | |
for client, color in colormapping.items()]) | |
# Add grid and show | |
plt.grid() | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment