По моему мнению, этот код очень сложен и его следует упростить ...
Однако, первым намеком может быть поместить имя группы и группу прямо в определении цикла в две разные переменные вместо индексации покортеж:
...
for lbl, grp in task[1].groupby("M"):
data = grp[["start", "diff"]]
ax.broken_barh(data.values, (i-0.4,0.8), color=color[lbl], label=lbl)
...
Тем не менее, я могу дать вам возможность добавлять в легенду только метки, которые еще не использовались.
Идея состоит в том, чтобы инициализировать пустой список lbl_pool
, чтобы сохранитьотслеживать, если метка уже использовалась для легенды.Если да, поставьте подчеркивание перед надписью, которое превосходит отображаемое в легенде:
w=[]
lbl_pool = []
for i, task in enumerate(df.groupby("L")):
w.append(task[0])
for lbl, grp in task[1].groupby("M"):
data = grp[["start", "diff"]]
if lbl in lbl_pool:
prefix = '_'
else:
lbl_pool.append(lbl)
prefix=''
ax.broken_barh(data.values, (i-0.4,0.8), color=color[lbl], label=prefix+lbl)
Результат:

Тем не менее, это все еще не делает читаемый код из всей программы;Я думаю, что это становится еще хуже, так как это дополнительный патч типа «код, пока он не сделает то, что должен, независимо от структуры» ...
Я определенно рекомендую вам просмотреть все это и, возможно, воссоздать егос нуля, используя уроки, которые вы получили с этой версией, для лучшей следующей.
(И просто для взаимодействия почти со всеми остальными кодами в python: используйте 4 пробела в качестве отступов, а не только 3.)