Skip to main content

Trajectories of Change

Python 3.11+ License MIT CI Open In Colab

Trajectories_of_Change measures how individual authors move relative to their research field over time. It takes a corpus of publications and their cited references and computes trajectories for a target author or a group of authors across four measures. The package is domain agnostic and runs on any publication dataset that follows its input format. It implements the measures introduced in Trajectories of Change: Approaches for Tracking Knowledge Evolution and the complete pipeline of a follow-up study (see Citing).

The four measures

Measure Output prefix Features
Own Vocabulary vocab_* lemmatised terms of the target's own titles and abstracts
Referenced Vocabulary ref_vocab_* terms of the works the target cites
Citation Identity cocit_* unordered pairs of co-cited authors in the target's reference lists
Embedding Density Estimation (EDE) density_* document embedding coordinates

The three distributional measures are Kullback–Leibler divergences between the target's distribution and the field's, computed in bits per time slice, where the field is the corpus with the target removed. EDE is a kernel density estimate at the target's positions in a document embedding. Definitions and interpretation guidance are in docs/methods.md.

Installation

Use uv. Requires Python 3.11 or newer.

uv add "trajectories-of-change[plotting]"

Without the Plotly plotting extra, if you only need the numbers:

uv add trajectories-of-change

For the toc command line outside a project:

uv tool install "trajectories-of-change[plotting]"

Plain pip install "trajectories-of-change[plotting]" works as well.

Quick start

The repository ships a small synthetic example dataset whose authors behave in known ways by construction, so your first run is verifiable. Clone the repository or download the examples/data folder, or run the same flow in the browser via the Colab notebook.

from trajectories_of_change import load_dataset_bundle, run_metrics
from trajectories_of_change.plotting import plot_multimetric

bundle = load_dataset_bundle(
    "examples/data/publications.parquet",
    "examples/data/references.parquet",
)
metrics = run_metrics(bundle, top_n=5, show_progress=False)

levels = ["vocab_kld_all_level", "ref_vocab_kld_all_level", "cocit_kld_all_level", "density_neglog_level"]
print(metrics[["author_display_name"] + levels].round(2).to_string())

plot_multimetric(metrics, export_dir="outputs/quickstart", show=False)
     author_display_name  vocab_kld_all_level  ref_vocab_kld_all_level  cocit_kld_all_level  density_neglog_level
0         Field-Like, F.                 0.03                     0.01                 0.15                  0.53
1  Stable Vocabulary, V.                13.77                     0.18                 1.44                  0.53
2   Spiky Vocabulary, S.                 0.03                     0.01                 0.15                  0.53
3  Citation Distinct, C.                 0.03                     2.51                18.09                  0.53
4      Density Shift, D.                 0.03                     0.01                 0.15                  2.67

This is the expected pattern, and the outliers are correct results, not a broken install. Each synthetic author carries one built-in behavior, visible in its own column. "Stable Vocabulary, V." holds a stably divergent vocabulary (13.77 bits against a 0.03 baseline; kld_all sums all feature contributions, so values above 1 bit are normal). "Citation Distinct, C." co-cites differently (18.09) and consequently also cites differently worded literature (2.51). "Density Shift, D." moves into a sparser field region (2.67, where lower density values mean denser neighbourhoods). "Spiky Vocabulary, S." is deliberately unremarkable here, its divergence comes as single-slice spikes that the trajectory plots reveal rather than the level. The plot call then lists its exported files and writes the overview figures to outputs/quickstart.

Input data

Two Parquet tables. The examples are real rows from the bundled dataset, whose names are synthetic.

publications.parquet, one row per publication of your corpus:

Column Needed for Type Example
Bibcode all measures str "SYN2000STABL00"
Year all measures int 2000
Author all measures list[str] ["Stable Vocabulary, V."]
author_uids author selection, strongly recommended list[str] ["uid:stable_vocab_distinct"]
References Citation Identity list[str] ["SYNREF-COR-00", ...]
tokens Own Vocabulary list[str] ["gravity", "relativity", "spacetime", ...]
embedding_2d_x, embedding_2d_y EDE float 0.0738, 0.0656

references.parquet, one row per cited work:

Column Needed for Type Example
Bibcode Citation Identity, Referenced Vocabulary str "SYNREF-COM-00"
Author Citation Identity list[str] ["Reference COM 00"]
tokens Referenced Vocabulary list[str] ["gravity", "gravity", "gravity", ...]

Repeated tokens are meaningful, term frequency is encoded by repetition. Produce tokens, the embedding coordinates and author_uids with your own upstream pipeline. The pipeline behind the papers is public in ads-bib and ads-and. Clean raw exports with duplicates or unresolved references once with toc prepare. Accepted column aliases and the full contract are in docs/data_contract.md.

Usage

Python API

The quick start used run_metrics, the entry point for author cohorts. For one measure of one author in full per-slice detail, use run_metric:

from trajectories_of_change import run_metric
from trajectories_of_change.plotting import plot_metric

# bundle as loaded in the quick start
result = run_metric(bundle, metric="citation_identity", target_author_uid="uid:stable_vocab_distinct")
plot_metric(result, export_dir="outputs/identity", format="html", show=False)

All functions, defaults, output columns and advanced options are documented in docs/api.md.

Command line

The CLI wraps the same functions with the same defaults and produces the same numbers.

uv run toc metrics prepared/publications.parquet prepared/references.parquet \
  --top-n 20 \
  --run-dir runs/top20

uv run toc plot multimetric --run-dir runs/top20

The --run-dir mode keeps results, plots, logs, the run configuration and a short report together in one folder. All commands and flags are documented in docs/cli.md.

Documentation

Citing

Cite trajectories-of-change as software via CITATION.cff, which GitHub renders through the "Cite this repository" button. Cite the framework paper if you discuss the approach or the measures:

Raphael Schlattmann and Malte Vogl (2024). Trajectories of Change: Approaches for Tracking Knowledge Evolution. BHDC 2023: Big Historical Data Conference, Jena. https://doi.org/10.48550/arXiv.2501.00391

The complete pipeline implemented here is specified in the follow-up study, whose supplementary material serves as the formal specification of this package:

Raphael Schlattmann and Malte Vogl. Tracing individual knowledge trajectories within a changing scientific field: language, citation, and semantic measures in general relativity and gravitation. In preparation.

Resources:

MIT licensed.

Metadata

Release files for trajectories-of-change 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trajectories-of-change 0.2.0
File Size Uploaded
trajectories_of_change-0.2.0.tar.gz 133.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trajectories-of-change 0.2.0
File Interpreter ABI Platform
trajectories_of_change-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 232.1 kB

Release files / trajectories_of_change-0.2.0.tar.gz

Download URL trajectories_of_change-0.2.0.tar.gz
Size 133.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5a7f074bcc95123709dd42190daca3ee8d9c17dc15c173d831c148fb3bafe960
BLAKE2b-256 checksum
How to use checksums
c668b064ae6679a5f6de0dcce7e30c215ce40161d35ac5cdabff5f50195554c6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / trajectories_of_change-0.2.0-py3-none-any.whl

Download URL trajectories_of_change-0.2.0-py3-none-any.whl
Size 98.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
146d1541469268d2119c5f15e640ec5f34f25ce98b25bcd09c96afd1fd271f7c
BLAKE2b-256 checksum
How to use checksums
22bb70d351f2059eb8fc98923af9430f78d56bf64f5b8e931f8a6bd1454503f7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page