History of gdelt_outlinks
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] Add the date when each entry was added, and remove icon_hash beff7c9
The dates are those of the commits that first added the entries' files (2020-08-11 for the entries of the initial commit); renamed entries keep the date of their first name. Changed: none
diff --git a/entries/gdelt_outlinks/__init__.py b/entries/gdelt_outlinks/__init__.py
index 2df1f55..14a6b2f 100644
--- a/entries/gdelt_outlinks/__init__.py
+++ b/entries/gdelt_outlinks/__init__.py
@@ -35,7 +35,7 @@ citation = [('The GDELT Project, "Who Links To Whom? The 30M Edge GKG Outlink Do
'https://www.gdeltproject.org/data.html')]
upstream_license = ("GDELT terms of use: unlimited use and redistribution, with citation and a link to the GDELT Project",
"https://www.gdeltproject.org/about.html#termsofuse")
-icon_hash = None
+date_added = '2026-10-31'
# A single file of 2019-01-28, not updated since
upstream_prefix = 'https://data.gdeltproject.org/blog/2019-gkg-outlinks-2016-2018'
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) bc3dbbd
The lists of properties at the end of the descriptions marked edge properties with "Edge" but left node properties unmarked, or grouped them in "Nodes: `a`, ...; `b`, ..." items, so the kind of a property was often unclear. Every item now starts with (Node), (Edge) or (Graph), followed by the property names, a colon and the explanation, one item per property or group of properties; qualifications (kinds of nodes, networks) follow the names in parentheses. Properties that were only named got a short explanation, and a few items that named the wrong kind of property were corrected.
diff --git a/entries/gdelt_outlinks/__init__.py b/entries/gdelt_outlinks/__init__.py
index c0398de..2df1f55 100644
--- a/entries/gdelt_outlinks/__init__.py
+++ b/entries/gdelt_outlinks/__init__.py
@@ -23,8 +23,9 @@ description = """The hyperlink network of the world's online news outlets, from
The network has the following properties:
-- Nodes: `domain`, the web domain.
-- Edges: `num_days`, the number of days on which articles of the source linked to the target; `num_links`, the total number of links (including repeated ones)."""
+- (Node) `domain`: the web domain.
+- (Edge) `num_days`: the number of days on which articles of the source linked to the target.
+- (Edge) `num_links`: the total number of links (including repeated ones)."""
tags = ['Informational', 'Web graph', 'Online', 'Weighted']
url = ['https://blog.gdeltproject.org/who-links-to-whom-the-30m-edge-gkg-outlink-domain-graph-april-2016-to-jan-2019/',
'https://www.gdeltproject.org/data.html']
[entries] Remove unneeded code from the entries 2c69f19
Unneeded "global files" statements, unused imports and variables, f-strings without placeholders, duplicate keys in foodweb_little_rock (keeping the order and the values used), and the second definition of get_lines() in twitter_higgs. Nothing changes in the networks or descriptions. Changed: none
diff --git a/entries/gdelt_outlinks/__init__.py b/entries/gdelt_outlinks/__init__.py
index c1ccab4..c0398de 100644
--- a/entries/gdelt_outlinks/__init__.py
+++ b/entries/gdelt_outlinks/__init__.py
@@ -48,7 +48,6 @@ def fetch_upstream(force=False):
@coerce_props()
@annotate()
def parse(alts=None):
- global files
import pyarrow, pyarrow.csv, pyarrow.compute
name = __name__.split(".")[-1]
with open_upstream_file(name, files[0][0], "rb") as f:
[entries] New entry: gdelt_outlinks b1c40df
diff --git a/entries/gdelt_outlinks/__init__.py b/entries/gdelt_outlinks/__init__.py
new file mode 100644
index 0000000..c1ccab4
--- /dev/null
+++ b/entries/gdelt_outlinks/__init__.py
@@ -0,0 +1,79 @@
+#! /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/>.
+
+from .. import *
+
+title = "GDELT news outlink domain network (2016-2019)"
+description = """The hyperlink network of the world's online news outlets, from the Global Knowledge Graph (GKG) of the GDELT Project, which records the hyperlinks in the body text of every news article that it monitors (links in headers, footers, insets and ads are excluded). From April 22, 2016 to January 28, 2019, GDELT recorded 1.78 billion links in 304 million articles, which it aggregated to a network of web domains: a directed edge from domain u to domain v means that articles of the news outlet u linked to pages of v (a registered domain, collapsed with BigQuery's `NET.REG_DOMAIN()`; the outlet is GDELT's `SourceCommonName`), weighted by the number of days with at least one such link, and by the total number of links. Links of an outlet to its own domain are left out. The network has 4,407,927 domains, of which 99,270 are news outlets with outgoing links. Domain names are as recorded, and are case-sensitive: domains that appear with different capitalizations are different nodes (138,884 of the nodes differ from others only in capitalization).
+
+The network has the following properties:
+
+- Nodes: `domain`, the web domain.
+- Edges: `num_days`, the number of days on which articles of the source linked to the target; `num_links`, the total number of links (including repeated ones)."""
+tags = ['Informational', 'Web graph', 'Online', 'Weighted']
+url = ['https://blog.gdeltproject.org/who-links-to-whom-the-30m-edge-gkg-outlink-domain-graph-april-2016-to-jan-2019/',
+ 'https://www.gdeltproject.org/data.html']
+citation = [('The GDELT Project, "Who Links To Whom? The 30M Edge GKG Outlink Domain Graph April 2016 To Jan 2019." GDELT Blog (2019)',
+ 'https://blog.gdeltproject.org/who-links-to-whom-the-30m-edge-gkg-outlink-domain-graph-april-2016-to-jan-2019/'),
+ ('K. Leetaru, P. A. Schrodt, "GDELT: Global data on events, location, and tone, 1979-2012." International Studies Association Annual Convention (2013)',
+ 'https://www.gdeltproject.org/data.html')]
+upstream_license = ("GDELT terms of use: unlimited use and redistribution, with citation and a link to the GDELT Project",
+ "https://www.gdeltproject.org/about.html#termsofuse")
+icon_hash = None
+
+# A single file of 2019-01-28, not updated since
+upstream_prefix = 'https://data.gdeltproject.org/blog/2019-gkg-outlinks-2016-2018'
+files = [('MASTER-GKG-OUTLINKS-2016-2018.CSV.gz', None, None)]
+
+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
+ import pyarrow, pyarrow.csv, pyarrow.compute
+ name = __name__.split(".")[-1]
+ with open_upstream_file(name, files[0][0], "rb") as f:
+ t = pyarrow.csv.read_csv(
+ f, read_options=pyarrow.csv.ReadOptions(use_threads=False),
+ convert_options=pyarrow.csv.ConvertOptions(
+ column_types={"fromsite": pyarrow.string(),
+ "tosite": pyarrow.string(),
+ "numdays": pyarrow.int64(),
+ "totlinks": pyarrow.int64()},
+ strings_can_be_null=False))
+ src = t.column("fromsite").combine_chunks()
+ tgt = t.column("tosite").combine_chunks()
+ domains = pyarrow.compute.unique(pyarrow.concat_arrays([src, tgt]))
+ domains = domains.sort()
+ s = pyarrow.compute.index_in(src, value_set=domains).to_numpy()
+ d = pyarrow.compute.index_in(tgt, value_set=domains).to_numpy()
+ del src, tgt
+ g = Graph(directed=True)
+ g.add_vertex(len(domains))
+ g.vp.domain = g.new_vp("string", vals=domains.to_pylist())
+ del domains
+ g.ep.num_days = g.new_ep("int64_t")
+ g.ep.num_links = g.new_ep("int64_t")
+ g.add_edge_list(numpy.column_stack((s, d, t.column("numdays").to_numpy(),
+ t.column("totlinks").to_numpy())),
+ eprops=[g.ep.num_days, g.ep.num_links])
+ yield None, g