Trabalho prático de Teoria dos Grafos (PUC Minas) que extrai eventos, comentários e reviews do repositório LadybirdBrowser/ladybird e os modela como redes de colaboração — com extração via API do GitHub em Python e construção, análise e exportação dos grafos em Java.
- Sobre o projeto
- Arquitetura
- Estrutura de pastas
- Dados extraídos
- Tipos de grafos gerados
- Métricas de análise
- Como usar
- Exportação para Gephi
- Documentação
- Tecnologias e dependências
Este projeto modela as interações de colaboração do repositório LadybirdBrowser/ladybird — um navegador open source com mais de 54 mil estrelas e milhares de pull requests, issues e reviews — como redes de grafos direcionados e ponderados. A pipeline é dividida em duas etapas:
- Extração (Python): coleta issues, pull requests, comentários, reviews e eventos via API REST do GitHub, com paginação automática, controle de rate limit e extração paralela (threads), salvando tudo em CSV.
- Análise (Java): carrega os CSVs, constrói diferentes tipos de grafos (lista ou matriz de adjacência), calcula métricas de centralidade, estrutura e comunidades, e exporta os resultados em formato GEXF para visualização no Gephi.
Notebooks Jupyter complementares (app/*.ipynb) replicam parte da modelagem em Python com NetworkX/Pandas, usados para exploração e validação cruzada dos grafos construídos em Java.
┌──────────────────────────────────────────────────────────────┐
│ Extração (Python) │
│ GitHub REST API → core/api.py (paginação, rate limit, │
│ threads) → issues.py / prs.py / comments.py → CSV │
└────────────────────────────┬─────────────────────────────────┘
│ app/data/*.csv
┌────────────────────────────▼─────────────────────────────────┐
│ Análise (Java) │
│ loader/ → carrega e mapeia os CSVs (GerenciadorUnificado) │
│ builder/ → constrói os 4 tipos de grafo (GerenciadorGrafos) │
│ model/ → AbstractGraph (Lista ou Matriz de Adjacência) │
│ service/ → métricas de centralidade, estrutura e comunidade │
│ ui/ → menu interativo de análise e exportação │
└────────────────────────────┬─────────────────────────────────┘
│ app/exports/*.gexf
Visualização no Gephi
Padrões centrais:
| Padrão | Onde se aplica |
|---|---|
| Strategy / Template Method | AbstractGraph com implementações AdjacencyListGraph e AdjacencyMatrixGraph |
| Builder especializado por tipo de grafo | ConstrutorGrafo* coordenados pela fachada GerenciadorGrafos |
| Acúmulo de pesos por par de usuários | ConstrutorGrafoIntegrado — combina todas as interações em arestas ponderadas |
| Algoritmo de Brandes | Betweenness centrality (CentralityMetrics) |
| Label Propagation | Detecção de comunidades (CommunityMetrics) |
| Rate limiting + retry com backoff exponencial | Cliente da API do GitHub (core/api.py), thread-safe |
| Extração paralela | ThreadPoolExecutor em prs.py (controlado por MAX_THREADS) |
grafos-tp1/
├── app/
│ ├── data/ # CSVs extraídos do GitHub
│ │ ├── issue_authors.csv # Autores das issues
│ │ ├── closed_issues.csv # Issues fechadas
│ │ ├── issue_comments.csv # Comentários em issues
│ │ ├── issue_events.csv # Eventos de issues (closed, labeled...)
│ │ ├── pr_events.csv # Eventos de PRs (abertura, merge, fechamento)
│ │ ├── pr_reviews.csv # Reviews de pull requests
│ │ └── pr_comments.csv # Comentários em PRs
│ │
│ ├── extraction/ # Scripts Python de extração
│ │ ├── core/
│ │ │ ├── api.py # Cliente HTTP da API GitHub (rate limit, retries, threads)
│ │ │ └── io.py # Persistência em CSV
│ │ ├── comments.py # Extração de comentários
│ │ ├── issues.py # Extração de issues e seus eventos
│ │ ├── prs.py # Extração de PRs, reviews e eventos (paralela)
│ │ ├── extract_pr_events_quick.py # Extração rápida só de eventos de PR
│ │ ├── check_rate_limit.py # Verifica o rate limit atual da API
│ │ └── main.py # Menu principal de extração
│ │
│ ├── exports/ # Grafos exportados em GEXF (Gephi)
│ │ ├── grafo_comentarios.gexf
│ │ ├── grafo_fechamentoissues.gexf
│ │ ├── grafo_pullrequests.gexf
│ │ └── grafo_grafointegrado.gexf
│ │
│ ├── graph.ipynb # Modelagem exploratória dos 3 grafos base (NetworkX)
│ ├── complete_graph.ipynb # Modelagem do grafo integrado ponderado + métricas
│ ├── analysis.ipynb # Análise e visualização dos grafos extraídos
│ │
│ └── api/ # Aplicação Java (Maven)
│ ├── pom.xml
│ └── src/main/java/com/grafos/puc/
│ ├── Main.java # Ponto de entrada — carrega dados e inicia o menu
│ ├── loader/ # Leitura e mapeamento dos CSVs
│ │ ├── GerenciadorUnificado.java
│ │ ├── issues/ # Issue, GerenciadorIssues, ProcessadorIssuesGenerico
│ │ ├── pullRequest/ # PullRequest, Review, GerenciadorPullRequests...
│ │ └── comentarios/ # ItemComComentarios, processadores de comentários
│ ├── builder/ # Construtores dos 4 tipos de grafo
│ │ ├── GerenciadorGrafos.java
│ │ ├── ConstrutorGrafoAbstrato.java
│ │ ├── ConstrutorGrafoComentarios.java
│ │ ├── ConstrutorGrafoFechamentoIssues.java
│ │ ├── ConstrutorGrafoReviewPullRequests.java
│ │ └── ConstrutorGrafoIntegrado.java
│ ├── model/ # Representações de grafo direcionado
│ │ ├── AbstractGraph.java
│ │ ├── AdjacencyListGraph.java
│ │ └── AdjacencyMatrixGraph.java
│ ├── service/ # Cálculo de métricas
│ │ ├── GraphMetricsService.java
│ │ └── metrics/ # CentralityMetrics, StructureMetrics, CommunityMetrics
│ └── ui/ # Menus interativos de análise e exportação
│ ├── GerenciadorMenu.java
│ └── AnaliseGrafo.java
├── docs/ # Documentação e relatórios do TP1
│ ├── LadybirdBrowser.md
│ ├── enunciado-tp1.pdf
│ ├── relatorio-tp1.pdf
│ └── apresentacao.pdf
├── images/ # Banners usados neste README
├── .env # GITHUB_TOKEN (nunca versionar)
├── LICENSE
└── README.md
Os dados são coletados do repositório LadybirdBrowser/ladybird e persistidos em app/data/ no formato CSV:
| Arquivo | Conteúdo | Linhas (aprox.) |
|---|---|---|
issue_authors.csv |
Autor, data e título de cada issue criada | ~1.300 |
closed_issues.csv |
Quem fechou cada issue e quando | ~750 |
issue_comments.csv |
Comentários em issues (ator, corpo, data, URL) | ~27.600 |
issue_events.csv |
Eventos de issues — closed, labeled, etc. |
~5.000 |
pr_events.csv |
Eventos de PR — abertura, fechamento, merge, merged_by |
~5.700 |
pr_reviews.csv |
Reviews de PR (ator, estado, corpo) | ~11.000 |
pr_comments.csv |
Comentários em pull requests | ~22.700 |
O cliente da API (
core/api.py) trata paginação automática, monitora os headersX-RateLimit-*, aguarda o reset quando o limite se esgota e faz retry com backoff exponencial em falhas transitórias — tudo de forma thread-safe para suportar a extração paralela de PRs (MAX_THREADS).
A aplicação Java constrói 4 grafos direcionados, na seguinte ordem:
Quem comenta em issues e PRs, conectado a quem abriu o item.
Une comentários de issues e de pull requests em um único grafo: aresta comentarista → autor do item. Construído por ConstrutorGrafoComentarios.
Quem fecha issues abertas por outras pessoas.
Cruza issue_authors.csv com closed_issues.csv: aresta quem fechou → quem criou a issue. Construído por ConstrutorGrafoFechamentoIssues.
Quem revisa o código de quem.
Modela o processo de revisão por pares: aresta revisor → autor do PR. Construído por ConstrutorGrafoReviewPullRequests.
Todas as interações combinadas em uma única rede, com pesos acumulados por par de usuários.
Soma, para cada par (origem, destino), o peso de todas as interações registradas entre eles:
| Interação | Peso |
|---|---|
| Comentário em issue | 3.0 |
| Comentário em PR | 2.0 |
| Review de PR | 4.0 |
| Merge de PR | 5.0 |
Construído por ConstrutorGrafoIntegrado, que mantém um mapa (origem→destino) → peso acumulado antes de gerar as arestas finais — útil para identificar os colaboradores mais influentes na rede como um todo.
Os notebooks
graph.ipynbecomplete_graph.ipynbreproduzem a mesma modelagem em Python/NetworkX, servindo como conferência cruzada dos grafos construídos em Java.
Implementadas em service/metrics/ e expostas via GraphMetricsService e o menu de análise (AnaliseGrafo):
| Categoria | Métricas | Classe |
|---|---|---|
| Centralidade | Degree, In-degree, Out-degree, Betweenness (Brandes), Closeness, PageRank | CentralityMetrics |
| Estrutura e Coesão | Densidade, Coeficiente de clustering, Assortatividade, Diâmetro | StructureMetrics |
| Comunidades | Detecção via Label Propagation, Modularidade (grafos direcionados/ponderados), Bridging ties | CommunityMetrics |
O menu de análise (GerenciadorMenu → AnaliseGrafo) permite, para qualquer grafo carregado:
- Ver estatísticas básicas (vértices, arestas, densidade)
- Rankear vértices por grau
- Inspecionar propriedades estruturais
- Calcular métricas de centralidade
- Calcular métricas de estrutura avançadas
- Detectar comunidades
- Gerar um relatório completo com todas as métricas
Há ainda uma comparação lado a lado entre todos os grafos carregados (vértices ativos, arestas e densidade).
- Java 21 (compilação e execução via Maven)
- Python 3.x com
requestsepython-dotenv(epandas,networkx,matplotlib,jupyterpara os notebooks) - Token do GitHub válido, em um arquivo
.envna raiz do projeto - Maven instalado
# 1. Clone o repositório
git clone <url-do-repositorio>
cd grafos-tp1
# 2. Instale as dependências Python
pip install requests python-dotenv pandas networkx matplotlib jupyter
# 3. Configure o token do GitHub
echo "GITHUB_TOKEN=seu_token_aqui" > .env
# 4. Compile o projeto Java
mvn clean compile -f app/api/pom.xmlpython app/extraction/main.pyMenu interativo com as opções: coletar issues, coletar pull requests, coletar eventos de issues, coletar apenas eventos de PR, coletar tudo. Os CSVs são salvos em app/data/.
# Verificar o rate limit atual da API antes de uma extração longa
python app/extraction/check_rate_limit.pymvn exec:java -Dexec.mainClass="com.grafos.puc.Main" -f app/api/pom.xmlAo iniciar, a aplicação carrega os CSVs de app/data/, pede para escolher entre Lista de Adjacência (grafos esparsos, menor uso de memória) ou Matriz de Adjacência (grafos densos, acesso mais rápido às arestas), constrói os 4 grafos na ordem descrita acima e abre o menu interativo de análise.
# Compilar
mvn clean compile -f app/api/pom.xml
# Executar testes
mvn test -f app/api/pom.xmlPelo menu da aplicação Java (opção 4. Exportar grafo para GEPHI), qualquer grafo carregado pode ser salvo em formato GEXF dentro de app/exports/, pronto para importação e visualização no Gephi:
grafo_comentarios.gexfgrafo_fechamentoissues.gexfgrafo_pullrequests.gexfgrafo_grafointegrado.gexf
A exportação é implementada diretamente em AdjacencyListGraph/AdjacencyMatrixGraph (exportToGEPHI), gerando um XML compatível com a especificação GEXF 1.2 — incluindo rótulos, pesos de vértices e de arestas.
Na pasta docs/ você encontra:
LadybirdBrowser.md— análise do repositório LadybirdBrowser/ladybird que justifica sua escolha como base de dados (popularidade, volume de interações, estrutura de colaboradores)enunciado-tp1.pdf— enunciado do trabalho prático, com requisitos e critérios de avaliaçãorelatorio-tp1.pdf— relatório final com a análise dos resultados e discussão das métricasapresentacao.pdf— slides usados na apresentação/vídeo do trabalho
| Categoria | Tecnologia |
|---|---|
| Linguagem (análise) | Java 21 |
| Build | Maven 3.9+ |
| Linguagem (extração) | Python 3.x |
| HTTP / variáveis de ambiente | requests, python-dotenv |
| Análise e modelagem de grafos | networkx, pandas, matplotlib |
| Notebooks | Jupyter |
| API de dados | GitHub REST API v3 |
| Visualização de grafos | Gephi (via exportação GEXF) |
| Formato de dados | CSV |
- Todos os comandos devem ser executados a partir do diretório raiz do projeto
- O token do GitHub (
GITHUB_TOKEN) é obrigatório para a extração de dados — nunca versione o.env - Os arquivos CSV precisam estar em
app/data/para a aplicação Java carregar os grafos - A aplicação suporta tanto grafos esparsos (lista de adjacência) quanto densos (matriz de adjacência)
MAX_THREADScontrola o paralelismo da extração de PRs — reduza caso o rate limit se esgote rapidamente
Este projeto está sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.
Fonte do banner: João Paulo Carneiro Aramuni
