dynet: Build a temporal network

View source: R/dynet.R

dynetR Documentation

Build a temporal network

Description

Builds a temporal network from a relational log. One constructor covers the four shapes relational data actually arrives in, and the shape is inferred from the arguments you name:

interval

Each row is an edge active over ⁠[start, end)⁠. Used when the data carry an end time or a duration.

contact

Each row is an instantaneous event with a time and no duration – a message, a click, a citation.

threaded

Forum, chat or email data. An edge is treated as active from its own post until the last post in the same thread, following Saqr and Nouri (2020). Name the thread argument to select this.

copresence

Two-mode attendance data. Actors sharing a group become connected for the span of that group. Name actor and group.

Every other column of data is kept as a tie attribute: it appears in as.data.frame() and can be selected on with induce_subgraph(ties = ). The exceptions are the canonical spell fields themselves – duration, weight, session, thread, onset_censored and terminus_censored – which are dropped even when they were never named as arguments, because the spell table owns those names. A non-atomic column raises dynet_bad_tie_attribute, and a factor is carried as character. Co-presence logs keep none, because their rows are memberships rather than ties.

Column names are resolved case-insensitively from a table of aliases, so Sender/Receiver, source/target and onset/terminus are all understood without being spelled out. Times may be numeric, Date, POSIXct or character date-time strings; character and date-time input is converted to elapsed time since the first event in a readable unit.

Vertices are addressed by name everywhere in this package. Integer vertex indices are used internally for speed but are never part of any result.

Explicit observation bounds are administrative measurement limits, not a destructive filter. A positive spell ⁠[s,e)⁠ contributes the half-open intersection ⁠[max(s,L),min(e,U))⁠ when it has positive duration, while a genuine instantaneous event is retained at either L or U. Original endpoints remain the only formation and dissolution events, censoring is never inferred from equality with a limit, and temporal paths must both start and finish inside the declared interval.

Vertex activity is a separate declaration. A vertex with at least one row in vertex_spells is eligible only on the union of those half-open positive spells and exact points; a vertex with no row remains eligible at all times. Snapshot measurements independently union eligible vertices and active edges over each positive window and then induce on eligible endpoints; point snapshots evaluate both at the exact time. Explicit vertex censor flags describe raw outer-boundary state and are never inferred from observation limits or used to alter eligibility.

Usage

dynet(
  data,
  from = NULL,
  to = NULL,
  start = NULL,
  end = NULL,
  duration = NULL,
  time = NULL,
  thread = NULL,
  actor = NULL,
  group = NULL,
  session = NULL,
  weight = NULL,
  nodes = NULL,
  groups = NULL,
  format = c("auto", "interval", "contact", "threaded", "copresence"),
  thread_clock = c("absolute", "relative"),
  directed = TRUE,
  interval = 1,
  time_unit = "auto",
  observation_start = NULL,
  observation_end = NULL,
  observation_spells = NULL,
  loops = FALSE,
  min_thread_posts = 1L,
  onset_censored = NULL,
  terminus_censored = NULL,
  vertex_spells = NULL
)

Arguments

data

Data frame holding one relational event per row.

from, to

Column names for the source and target vertex. Auto-detected from from/to, source/target, sender/receiver, tail/head, ego/alter.

start, end

Column names for the start and end of an edge spell. Auto-detected from start/end, onset/terminus, begin/finish.

duration

Column name for a spell duration, used in place of end.

time

Column name for an event time, used in place of start. Auto-detected from time, timestamp, date, datetime.

thread

Column name identifying a conversation thread. Naming it selects the threaded format.

actor, group

Column names for the actor and the shared group. Naming both selects the co-presence format.

session

Column name for a session or period grouping. Sessions act as walls that time-respecting paths do not cross.

weight

Column name for event multiplicity. NULL auto-detects a column named weight, weights or strength (and says so); with none, every row counts once.

nodes

Optional data frame of vertex attributes. The vertex key is auto-detected (node, vertex.id, id, name, ...), or given as the first column. When the key is not name and the table also has a name column, the vertices are named by name: edge endpoints and vertex spells given by key are translated, and the key stays on the node table as an attribute. A key with no row in nodes keeps the key as its name, with a dynet_unnamed_nodes warning.

groups

Name of a column in nodes to use as the vertex partition. Written into the places cograph looks for it, so cograph::splot() colours and groups by it without further argument. A name that is not a column of nodes raises a condition of class dynet_unknown_attribute.

format

