History of hyperbard
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: hyperbard 22367fa
diff --git a/entries/hyperbard/__init__.py b/entries/hyperbard/__init__.py
new file mode 100644
index 0000000..d777209
--- /dev/null
+++ b/entries/hyperbard/__init__.py
@@ -0,0 +1,96 @@
+#! /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 = "Shakespeare's plays, characters on stage (Hyperbard, 2022)"
+description = """Bipartite networks of the characters of the 37 plays of William Shakespeare and the groups of characters that are on stage together, one network per play, from the Hyperbard dataset of Coupette, Vreeken and Rieck, built from the TEI XML encoding of the Folger Shakespeare editions, as distributed by XGI-data (the "hg-group-mw" representation of Hyperbard). Each play is divided into consecutive parts during which the set of characters on stage does not change; each part is a node, connected to the characters on stage during it, and carries the act and scene it belongs to and the numbers of lines and tokens (words) spoken during it.
+
+The character co-presence networks of the same plays (weighted by the number of scenes in common) are part of the entry `dracor`.
+
+The networks have the following properties:
+
+- `is_group`: whether the node is an on-stage group (otherwise a character).
+- Characters: `name`, the identifier of the character in the Folger edition (e.g. `Hamlet` or `Ghost`; groups of unnamed characters, e.g. attendants, are identified as in the edition, e.g. `ATTENDANTS.CAESAR`).
+- Groups: `index`, the order of the group in the play (from 0); `act` and `scene`, the act and scene of the group (acts 0 and 6 hold the parts before the first act and after the fifth one, e.g. prologues and epilogues); `n_lines` and `n_tokens`, the numbers of lines and tokens spoken while the group is on stage.
+- Graph property `play_type`: the kind of play (`comedy`, `history` or `tragedy`)."""
+tags = ['Social', 'Fictional', 'Unweighted', 'Metadata']
+url = ['https://hyperbard.net/',
+ 'https://zenodo.org/records/22070327',
+ 'https://github.com/xgi-org/xgi-data']
+citation = [('C. Coupette, J. Vreeken, B. Rieck, "All the world\'s a (hyper)graph: A data drama." Digital Scholarship in the Humanities 39(1), 74-96 (2024)', 'https://doi.org/10.1093/llc/fqad071'),
+ ('N. W. Landry, M. Lucas, I. Iacopini, G. Petri, A. Schwarze, A. Patania, L. Torres, "XGI: A Python package for higher-order interaction networks." Journal of Open Source Software 8(85), 5162 (2023)', 'https://doi.org/10.21105/joss.05162')]
+icon_hash = None
+upstream_license = ('CC BY 4.0', 'https://creativecommons.org/licenses/by/4.0/')
+upstream_prefix = 'https://zenodo.org/records/22070327/files'
+
+plays = ['a-midsummer-nights-dream', 'alls-well-that-ends-well',
+ 'antony-and-cleopatra', 'as-you-like-it', 'coriolanus', 'cymbeline',
+ 'hamlet', 'henry-iv-part-1', 'henry-iv-part-2', 'henry-v',
+ 'henry-vi-part-1', 'henry-vi-part-2', 'henry-vi-part-3',
+ 'henry-viii', 'julius-caesar', 'king-john', 'king-lear',
+ 'loves-labors-lost', 'macbeth', 'measure-for-measure',
+ 'much-ado-about-nothing', 'othello', 'pericles', 'richard-ii',
+ 'richard-iii', 'romeo-and-juliet', 'the-comedy-of-errors',
+ 'the-merchant-of-venice', 'the-merry-wives-of-windsor',
+ 'the-taming-of-the-shrew', 'the-tempest',
+ 'the-two-gentlemen-of-verona', 'the-winters-tale', 'timon-of-athens',
+ 'titus-andronicus', 'troilus-and-cressida', 'twelfth-night']
+files = [(f'hyperbard_{p}.json', p.replace("-", "_"), None) for p in plays]
+
+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 fname, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ # HIF (hypergraph interchange format) of XGI
+ with open_upstream_file(name, fname, "r") as f:
+ d = json.load(f)
+ groups = sorted(d["edges"], key=lambda e: int(e["edge"]))
+ gindex = {e["edge"]: i for i, e in enumerate(groups)}
+ assert sorted(int(e) for e in gindex) == list(range(len(groups)))
+ # characters, in the order of their first appearance
+ inc = sorted(d["incidences"], key=lambda x: int(x["edge"]))
+ chars = list(dict.fromkeys(x["node"] for x in inc))
+ cindex = {c: i for i, c in enumerate(chars)}
+ N = len(chars)
+ g = Graph(directed=False)
+ g.add_vertex(N + len(groups))
+ g.vp.is_group = g.new_vp("bool")
+ g.vp.is_group.a[N:] = True
+ g.vp.name = g.new_vp("string", vals=chars + [""] * len(groups))
+ g.vp.index = g.new_vp("int", val=-1)
+ g.vp.index.a[N:] = numpy.arange(len(groups))
+ for k in ["act", "scene", "n_lines", "n_tokens"]:
+ g.vp[k] = g.new_vp("int", val=-1)
+ g.vp[k].a[N:] = [e["attrs"][k] for e in groups]
+ g.add_edge_list(sorted(set((cindex[x["node"]], N + gindex[x["edge"]])
+ for x in inc), key=lambda e: e[::-1]))
+ g.gp.play_type = g.new_gp("string", val=d["metadata"]["play-type"])
+ yield alt, g