History of thgl_github
The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.
[entries] New entry: thgl_github 0f1ae16
diff --git a/entries/thgl_github/__init__.py b/entries/thgl_github/__init__.py
new file mode 100644
index 0000000..6d088b0
--- /dev/null
+++ b/entries/thgl_github/__init__.py
@@ -0,0 +1,107 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+
+import pandas
+
+from .. import *
+
+
+title = "GitHub activity in January and March 2024 (thgl-github and thgl-software, TGB 2.0)"
+description = """Temporal heterogeneous networks of the activity on GitHub, from the `thgl-github` and `thgl-software` datasets of the Temporal Graph Benchmark (TGB 2.0), built from the public event stream of GitHub collected by GH Archive. The nodes are users, repositories, issues and pull requests, anonymized by TGB (they are identified only by indices). Each timestamped directed edge is an event of one of 14 kinds: a user opens, closes or reopens an issue or a pull request (with a corresponding edge from the issue or pull request to its repository), a user is added as a member of a repository, or a repository is forked from another one (the edge goes from the new fork to the forked repository). The comments on issues and pull requests, which TGB extracted as well, were removed by TGB since they rarely interact more than once. The networks are:
+
+- `march_2024` (`thgl-github`): the activity of March 2024, keeping only the nodes with more than two edges;
+- `january_2024` (`thgl-software`): the activity of January 2024, keeping only the nodes with at least 10 edges.
+
+The networks have the following properties:
+
+- `kind`: the kind of the node: `user`, `repository`, `issue` or `pull_request`.
+- Edge `relation`: the kind of event: `user_opened_issue`, `user_closed_issue`, `user_reopened_issue`, `issue_opened_in_repository`, `issue_closed_in_repository`, `issue_reopened_in_repository`, `user_opened_pull_request`, `user_closed_pull_request`, `user_reopened_pull_request`, `pull_request_opened_in_repository`, `pull_request_closed_in_repository`, `pull_request_reopened_in_repository`, `user_added_as_member` or `forked_from`.
+- Edge `time`: the time of the event, in Unix time, as given by TGB. The times appear to be shifted by the offset of the US Eastern time zone (4 or 5 hours later than the actual times of the events, which GH Archive gives in UTC): those of `march_2024` span from 2024-03-01 05:00 to 2024-04-01 03:59 UTC, and those of `january_2024` from 2024-01-01 05:01 to 2024-02-01 04:59 UTC."""
+tags = ['Technological', 'Software', 'Online', 'Collaboration', 'Unweighted', 'Multigraph', 'Timestamps', 'Metadata']
+url = ['https://tgb.complexdatalab.com/docs/thg/',
+ 'https://github.com/shenyangHuang/TGB',
+ 'https://www.gharchive.org/']
+citation = [('J. Gastinger, S. Huang, M. Galkin, E. Loghmani, A. Parviz, F. Poursafaei, J. Danovitch, E. Rossi, I. Koutis, H. Stuckenschmidt, R. Rabbany, G. Rabusseau, "TGB 2.0: A Benchmark for Learning on Temporal Knowledge Graphs and Heterogeneous Graphs." Advances in Neural Information Processing Systems 37 (Datasets and Benchmarks Track) (2024)', 'https://doi.org/10.48550/arXiv.2406.09639')]
+icon_hash = None
+upstream_license = ('CC BY 4.0', 'https://creativecommons.org/licenses/by/4.0/')
+upstream_prefix = 'https://object-arbutus.alliancecan.ca/swift/v1/14c95234f6cd4a21a47deafe20cce2a7/tgb'
+files = [(tuple(f'{d}.zip:{d}_{x}.csv' for x in ['edgelist', 'edgemapping',
+ 'nodemapping', 'nodetype']),
+ alt, None)
+ for alt, d in [('march_2024', 'thgl-github'),
+ ('january_2024', 'thgl-software')]]
+
+relations = {"U_SE_O_I": "user_opened_issue",
+ "U_SE_C_I": "user_closed_issue",
+ "U_SE_RO_I": "user_reopened_issue",
+ "I_AO_O_R": "issue_opened_in_repository",
+ "I_AO_C_R": "issue_closed_in_repository",
+ "I_AO_RO_R": "issue_reopened_in_repository",
+ "U_SO_O_P": "user_opened_pull_request",
+ "U_SO_C_P": "user_closed_pull_request",
+ "U_SO_R_P": "user_reopened_pull_request",
+ "P_AO_O_R": "pull_request_opened_in_repository",
+ "P_AO_C_R": "pull_request_closed_in_repository",
+ "P_AO_R_R": "pull_request_reopened_in_repository",
+ "U_CO_A_R": "user_added_as_member",
+ "R_FO_R": "forked_from"}
+kinds = {"user": "user", "repo": "repository", "issue": "issue",
+ "pr": "pull_request"}
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ global files
+ name = __name__.split(".")[-1]
+ for fnames, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ with open_upstream_file(name, fnames[1], "r") as f:
+ # "edge_id,type": relation code and its index
+ ecodes = {int(r["type"]): r["edge_id"] for r in csv.DictReader(f)}
+ with open_upstream_file(name, fnames[2], "r") as f:
+ # "node_type_id,type": node kind and its index
+ nkinds = {int(r["type"]): kinds[r["node_type_id"]] for r in csv.DictReader(f)}
+ with open_upstream_file(name, fnames[3], "rb") as f:
+ ntypes = pandas.read_csv(f, dtype="int64").values
+ with open_upstream_file(name, fnames[0], "rb") as f:
+ # "timestamp,head,tail,relation_type"
+ edges = pandas.read_csv(f, dtype="int64")
+ N = max(ntypes[:, 0].max(), edges["head"].max(), edges["tail"].max()) + 1
+ g = Graph(directed=True)
+ g.add_vertex(N)
+ t = numpy.full(N, -1)
+ t[ntypes[:, 0]] = ntypes[:, 1]
+ assert (t >= 0).all()
+ g.vp.kind = g.new_vp("string", vals=[nkinds[x] for x in t])
+ del t, ntypes
+ g.ep.time = g.new_ep("int64_t")
+ g.add_edge_list(edges[["head", "tail", "timestamp"]].values,
+ eprops=[g.ep.time])
+ rels = edges["relation_type"].values
+ del edges
+ names = {r: relations[c] for r, c in ecodes.items()}
+ g.ep.relation = g.new_ep("string", vals=[names[r] for r in rels])
+ yield alt, g