One of "auto" (the default), "interval", "contact", "threaded", "copresence". "auto" infers the format from the arguments you name and the columns present.

thread_clock

For a threaded log, "absolute" (the default) keeps every post on the calendar; "relative" puts each thread on its own clock, measured from the thread's first post, so a tie opens at the time since its thread began and closes when the thread ends. Threads are then comparable by how they unfold rather than by when they happened, the convention of the Trees of Thought study. Requires thread.

directed

Whether edges are directed, TRUE by default. Co-presence networks are always undirected.

interval

Width of one time bin, in the network's time unit. Defaults to 1.

time_unit

Unit for converting Date/POSIXct/character times: "auto" (the default), "seconds", "minutes", "hours", "days" or "weeks". Numeric times are left alone and reported as "step".

observation_start, observation_end

Optional bounds of the continuous observation interval. Supply numeric values in the network's internal time scale, or Date/POSIXct values for a calendar network. Either bound may be omitted, in which case the corresponding raw event limit is used. Positive spells are measured on their half-open intersection with this interval; instantaneous events are retained at either boundary. Raw spell endpoints returned by as.data.frame() are never changed.

observation_spells

Optional data frame with exactly two columns, start and end, defining discontinuous observed support. Overlapping and adjacent positive intervals are merged; isolated points are retained. This is mutually exclusive with observation_start and observation_end; supplying both raises a condition of class dynet_conflicting_observation.

loops

Whether to keep self-loops. FALSE, the default, drops them with a message, which is almost always what relational logs need; TRUE keeps them and reports how many. A kept loop is counted by degree, and contributes two to it, since both of its endpoint stubs are incident to the same vertex. In a threaded log a dropped self-reply is dropped before the thread's lifetime is computed, so it neither opens a tie nor keeps its thread alive.

min_thread_posts

For a threaded log, the smallest number of posts a thread must hold, after self-loops have been dropped, for its posts to enter the network. The default 1 keeps every thread; 2 drops threads that never became an exchange, the rule of Saqr (2024). Dropped threads are reported with a message. Requires thread.

onset_censored, terminus_censored

Optional logical column names for explicit raw interval-boundary censor state. These selectors are available only for interval input, are never auto-detected, and may not flag a zero-duration point.

vertex_spells

Optional tidy vertex-activity table: one row per period in which a vertex is present, with a node column (node, vertex.id, name, ...) and a start and end column (start/end, onset/terminus, ...), resolved through the same alias table as data, plus optional exact columns session, onset_censored, and terminus_censored. Any other column is ignored, so a node table that carries entry and exit times can be passed as it is. Positive spells use ⁠[start,end)⁠ and points are exact. Overlapping and adjacent positive spells are unioned independently by node and session. A vertex absent from this table remains active at all times.

Value

An object of class c("dynet", "netobject", "cograph_network"). It is a cograph network, so cograph::splot() draws it directly and every cograph rendering argument applies. Use as.data.frame() for the tidy spell table, as.data.frame(x, what = "nodes") for the vertex table, as.data.frame(x, what = "network") for the aggregate edge list, summary() for the description and plot() for a picture. Nothing in this package requires you to reach into the object.

References

Saqr, M., & Nouri, J. (2020). High resolution temporal network analysis to understand and improve collaborative learning. Proceedings of the Tenth International Conference on Learning Analytics & Knowledge, 314-319.

Holme, P., & Saramaki, J. (2012). Temporal networks. Physics Reports, 519(3), 97-125.

Butts, C. T. (2008). network: a package for managing relational data in R. Journal of Statistical Software, 24(2), 1-36.

Examples

# An interval log: each row carries its own start and end
dynet(school_contacts)

# A threaded log: edge stays active until its thread falls silent
dynet(forum_posts, thread = "thread")

# A co-presence log: actors sharing a group become connected
dynet(seminar_attendance, actor = "student", group = "seminar")

# Declare observation time without rewriting the source spell.
bounded <- dynet(data.frame(
  from = "A", to = "B", start = -2, end = 8
), observation_start = 0, observation_end = 5)
as.data.frame(bounded)

# Declare changing vertex eligibility without altering edge spells.
scheduled <- dynet(data.frame(
  from = "A", to = "B", start = 0, end = 10
), vertex_spells = data.frame(
  node = c("A", "A"), start = c(0, 7), end = c(4, 10)
))
as.data.frame(scheduled, what = "vertex_spells")


Dynet documentation built on Oct. 7, 2026, 5:08 p.m.