Neste passo a passo, vamos falar sobre o que é um gráfico de Gantt, por que e quando esse tipo de visualização é útil, como fazer um gráfico de Gantt em Python com matplotlib e como personalizá-lo. No caminho, vamos construir alguns exemplos de gráficos de Gantt em matplotlib.
O que é um gráfico de Gantt e por que ele é útil?
Um gráfico de Gantt é um tipo de gráfico de barras usado para ilustrar um cronograma completo de planejamento e gestão de projetos. Ele costuma exibir itens como nomes das tarefas do projeto, datas de início e término, times responsáveis por cada tarefa, status de conclusão em percentual ou fração, desempenho por time e marcos importantes do projeto.
Os nomes das tarefas ficam no eixo y do gráfico de Gantt, geralmente ordenados por data de início em ordem cronológica de cima para baixo. Já o eixo x representa períodos de tempo, e a largura de cada barra corresponde à duração de execução de cada tarefa.
Como um gráfico de Gantt é, essencialmente, uma forma específica de gráfico de barras horizontal, podemos criá-lo em várias bibliotecas de visualização de dados do Python, incluindo matplotlib, Plotly, Bokeh e Altair. Neste tutorial, vamos focar em criar gráficos de Gantt na mais popular delas – o matplotlib.
Como fazer um gráfico de Gantt em Python com Matplotlib
Usando barh()
Vamos começar criando um gráfico de Gantt básico no matplotlib usando o método barh() de matplotlib.pyplot.
Primeiro, precisamos importar as bibliotecas necessárias:
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import datetime as dtTecnologia
Em seguida, vamos criar dados de exemplo para trabalhar:
df = pd.DataFrame({'task':['A','B','C','D','E','F','G','H','I','J','K','L'],'team':['R&D','Accounting','Sales','Sales','IT','R&D','IT','Sales','Accounting','Accounting','Sales','IT'],'start': pd.to_datetime(['20 Oct 2022','24 Oct 2022','26 Oct 2022','31 Oct 2022','3 Nov 2022','7 Nov 2022','10 Nov 2022','14 Nov 2022','18 Nov 2022','23 Nov 2022','28 Nov 2022','30 Nov 2022']),'end': pd.to_datetime(['31 Oct 2022','28 Oct 2022','31 Oct 2022','8 Nov 2022','9 Nov 2022','18 Nov 2022','17 Nov 2022','22 Nov 2022','23 Nov 2022','1 Dec 2022','5 Dec 2022','5 Dec 2022']),'completion_frac':[1,1,1,1,1,0.95,0.7,0.35,0.1,0,0,0]})print(df)Tecnologia
Saída:
task team start end completion_frac
0 A R&D 2022-10-202022-10-311.001 B Accounting 2022-10-242022-10-281.002 C Sales 2022-10-262022-10-311.003 D Sales 2022-10-312022-11-081.004 E IT 2022-11-032022-11-091.005 F R&D 2022-11-072022-11-180.956 G IT 2022-11-102022-11-170.707 H Sales 2022-11-142022-11-220.358 I Accounting 2022-11-182022-11-230.109 J Accounting 2022-11-232022-12-010.0010 K Sales 2022-11-282022-12-050.0011 L IT 2022-11-302022-12-050.00Tecnologia
Para facilitar a construção do gráfico de Gantt com esses dados, precisamos calcular mais quatro colunas que representarão as seguintes informações:
Quantos dias se passaram/passariam desde o início geral do projeto até a data de início de cada tarefa:
task team start end completion_frac days_to_start \
0 A R&D 2022-10-202022-10-311.0001 B Accounting 2022-10-242022-10-281.0042 C Sales 2022-10-262022-10-311.0063 D Sales 2022-10-312022-11-081.00114 E IT 2022-11-032022-11-091.00145 F R&D 2022-11-072022-11-180.95186 G IT 2022-11-102022-11-170.70217 H Sales 2022-11-142022-11-220.35258 I Accounting 2022-11-182022-11-230.10299 J Accounting 2022-11-232022-12-010.003410 K Sales 2022-11-282022-12-050.003911 L IT 2022-11-302022-12-050.0041
days_to_end task_duration completion_days
0111212.001855.0021166.0031999.0042077.005291211.4062885.6073393.1583460.6094290.00104680.00114660.00Tecnologia
Agora, estamos prontos para gerar um gráfico de Gantt básico no matplotlib:
Esse gráfico ainda precisa de alguns ajustes para extrair o máximo de informação:
Adicionar um título relevante e rótulos no eixo x (datas)
Inverter o eixo y para ter as tarefas em ordem cronológica de cima para baixo
Adicionar uma grade
Colorir as tarefas por time
Exibir uma legenda
Adicionar o status de conclusão das tarefas
Vamos implementar tudo isso já já. Antes, porém, vamos ver outra forma de construir um gráfico de Gantt básico.
Usando broken_barh()
Quando algumas tarefas têm duas ou mais subtarefas distribuídas ao longo do tempo, devemos usar outro método do matplotlib – broken_barh().
Para ter dados de exemplo e testar essa abordagem, vamos fazer o seguinte:
Pegar do nosso dataframe inicial apenas as tarefas atribuídas ao time de Sales (por enquanto, vamos ignorar a coluna completion_frac).
Renomear as colunas start e end para start_1 e end_1, respectivamente (por conveniência).
Adicionar mais subtarefas a algumas das tarefas disponíveis.
Para cada subtarefa, calcular as três colunas mostradas acima representando:
Quantos dias se passaram/passariam desde o início geral do projeto até a data de início de cada subtarefa.
Quantos dias se passaram/passariam desde o início geral do projeto até a data de término de cada subtarefa.
A duração de cada subtarefa, incluindo as datas de início e de término.
# 1
df2 = df[df['team']=='Sales'][['task','team','start','end']]# 2
df2.rename(columns={'start':'start_1','end':'end_1'}, inplace=True)
df2.reset_index(drop=True, inplace=True)# 3
df2['start_2']= pd.to_datetime([None,'10 Nov 2022','25 Nov 2022',None])
df2['end_2']= pd.to_datetime([None,'14 Nov 2022','28 Nov 2022',None])
df2['start_3']= pd.to_datetime([None,None,'1 Dec 2022',None])
df2['end_3']= pd.to_datetime([None,None,'5 Dec 2022',None])# 4for i in[1,2,3]:
suffix ='_'+str(i)
df2['days_to_start'+ suffix]=(df2['start'+ suffix]- df2['start_1'].min()).dt.days
df2['days_to_end'+ suffix]=(df2['end'+ suffix]- df2['start_1'].min()).dt.days
df2['task_duration'+ suffix]= df2['days_to_end'+ suffix]- df2['days_to_start'+ suffix]+1print(df2)Tecnologia
Saída:
task team start_1 end_1 start_2 end_2 start_3 \
0 C Sales 2022-10-262022-10-31 NaT NaT NaT
1 D Sales 2022-10-312022-11-082022-11-102022-11-14 NaT
2 H Sales 2022-11-142022-11-222022-11-252022-11-282022-12-013 K Sales 2022-11-282022-12-05 NaT NaT NaT
end_3 days_to_start_1 days_to_end_1 task_duration_1 \
0 NaT 0561 NaT 513922022-12-05192793 NaT 33408
days_to_start_2 days_to_end_2 task_duration_2 days_to_start_3 \
0 NaN NaN NaN NaN
115.019.05.0 NaN
230.033.04.036.03 NaN NaN NaN NaN
days_to_end_3 task_duration_3
0 NaN NaN
1 NaN NaN
240.05.03 NaN NaN Tecnologia
Repare que agora a tarefa D tem duas subtarefas, a tarefa H tem três subtarefas e as tarefas C e K têm uma subtarefa cada. Portanto, D e H são as tarefas para as quais vamos aplicar o método broken_barh(). Como a sintaxe desse método é um pouco menos intuitiva que a do barh(), vamos ver seus principais parâmetros e formatos. Os parâmetros obrigatórios de broken_barh() são:
xranges – uma sequência de tuplas no formato (xmin, xwidth) para indicar o início e a extensão de cada barra. Aqui, cada barra representa uma subtarefa. Ou seja, esse parâmetro exibe a data de início e a duração de cada subtarefa.
yrange – uma tupla no formato (ymin, yheight) para indicar a posição em y e a altura de cada barra.
Agora, vamos plotar nosso gráfico de Gantt "quebrado". O passo a passo é:
Criar uma figura com subplots.
Iterar pelas linhas do dataframe e verificar se a tarefa tem uma, duas ou três subtarefas. Com base nisso, fazer o seguinte:
Uma subtarefa: plotar uma barra usando o método barh(), como fizemos antes.
Duas subtarefas: plotar duas barras usando broken_barh().
Três subtarefas: plotar três barras usando broken_barh().
Adicionar ajustes básicos: definir e rotular os ticks do eixo y.
No código acima, também podemos usar o método broken_barh() para plotar as barras das tarefas com apenas uma subtarefa. Nesse caso, basta substituir esta linha:
task team start end completion_frac days_to_start \
0 A R&D 2022-10-202022-10-311.0001 B Accounting 2022-10-242022-10-281.0042 C Sales 2022-10-262022-10-311.0063 D Sales 2022-10-312022-11-081.00114 E IT 2022-11-032022-11-091.00145 F R&D 2022-11-072022-11-180.95186 G IT 2022-11-102022-11-170.70217 H Sales 2022-11-142022-11-220.35258 I Accounting 2022-11-182022-11-230.10299 J Accounting 2022-11-232022-12-010.003410 K Sales 2022-11-282022-12-050.003911 L IT 2022-11-302022-12-050.0041
days_to_end task_duration completion_days
0111212.001855.0021166.0031999.0042077.005291211.4062885.6073393.1583460.6094290.00104680.00114660.00Tecnologia
Se você precisa de mais prática para ler e escrever qualquer código em Python com tranquilidade, o curso Intermediate Python é um ótimo ponto de partida.
Colorindo tarefas por time
Agora, vamos colorir cada barra (que representa uma tarefa) de acordo com o time responsável. Para isso, vamos:
Criar um dicionário com os nomes dos times como chaves e cores básicas do matplotlib como valores.
Criar uma figura com subplots.
Iterar pelas linhas do dataframe, criar uma barra para cada linha e aplicar a cor correspondente ao time.
Adicionar todos os ajustes básicos que aplicamos antes.
Falta no gráfico acima uma legenda que mostre qual cor corresponde a qual time. Para resolver, vamos criar patches – objetos 2D do matplotlib preenchidos com uma cor definida. Usaremos a classe matplotlib.patches.Patch para gerar uma lista de patches, um para cada time, com a cor apropriada:
patches =[]for team in team_colors:
patches.append(matplotlib.patches.Patch(color=team_colors[team]))Tecnologia
Agora, podemos adicionar a legenda ao gráfico:
fig, ax = plt.subplots()for index, row in df.iterrows():
plt.barh(y=row['task'], width=row['task_duration'], left=row['days_to_start']+1, color=team_colors[row['team']])
plt.title('Project Management Schedule of Project X', fontsize=15)
plt.gca().invert_yaxis()
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])
ax.xaxis.grid(True, alpha=0.5)# Adicionando uma legenda
ax.legend(handles=patches, labels=team_colors.keys(), fontsize=11)
plt.show()Tecnologia
Saída:
O gráfico de Gantt acima ficou bem mais informativo.
Até agora, não usamos a coluna completion_days que calculamos no início do tutorial. Vamos usá-la agora para deixar o gráfico mais claro, mostrando em que estágio de conclusão cada tarefa está.
Tecnicamente, vamos adicionar outra barra por cima de cada barra já construída. A barra inferior representa a duração total da tarefa em dias alocados, enquanto a superior corresponde ao status de conclusão dessa tarefa em dias alocados.
Para cada tarefa, as duas barras terão a mesma cor do time correspondente, mas a barra inferior será mais clara que a superior para destacar a diferença entre elas.
Em outras palavras, se um time estiver acima do ritmo em uma tarefa, a combinação das duas barras vai parecer que o time já trabalhou mais dias do que o esperado (indicando que a tarefa provavelmente será concluída antes do prazo).
No caso oposto, se um time estiver abaixo do ritmo, a combinação das barras vai mostrar que o time trabalhou menos dias que o esperado (indicando que a tarefa provavelmente será concluída após o prazo).
fig, ax = plt.subplots()for index, row in df.iterrows():# Barra inferior - duração total da tarefa
plt.barh(y=row['task'], width=row['task_duration'], left=row['days_to_start']+1, color=team_colors[row['team']], alpha=0.4)# Barra superior - status de conclusão
plt.barh(y=row['task'], width=row['completion_days'], left=row['days_to_start']+1, color=team_colors[row['team']])
plt.title('Project Management Schedule of Project X', fontsize=15)
plt.gca().invert_yaxis()
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])
ax.xaxis.grid(True, alpha=0.5)
ax.legend(handles=patches, labels=team_colors.keys(), fontsize=11)
plt.show()Tecnologia
Saída:
No gráfico acima, dá para ver que os times não avançam no mesmo ritmo — algo comum em projetos reais. Para extrair mais informação, vamos supor que a data atual é 17 de novembro de 2022 e marcá-la no gráfico:
fig, ax = plt.subplots()for index, row in df.iterrows():
plt.barh(y=row['task'], width=row['task_duration'], left=row['days_to_start']+1, color=team_colors[row['team']], alpha=0.4)
plt.barh(y=row['task'], width=row['completion_days'], left=row['days_to_start']+1, color=team_colors[row['team']])
plt.title('Project Management Schedule of Project X', fontsize=15)
plt.gca().invert_yaxis()
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])
ax.xaxis.grid(True, alpha=0.5)
ax.legend(handles=patches, labels=team_colors.keys(), fontsize=11)# Marcando a data atual no gráfico
ax.axvline(x=29, color='r', linestyle='dashed')
ax.text(x=29.5, y=11.5, s='17/11', color='r')
plt.show()Tecnologia
Saída:
Podemos fazer as seguintes observações sobre o status atual do Projeto X:
O time de R&D está acima do ritmo na tarefa F e provavelmente a concluirá antes do prazo.
O time de IT está atrasado na tarefa G e provavelmente precisa de suporte.
O time de Sales está seguindo o cronograma na tarefa H.
O time de Accounting começou a tarefa I adiantado em relação ao cronograma do projeto.
Essas observações ajudam líderes de time e o gerente do projeto a ajustar o cronograma e alocar recursos a tempo para evitar atrasos nas entregas.
Outros possíveis ajustes
Podemos adicionar mais detalhes ao nosso gráfico de Gantt no matplotlib. Por exemplo:
Adicionar o percentual de conclusão em cada barra.
Subdividir algumas tarefas em subtarefas (já vimos como fazer isso tecnicamente mais acima).
Anotar tarefas correlacionadas.
Destacar marcos e prazos críticos.
Realçar fins de semana e feriados.
Ordenar as barras por time ou tipo de tarefa.
Adicionar minor ticks no eixo x para aumentar a granularidade de informação.
Melhorar a formatação geral e o layout do gráfico.
É importante, no entanto, manter o gráfico de Gantt limpo e evitar excesso de detalhes. Como em qualquer visualização de dados, precisamos equilibrar a quantidade de informação com a legibilidade do gráfico e também do código usado para construí-lo.
Comece a criar seu próprio gráfico de Gantt em Python com Matplotlib
Para resumir, neste tutorial, exploramos:
o que é um gráfico de Gantt
que tipo de informação ele exibe
quando ele é usado
as diferentes formas e nuances de criar gráficos de Gantt com matplotlib
como fazer um gráfico de Gantt em Python com matplotlib
como ajustá-lo para deixá-lo mais informativo
como interpretar o resultado final.
Além disso, vimos vários exemplos de gráficos de Gantt e o passo a passo para construí-los.
Para uma abordagem mais integrada de como criar gráficos impactantes e informativos em Python, confira nossa trilha de habilidades Data Visualization with Python.
Este tutorial demonstra como usar o Matplotlib, uma poderosa biblioteca de visualização de dados em Python, para criar gráficos de linha, barra e dispersão com dados do mercado de ações.
Este tutorial prático se aprofunda na criação e na personalização de gráficos de linhas com o Matplotlib, uma biblioteca avançada de visualização de dados em Python.
Explore vários tipos de gráficos de dados, desde os mais comuns até os avançados e não convencionais, o que eles mostram, quando usá-los, quando evitá-los e como criá-los e personalizá-los em Python.
Neste passo a passo, vamos falar sobre o que é um gráfico de Gantt, por que e quando esse tipo de visualização é útil, como fazer um gráfico de Gantt em Python com matplotlib e como personalizá-lo. No caminho, vamos construir alguns exemplos de gráficos de Gantt em matplotlib.
O que é um gráfico de Gantt e por que ele é útil?
Um gráfico de Gantt é um tipo de gráfico de barras usado para ilustrar um cronograma completo de planejamento e gestão de projetos. Ele costuma exibir itens como nomes das tarefas do projeto, datas de início e término, times responsáveis por cada tarefa, status de conclusão em percentual ou fração, desempenho por time e marcos importantes do projeto.
Os nomes das tarefas ficam no eixo y do gráfico de Gantt, geralmente ordenados por data de início em ordem cronológica de cima para baixo. Já o eixo x representa períodos de tempo, e a largura de cada barra corresponde à duração de execução de cada tarefa.
Como um gráfico de Gantt é, essencialmente, uma forma específica de gráfico de barras horizontal, podemos criá-lo em várias bibliotecas de visualização de dados do Python, incluindo matplotlib, Plotly, Bokeh e Altair. Neste tutorial, vamos focar em criar gráficos de Gantt na mais popular delas – o matplotlib.
Se você quiser explorar outras maneiras de criar um gráfico de Gantt e outros tipos de gráficos em Python, confira o curso Introduction to Data Visualization with Plotly in Python. Se precisar revisar ou desenvolver suas habilidades em matplotlib, estes cursos vão ajudar: Introduction to Data Visualization with Matplotlib e Python for MATLAB Users.
Como fazer um gráfico de Gantt em Python com Matplotlib
Usando barh()
Vamos começar criando um gráfico de Gantt básico no matplotlib usando o método
barh()dematplotlib.pyplot.Primeiro, precisamos importar as bibliotecas necessárias:
Em seguida, vamos criar dados de exemplo para trabalhar:
Saída:
Para facilitar a construção do gráfico de Gantt com esses dados, precisamos calcular mais quatro colunas que representarão as seguintes informações:
Vamos conferir o que obtivemos:
Saída:
Agora, estamos prontos para gerar um gráfico de Gantt básico no matplotlib:
Saída:
Esse gráfico ainda precisa de alguns ajustes para extrair o máximo de informação:
Vamos implementar tudo isso já já. Antes, porém, vamos ver outra forma de construir um gráfico de Gantt básico.
Usando
broken_barh()Quando algumas tarefas têm duas ou mais subtarefas distribuídas ao longo do tempo, devemos usar outro método do matplotlib –
broken_barh().Para ter dados de exemplo e testar essa abordagem, vamos fazer o seguinte:
completion_frac).starteendparastart_1eend_1, respectivamente (por conveniência).Saída:
Repare que agora a tarefa D tem duas subtarefas, a tarefa H tem três subtarefas e as tarefas C e K têm uma subtarefa cada. Portanto, D e H são as tarefas para as quais vamos aplicar o método
broken_barh(). Como a sintaxe desse método é um pouco menos intuitiva que a dobarh(), vamos ver seus principais parâmetros e formatos. Os parâmetros obrigatórios debroken_barh()são:xranges– uma sequência de tuplas no formato (xmin,xwidth) para indicar o início e a extensão de cada barra. Aqui, cada barra representa uma subtarefa. Ou seja, esse parâmetro exibe a data de início e a duração de cada subtarefa.yrange– uma tupla no formato (ymin,yheight) para indicar a posição em y e a altura de cada barra.Agora, vamos plotar nosso gráfico de Gantt "quebrado". O passo a passo é:
barh(), como fizemos antes.broken_barh().broken_barh().Saída:
No código acima, também podemos usar o método
broken_barh()para plotar as barras das tarefas com apenas uma subtarefa. Nesse caso, basta substituir esta linha:por esta:
Essa abordagem também deixa o código mais uniforme e legível.
Como personalizar um gráfico de Gantt no Matplotlib
Vamos voltar ao nosso dataframe inicial:
Saída:
e ao nosso primeiro gráfico de Gantt:
Saída:
Em particular, queremos adicionar algumas personalizações para tornar o gráfico mais informativo.
Para se aprofundar na personalização de gráficos com matplotlib, confira: Matplotlib Tutorial: Python Plotting e a Matplotlib Cheat Sheet: Plotting in Python.
Ajustes básicos no gráfico de Gantt
Incluem:
Adicionando um título
Ter um título claro é essencial para qualquer gráfico, inclusive um gráfico de Gantt. Vamos assumir que nosso projeto se chama Projeto X:
Saída:
Ajustando e personalizando os eixos e adicionando uma grade
Nesta etapa, vamos partir do código anterior e fazer o seguinte:
ax.Saída:
Se você precisa de mais prática para ler e escrever qualquer código em Python com tranquilidade, o curso Intermediate Python é um ótimo ponto de partida.
Colorindo tarefas por time
Agora, vamos colorir cada barra (que representa uma tarefa) de acordo com o time responsável. Para isso, vamos:
Saída:
Adicionando uma legenda
Falta no gráfico acima uma legenda que mostre qual cor corresponde a qual time. Para resolver, vamos criar patches – objetos 2D do matplotlib preenchidos com uma cor definida. Usaremos a classe matplotlib.patches.Patch para gerar uma lista de patches, um para cada time, com a cor apropriada:
Agora, podemos adicionar a legenda ao gráfico:
Saída:
O gráfico de Gantt acima ficou bem mais informativo.
Você vai encontrar mais técnicas para melhorar a estética e a legibilidade dos gráficos no curso Improving Your Data Visualizations in Python.
Adicionando o status de conclusão
Até agora, não usamos a coluna
completion_daysque calculamos no início do tutorial. Vamos usá-la agora para deixar o gráfico mais claro, mostrando em que estágio de conclusão cada tarefa está.Tecnicamente, vamos adicionar outra barra por cima de cada barra já construída. A barra inferior representa a duração total da tarefa em dias alocados, enquanto a superior corresponde ao status de conclusão dessa tarefa em dias alocados.
Para cada tarefa, as duas barras terão a mesma cor do time correspondente, mas a barra inferior será mais clara que a superior para destacar a diferença entre elas.
Em outras palavras, se um time estiver acima do ritmo em uma tarefa, a combinação das duas barras vai parecer que o time já trabalhou mais dias do que o esperado (indicando que a tarefa provavelmente será concluída antes do prazo).
No caso oposto, se um time estiver abaixo do ritmo, a combinação das barras vai mostrar que o time trabalhou menos dias que o esperado (indicando que a tarefa provavelmente será concluída após o prazo).
Saída:
No gráfico acima, dá para ver que os times não avançam no mesmo ritmo — algo comum em projetos reais. Para extrair mais informação, vamos supor que a data atual é 17 de novembro de 2022 e marcá-la no gráfico:
Saída:
Podemos fazer as seguintes observações sobre o status atual do Projeto X:
Essas observações ajudam líderes de time e o gerente do projeto a ajustar o cronograma e alocar recursos a tempo para evitar atrasos nas entregas.
Outros possíveis ajustes
Podemos adicionar mais detalhes ao nosso gráfico de Gantt no matplotlib. Por exemplo:
É importante, no entanto, manter o gráfico de Gantt limpo e evitar excesso de detalhes. Como em qualquer visualização de dados, precisamos equilibrar a quantidade de informação com a legibilidade do gráfico e também do código usado para construí-lo.
Comece a criar seu próprio gráfico de Gantt em Python com Matplotlib
Para resumir, neste tutorial, exploramos:
Além disso, vimos vários exemplos de gráficos de Gantt e o passo a passo para construí-los.
Para uma abordagem mais integrada de como criar gráficos impactantes e informativos em Python, confira nossa trilha de habilidades Data Visualization with Python.