beatrina 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +92 -0
- package/NOTICES +72 -0
- package/README.md +124 -0
- package/bin/beatrina.mjs +223 -0
- package/bin/cli.mjs +80 -0
- package/bin/failsafe.mjs +74 -0
- package/bin/identity.mjs +45 -0
- package/bin/prova-post.mjs +51 -0
- package/bin/sessions.mjs +95 -0
- package/bin/shortcut.mjs +151 -0
- package/bin/update-check.mjs +55 -0
- package/bin/upgrade.mjs +76 -0
- package/build-info.json +1 -0
- package/carmar_V0.8.6.html +1310 -0
- package/check/acceptance.mjs +278 -0
- package/check/session.mjs +215 -0
- package/engines/js/document-exec.mjs +82 -0
- package/engines/js/persist.mjs +214 -0
- package/engines/js/worker.mjs +424 -0
- package/engines/python/adapter.py +577 -0
- package/engines/python/analyze.py +814 -0
- package/engines/python/bootstrap.py +309 -0
- package/engines/python/dataview.py +735 -0
- package/engines/python/debugger.py +346 -0
- package/engines/python/document_exec.py +158 -0
- package/engines/python/engine.json +28 -0
- package/engines/python/handoff.py +118 -0
- package/engines/python/worker.py +564 -0
- package/engines/r/engine.json +25 -0
- package/engines/r/handoff.R +92 -0
- package/failsafe/ai-policy.R +255 -0
- package/failsafe/ai-store.R +373 -0
- package/failsafe/cite.R +418 -0
- package/failsafe/journal.R +684 -0
- package/failsafe/plugins.R +809 -0
- package/failsafe/serve.R +5500 -0
- package/host/ai-policy.mjs +218 -0
- package/host/deployment.mjs +160 -0
- package/host/engine-js.mjs +98 -0
- package/host/engine-pool.mjs +383 -0
- package/host/engine-python.mjs +228 -0
- package/host/engine-r.mjs +206 -0
- package/host/engine-stdio.mjs +401 -0
- package/host/journal-store.mjs +749 -0
- package/host/main.mjs +503 -0
- package/host/planes/README.md +41 -0
- package/host/planes/ai-store.mjs +327 -0
- package/host/planes/ai.mjs +467 -0
- package/host/planes/analyze.mjs +397 -0
- package/host/planes/cite.mjs +517 -0
- package/host/planes/files.mjs +0 -0
- package/host/planes/jobs.mjs +704 -0
- package/host/planes/journal.mjs +53 -0
- package/host/planes/latex.mjs +201 -0
- package/host/planes/mcp.mjs +493 -0
- package/host/planes/pair.mjs +325 -0
- package/host/planes/pipe-term.mjs +122 -0
- package/host/planes/plugins.mjs +112 -0
- package/host/planes/proc-tree.mjs +76 -0
- package/host/planes/sessions.mjs +434 -0
- package/host/planes/settings.mjs +164 -0
- package/host/planes/terminal.mjs +286 -0
- package/host/planes/test-file.mjs +80 -0
- package/host/planes/update.mjs +214 -0
- package/host/plugin-store.mjs +838 -0
- package/host/server.mjs +441 -0
- package/host/settings.mjs +379 -0
- package/host/update-record.mjs +59 -0
- package/host/user-dirs.mjs +117 -0
- package/host/windows-runtime.mjs +145 -0
- package/host/worker-plane.mjs +713 -0
- package/host/ws.mjs +190 -0
- package/kernel/analyze.R +668 -0
- package/kernel/deployment.R +165 -0
- package/kernel/examples/NOTICE.md +38 -0
- package/kernel/examples/tna-complete-tutorial.Rmd +210 -0
- package/kernel/fileio.R +656 -0
- package/kernel/index.html +96 -0
- package/kernel/job-run.R +391 -0
- package/kernel/jobs.R +276 -0
- package/kernel/kernel-protocol +1 -0
- package/kernel/kernel-version +1 -0
- package/kernel/kernel.R +671 -0
- package/kernel/knitr-run.R +245 -0
- package/kernel/latex.R +609 -0
- package/kernel/mcp/carmar-mcp.mjs +516 -0
- package/kernel/notebook-page.R +67 -0
- package/kernel/plugins/csl/apa/apa.csl +2273 -0
- package/kernel/plugins/csl/apa/plugin.json +19 -0
- package/kernel/plugins/csl/chicago-author-date/chicago-author-date.csl +4216 -0
- package/kernel/plugins/csl/chicago-author-date/plugin.json +19 -0
- package/kernel/plugins/csl/harvard-cite-them-right/harvard-cite-them-right.csl +316 -0
- package/kernel/plugins/csl/harvard-cite-them-right/plugin.json +19 -0
- package/kernel/plugins/csl/ieee/ieee.csl +519 -0
- package/kernel/plugins/csl/ieee/plugin.json +19 -0
- package/kernel/plugins/csl/modern-language-association/modern-language-association.csl +1184 -0
- package/kernel/plugins/csl/modern-language-association/plugin.json +19 -0
- package/kernel/plugins/csl/nature/nature.csl +189 -0
- package/kernel/plugins/csl/nature/plugin.json +19 -0
- package/kernel/plugins/latex/apa7/apa7.json +14 -0
- package/kernel/plugins/latex/apa7/plugin.json +19 -0
- package/kernel/plugins/latex/elsarticle/elsarticle.json +14 -0
- package/kernel/plugins/latex/elsarticle/plugin.json +19 -0
- package/kernel/plugins/latex/ieeetran/ieeetran.json +10 -0
- package/kernel/plugins/latex/ieeetran/plugin.json +19 -0
- package/kernel/project.R +131 -0
- package/kernel/settings.R +410 -0
- package/kernel/sniff.R +769 -0
- package/kernel/worker-boot.R +22 -0
- package/kernel/worker.R +3496 -0
- package/lib/agent-authoring-contract.js +547 -0
- package/lib/cell-kinds.js +108 -0
- package/lib/engine-labels.js +324 -0
- package/package.json +32 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# deployment.R — where this kernel listens, and who is allowed to reach it.
|
|
2
|
+
#
|
|
3
|
+
# CarmaR was written for exactly one deployment: a loopback socket serving one
|
|
4
|
+
# person on their own machine. Every trust rule in serve.R is an expression of
|
|
5
|
+
# that, and one of them INVERTS the moment the socket leaves loopback:
|
|
6
|
+
#
|
|
7
|
+
# a request with NO Origin header is currently allowed outright.
|
|
8
|
+
#
|
|
9
|
+
# On 127.0.0.1 that is correct and deliberate — no Origin means "not a
|
|
10
|
+
# browser", i.e. the launcher, R, curl, the MCP bridge, all of which are the
|
|
11
|
+
# same OS user, all of which could have run `Rscript` themselves. The socket
|
|
12
|
+
# grants them nothing they did not already have.
|
|
13
|
+
#
|
|
14
|
+
# On 0.0.0.0 the identical rule reads: `curl` from anywhere on the network may
|
|
15
|
+
# execute R as this user, without so much as a consent click. Same code, same
|
|
16
|
+
# header, opposite meaning — because the premise that "no Origin" implies
|
|
17
|
+
# "same user" was a fact about loopback, not a fact about HTTP.
|
|
18
|
+
#
|
|
19
|
+
# So this module computes the posture ONCE, at startup, and hands serve.R a
|
|
20
|
+
# decided answer rather than an environment variable to re-interpret at each
|
|
21
|
+
# call site. Everything here is pure: `env` is injected so the whole policy is
|
|
22
|
+
# testable without a server (test/deployment.test.mjs drives it through R).
|
|
23
|
+
#
|
|
24
|
+
# The refusals are the point. Binding off loopback is a deployment decision
|
|
25
|
+
# with consequences the operator must state out loud:
|
|
26
|
+
#
|
|
27
|
+
# · no CARMAR_HOSTS → refuse. An unset Host allow-list off
|
|
28
|
+
# loopback is a DNS-rebinding hole with the
|
|
29
|
+
# door held open.
|
|
30
|
+
# · no authentication in front → refuse, unless CARMAR_ALLOW_UNAUTHENTICATED
|
|
31
|
+
# is set. The variable is deliberately long
|
|
32
|
+
# and unpleasant to type; it is a decision,
|
|
33
|
+
# not a default.
|
|
34
|
+
#
|
|
35
|
+
# The intended P0 shape is one CarmaR per person, each as their own OS user on
|
|
36
|
+
# its own port, with TLS and login in a reverse proxy (Caddy + OIDC
|
|
37
|
+
# forward-auth). serve.R never sees a password; it trusts an identity header,
|
|
38
|
+
# and only from the proxy address. See docs/server.md.
|
|
39
|
+
|
|
40
|
+
`%||%` <- if (exists("%||%")) `%||%` else function(a, b) if (is.null(a)) b else a
|
|
41
|
+
|
|
42
|
+
LOOPBACK_HOSTS <- c("127.0.0.1", "::1", "[::1]", "localhost")
|
|
43
|
+
|
|
44
|
+
#' Split a comma/space-separated environment value into trimmed, non-empty parts.
|
|
45
|
+
split_list <- function(value) {
|
|
46
|
+
parts <- trimws(unlist(strsplit(value %||% "", "[,[:space:]]+")))
|
|
47
|
+
parts[nzchar(parts)]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#' Is this bind address one of the loopback literals?
|
|
51
|
+
#'
|
|
52
|
+
#' Deliberately a literal comparison and not a resolve: a NAME that currently
|
|
53
|
+
#' resolves to 127.0.0.1 is not the same promise as an address that cannot
|
|
54
|
+
#' leave the machine, and the whole point of the flag is that it cannot be
|
|
55
|
+
#' talked into being true.
|
|
56
|
+
is_loopback_bind <- function(bind) tolower(bind %||% "") %in% LOOPBACK_HOSTS
|
|
57
|
+
|
|
58
|
+
#' Compute the deployment posture from the environment.
|
|
59
|
+
#'
|
|
60
|
+
#' @param port the port the server will listen on.
|
|
61
|
+
#' @param env a getter with `Sys.getenv`'s signature; injected for tests.
|
|
62
|
+
#' @return a list with `bind`, `loopback`, `origins` (exact strings that may
|
|
63
|
+
#' open a socket with no consent click), `hosts` (accepted Host headers),
|
|
64
|
+
#' `allow_native` (may an Origin-less client connect?), `trust_proxy`,
|
|
65
|
+
#' `user_header`, `proxy_addrs`, and `errors` — a character vector that is
|
|
66
|
+
#' EMPTY when the posture is safe to serve. A non-empty `errors` must abort
|
|
67
|
+
#' startup; it is never a warning.
|
|
68
|
+
carmar_deployment <- function(port, env = Sys.getenv) {
|
|
69
|
+
bind <- trimws(env("CARMAR_BIND", "127.0.0.1"))
|
|
70
|
+
if (!nzchar(bind)) bind <- "127.0.0.1"
|
|
71
|
+
loopback <- is_loopback_bind(bind)
|
|
72
|
+
|
|
73
|
+
# The origin this kernel serves its own page from is always allowed: that is
|
|
74
|
+
# the same-origin case, and it is what `origin_ok` meant before this file
|
|
75
|
+
# existed. Off loopback the server is behind a proxy, so its own page
|
|
76
|
+
# arrives with the PROXY's origin — which the operator must name.
|
|
77
|
+
self_origins <- c(sprintf("http://%s:%d", bind, port),
|
|
78
|
+
sprintf("http://127.0.0.1:%d", port),
|
|
79
|
+
sprintf("http://localhost:%d", port))
|
|
80
|
+
origins <- unique(c(self_origins, split_list(env("CARMAR_ORIGINS", ""))))
|
|
81
|
+
|
|
82
|
+
hosts_env <- split_list(env("CARMAR_HOSTS", ""))
|
|
83
|
+
default_hosts <- c(sprintf("127.0.0.1:%d", port), sprintf("localhost:%d", port),
|
|
84
|
+
sprintf("[::1]:%d", port))
|
|
85
|
+
# A configured host may or may not carry a port. Accept both spellings so an
|
|
86
|
+
# operator writing `stats.example.edu` is not silently refused behind a proxy
|
|
87
|
+
# that forwards the default 80/443 and therefore sends no port at all.
|
|
88
|
+
hosts_env <- unique(c(hosts_env, ifelse(grepl(":", hosts_env, fixed = TRUE),
|
|
89
|
+
hosts_env,
|
|
90
|
+
sprintf("%s:%d", hosts_env, port))))
|
|
91
|
+
hosts <- tolower(unique(c(default_hosts, hosts_env)))
|
|
92
|
+
|
|
93
|
+
# "Anyone who reaches this port is this same OS user" is the premise behind
|
|
94
|
+
# allowing an Origin-less client, and binding off loopback is the obvious way
|
|
95
|
+
# to break it — but not the only one. A shared multi-user host, or a container
|
|
96
|
+
# whose 127.0.0.1 is port-forwarded out, breaks it while still binding
|
|
97
|
+
# loopback. So the posture is declarable in its own right and the bind
|
|
98
|
+
# address merely IMPLIES it; an operator hardening a shared machine does not
|
|
99
|
+
# have to move the socket to say so.
|
|
100
|
+
require_origin <- identical(env("CARMAR_REQUIRE_ORIGIN", ""), "1") || !loopback
|
|
101
|
+
|
|
102
|
+
trust_proxy <- identical(env("CARMAR_TRUST_PROXY", ""), "1")
|
|
103
|
+
user_header <- trimws(env("CARMAR_USER_HEADER", "X-Forwarded-User"))
|
|
104
|
+
proxy_addrs <- split_list(env("CARMAR_TRUSTED_PROXY", "127.0.0.1 ::1"))
|
|
105
|
+
allow_open <- identical(env("CARMAR_ALLOW_UNAUTHENTICATED", ""), "1")
|
|
106
|
+
|
|
107
|
+
errors <- character(0)
|
|
108
|
+
if (!loopback) {
|
|
109
|
+
if (!length(hosts_env)) {
|
|
110
|
+
errors <- c(errors, paste0(
|
|
111
|
+
"CARMAR_BIND is ", bind, " but CARMAR_HOSTS is unset. Off loopback the ",
|
|
112
|
+
"Host allow-list is the only defence against DNS rebinding, so it must ",
|
|
113
|
+
"name the hostname readers will use (e.g. CARMAR_HOSTS=stats.example.edu)."))
|
|
114
|
+
}
|
|
115
|
+
if (!trust_proxy && !allow_open) {
|
|
116
|
+
errors <- c(errors, paste0(
|
|
117
|
+
"CARMAR_BIND is ", bind, " with no authentication in front of it. Put ",
|
|
118
|
+
"CarmaR behind a reverse proxy that authenticates and set ",
|
|
119
|
+
"CARMAR_TRUST_PROXY=1, or set CARMAR_ALLOW_UNAUTHENTICATED=1 to serve R ",
|
|
120
|
+
"execution to everyone who can reach this port. See docs/server.md."))
|
|
121
|
+
}
|
|
122
|
+
if (trust_proxy && !nzchar(user_header)) {
|
|
123
|
+
errors <- c(errors, "CARMAR_TRUST_PROXY=1 requires a non-empty CARMAR_USER_HEADER.")
|
|
124
|
+
}
|
|
125
|
+
if (trust_proxy && !length(proxy_addrs)) {
|
|
126
|
+
errors <- c(errors, "CARMAR_TRUST_PROXY=1 requires CARMAR_TRUSTED_PROXY to name the proxy's address.")
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
list(
|
|
131
|
+
bind = bind,
|
|
132
|
+
port = port,
|
|
133
|
+
loopback = loopback,
|
|
134
|
+
origins = origins,
|
|
135
|
+
hosts = hosts,
|
|
136
|
+
# THE INVERSION. On a private loopback an absent Origin is a same-user
|
|
137
|
+
# native client and is allowed; anywhere the port is reachable by someone
|
|
138
|
+
# else it is an unauthenticated stranger and is not.
|
|
139
|
+
allow_native = !require_origin,
|
|
140
|
+
require_origin = require_origin,
|
|
141
|
+
trust_proxy = trust_proxy && require_origin,
|
|
142
|
+
user_header = user_header,
|
|
143
|
+
# httpuv's Rook environment spells a header `HTTP_` + uppercase, `-`→`_`.
|
|
144
|
+
user_header_key = paste0("HTTP_", toupper(gsub("-", "_", user_header, fixed = TRUE))),
|
|
145
|
+
proxy_addrs = proxy_addrs,
|
|
146
|
+
allow_unauthenticated = allow_open,
|
|
147
|
+
errors = errors)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#' Who is this request, according to the proxy in front of us?
|
|
151
|
+
#'
|
|
152
|
+
#' Returns "" unless the posture trusts a proxy AND the request actually came
|
|
153
|
+
#' from one of the named proxy addresses. That second half is what stops the
|
|
154
|
+
#' header being a self-service login: anyone who can reach the port directly
|
|
155
|
+
#' can set `X-Forwarded-User: root`, so the header is only ever as trustworthy
|
|
156
|
+
#' as the guarantee that nobody but the proxy can reach the port.
|
|
157
|
+
proxy_user <- function(req, deployment) {
|
|
158
|
+
if (!isTRUE(deployment$trust_proxy)) return("")
|
|
159
|
+
peer <- tolower(req$REMOTE_ADDR %||% "")
|
|
160
|
+
if (!nzchar(peer) || !(peer %in% tolower(deployment$proxy_addrs))) return("")
|
|
161
|
+
name <- req[[deployment$user_header_key]] %||% ""
|
|
162
|
+
# One line, printable, bounded — it reaches the audit log and the page title.
|
|
163
|
+
name <- gsub("[[:cntrl:]]", "", name)
|
|
164
|
+
trimws(substr(name, 1L, 128L))
|
|
165
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Test files shipped with CarmaR
|
|
2
|
+
|
|
3
|
+
## tna-complete-tutorial.Rmd
|
|
4
|
+
|
|
5
|
+
"A showcase of the main tna functions" — the `complete_tutorial.Rmd` vignette of
|
|
6
|
+
the **tna** R package, copied unmodified.
|
|
7
|
+
|
|
8
|
+
- Source: https://github.com/sonsoleslp/tna/blob/main/vignettes/complete_tutorial.Rmd
|
|
9
|
+
- Revision: `5c08ec9dbed28d47f67f6c9c79e58aee152fcc9a` (2026-03-03)
|
|
10
|
+
- License: MIT (the package's DESCRIPTION: `MIT + file LICENSE`)
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
YEAR: 2025-2026
|
|
14
|
+
COPYRIGHT HOLDER: tna authors
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
MIT License
|
|
18
|
+
|
|
19
|
+
Copyright (c) 2025-2026 tna authors
|
|
20
|
+
|
|
21
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
22
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
23
|
+
the Software without restriction, including without limitation the rights to
|
|
24
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
25
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
26
|
+
subject to the following conditions:
|
|
27
|
+
|
|
28
|
+
The above copyright notice and this permission notice shall be included in all
|
|
29
|
+
copies or substantial portions of the Software.
|
|
30
|
+
|
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
32
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
33
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
34
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
35
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
36
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
37
|
+
|
|
38
|
+
To run it, R needs the packages it loads: `tna`, `tibble`, `dplyr` and `gt`.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "A showcase of the main tna functions"
|
|
3
|
+
output: rmarkdown::html_vignette
|
|
4
|
+
vignette: >
|
|
5
|
+
%\VignetteIndexEntry{A showcase of the main tna functions}
|
|
6
|
+
%\VignetteEngine{knitr::rmarkdown}
|
|
7
|
+
%\VignetteEncoding{UTF-8}
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
```{r, include = FALSE}
|
|
11
|
+
knitr::opts_chunk$set(
|
|
12
|
+
collapse = TRUE,
|
|
13
|
+
fig.width = 6,
|
|
14
|
+
fig.height = 4,
|
|
15
|
+
out.width = "100%",
|
|
16
|
+
dev = "jpeg",
|
|
17
|
+
dpi = 100,
|
|
18
|
+
comment = "#>"
|
|
19
|
+
)
|
|
20
|
+
suppressPackageStartupMessages({
|
|
21
|
+
library("tna")
|
|
22
|
+
library("tibble")
|
|
23
|
+
library("dplyr")
|
|
24
|
+
library("gt")
|
|
25
|
+
})
|
|
26
|
+
options(scipen = 99)
|
|
27
|
+
options(digits = 2)
|
|
28
|
+
options(max.print = 30)
|
|
29
|
+
options(width = 83)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Tutorial of TNA with R
|
|
34
|
+
|
|
35
|
+
This is a short tutorial of the `tna` package. We begin by loading the package and the example data set `group_regulation`.
|
|
36
|
+
|
|
37
|
+
```{r}
|
|
38
|
+
library("tna")
|
|
39
|
+
data("group_regulation", package = "tna")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Building `tna` Model
|
|
43
|
+
|
|
44
|
+
TNA models can be built with the `tna` function, which accepts several types of data such a sequence data, data frames or matrices.
|
|
45
|
+
```{r, message = FALSE, results = FALSE}
|
|
46
|
+
model <- tna(group_regulation)
|
|
47
|
+
print(model)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Plotting and interpreting `tna` models
|
|
52
|
+
|
|
53
|
+
### Interpretation of the model
|
|
54
|
+
|
|
55
|
+
```{r fig.height=6, fig.width=6, fig.align='center', layout = c(1,1)}
|
|
56
|
+
# TNA visualization
|
|
57
|
+
plot(model)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Pruning and retaining edges that "matter"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
```{r, fig.show='hold', fig.width=5, fig.height=5 }
|
|
64
|
+
layout(matrix(1:4, ncol = 2, byrow = TRUE))
|
|
65
|
+
# Pruning with different methods (using comparable parameters)
|
|
66
|
+
pruned_threshold <- prune(model, method = "threshold", threshold = 0.15)
|
|
67
|
+
pruned_lowest <- prune(model, method = "lowest", lowest = 0.15)
|
|
68
|
+
pruned_disparity <- prune(model, method = "disparity", level = 0.5)
|
|
69
|
+
|
|
70
|
+
# Plotting for comparison
|
|
71
|
+
plot(pruned_threshold)
|
|
72
|
+
plot(pruned_lowest)
|
|
73
|
+
plot(pruned_disparity)
|
|
74
|
+
plot(model)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Patterns
|
|
78
|
+
|
|
79
|
+
```{r }
|
|
80
|
+
layout(t(1:2))
|
|
81
|
+
# Identify 2-cliques (dyads) from the TNA model, excluding loops in the visualization
|
|
82
|
+
# A clique of size 2 is essentially a pair of connected nodes
|
|
83
|
+
cliques_of_two <- cliques(
|
|
84
|
+
model,
|
|
85
|
+
size = 2,
|
|
86
|
+
threshold = 0.15 # Only consider edges with weight > 0.15
|
|
87
|
+
)
|
|
88
|
+
print(cliques_of_two)
|
|
89
|
+
plot(cliques_of_two, ask = FALSE)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```{r, fig.width=6,fig.height=2}
|
|
93
|
+
layout(t(1:3))
|
|
94
|
+
# Identify 3-cliques (triads) from the TNA_Model
|
|
95
|
+
# A clique of size 3 means a fully connected triplet of nodes
|
|
96
|
+
cliques_of_three <- cliques(
|
|
97
|
+
model,
|
|
98
|
+
size = 3,
|
|
99
|
+
threshold = 0.05 # Only consider edges with weight > 0.05
|
|
100
|
+
)
|
|
101
|
+
print(cliques_of_three)
|
|
102
|
+
plot(cliques_of_three, ask = FALSE)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```{r, fig.width=5}
|
|
106
|
+
# Identify 4-cliques (quadruples) from the TNA_Model
|
|
107
|
+
# A clique of size 4 means four nodes that are all mutually connected
|
|
108
|
+
cliques_of_four <- cliques(
|
|
109
|
+
model,
|
|
110
|
+
size = 4,
|
|
111
|
+
threshold = 0.035 # Only consider edges with weight > 0.03
|
|
112
|
+
)
|
|
113
|
+
print(cliques_of_four)
|
|
114
|
+
plot(cliques_of_four, ask = FALSE)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Centralities
|
|
119
|
+
|
|
120
|
+
#### Node-level measures
|
|
121
|
+
|
|
122
|
+
```{r fig.height=8, fig.width=8, fig.align='center'}
|
|
123
|
+
# Compute centrality measures for the TNA model
|
|
124
|
+
Centralities <- centralities(model)
|
|
125
|
+
|
|
126
|
+
# Visualize the centrality measures
|
|
127
|
+
plot(Centralities)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
```{r}
|
|
132
|
+
# Calculate hub scores and the authority scores for the network
|
|
133
|
+
hits_scores <- igraph::hits_scores(as.igraph(model))
|
|
134
|
+
hub_scores <- hits_scores$hub
|
|
135
|
+
authority_scores <- hits_scores$authority
|
|
136
|
+
|
|
137
|
+
# Print the calculated hub and authority scores for further analysis
|
|
138
|
+
print(hub_scores)
|
|
139
|
+
print(authority_scores)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
#### Edge-level measures
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
```{r, fig.align='center', fig.width=6, fig.height=5.5, out.width="60%"}
|
|
147
|
+
# Edge betweenness
|
|
148
|
+
Edge_betweeness <- betweenness_network(model)
|
|
149
|
+
plot(Edge_betweeness)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Community finding
|
|
153
|
+
|
|
154
|
+
```{r}
|
|
155
|
+
communities <- communities(model)
|
|
156
|
+
print(communities)
|
|
157
|
+
plot(communities, method = "leading_eigen")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Network inference
|
|
161
|
+
|
|
162
|
+
### Bootstrapping
|
|
163
|
+
|
|
164
|
+
```{r}
|
|
165
|
+
# Perform bootstrapping on the TNA model with a fixed seed for reproducibility
|
|
166
|
+
set.seed(265)
|
|
167
|
+
boot <- bootstrap(model, threshold = 0.05)
|
|
168
|
+
|
|
169
|
+
# Print a summary of the bootstrap results
|
|
170
|
+
print(summary(boot))
|
|
171
|
+
|
|
172
|
+
# Show the non-significant edges (p-value >= 0.05 in this case)
|
|
173
|
+
# These are edges that are less likely to be stable across bootstrap samples
|
|
174
|
+
print(boot, type = "nonsig")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Permutation
|
|
178
|
+
|
|
179
|
+
```{r, fig.align='center', fig.width = 5, fig.height = 5, layout = c(1,1)}
|
|
180
|
+
# Create TNA for the high-achievers subset (rows 1 to 1000)
|
|
181
|
+
Hi <- tna(group_regulation[1:1000, ])
|
|
182
|
+
|
|
183
|
+
# Create TNA for the low-achievers subset (rows 1001 to 2000)
|
|
184
|
+
Lo <- tna(group_regulation[1001:2000, ])
|
|
185
|
+
|
|
186
|
+
# Plot a comparison of the "Hi" and "Lo" models
|
|
187
|
+
# The 'minimum' parameter is set to 0.001, so edges with weights >= 0.001 are shown
|
|
188
|
+
plot_compare(Hi, Lo, minimum = 0.01)
|
|
189
|
+
|
|
190
|
+
# Run a permutation test to determine statistical significance of differences
|
|
191
|
+
# between "Hi" and "Lo"
|
|
192
|
+
# The 'iter' argument is set to 1000, meaning 1000 permutations are performed
|
|
193
|
+
Permutation <- permutation_test(Hi, Lo, iter = 1000, measures = "Betweenness")
|
|
194
|
+
|
|
195
|
+
# Plot the significant differences identified in the permutation test
|
|
196
|
+
plot(Permutation, minimum = 0.01)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```{r}
|
|
200
|
+
print(Permutation$edges$stats)
|
|
201
|
+
print(Permutation$centralities$stats)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Interpreting the Results of the Case-Dropping Bootstrap for Centrality Indices
|
|
205
|
+
|
|
206
|
+
```{r, fig.align='center', fig.width=7, fig.height=4}
|
|
207
|
+
# Results of the Case-Dropping Bootstrap for Centrality Indices
|
|
208
|
+
Centrality_stability <- estimate_centrality_stability(model, iter = 100)
|
|
209
|
+
plot(Centrality_stability)
|
|
210
|
+
```
|