Analysis layer ([graph] extra)¶
The optional analysis pipeline: sentence embeddings → cosine kNN graph →
(optional disparity backbone) → PageRank and community detection. Install it with
uv add "lexograph[graph]". Everything here only produces the plain per-unit
arrays the encode channels accept; the core never imports it.
lexograph.analyze.analyze_text(text, *, embeddings=None, k=5, community='louvain', n_clusters=10, backbone=False, min_alpha_ptile=0.5, seed=42)
¶
Run the analysis pipeline and return per-sentence channel arrays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The source text. |
required |
embeddings
|
FloatArray | None
|
Precomputed |
None
|
k
|
int
|
Neighbours per node in the kNN graph. |
5
|
community
|
CommunityMethod
|
Community method — |
'louvain'
|
n_clusters
|
int
|
Number of clusters for the |
10
|
backbone
|
bool
|
If |
False
|
min_alpha_ptile
|
float
|
Disparity-filter threshold (used when |
0.5
|
seed
|
int
|
Random seed for reproducibility. |
42
|
Returns:
| Name | Type | Description |
|---|---|---|
An |
Analysis
|
class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
Drive a walk and a semantic dotplot from the analysis (not run as a doctest — embedding downloads a model)::
from lexograph import text_walk, recurrence_plot, load_demo_text
from lexograph.analyze import analyze_text
a = analyze_text(load_demo_text())
walk = text_walk(load_demo_text(), colour=a.community,
colour_kind="categorical", size=a.size)
dots = recurrence_plot(load_demo_text(), distances=a.distances,
threshold=0.4)
Source code in lexograph/analyze/__init__.py
lexograph.analyze.Analysis
dataclass
¶
The per-sentence channel arrays derived from a text.
Attributes:
| Name | Type | Description |
|---|---|---|
sentences |
list[str]
|
The segmented sentences (length |
embeddings |
FloatArray
|
The |
size |
FloatArray
|
PageRank centrality per sentence — the size channel. |
community |
ndarray
|
Community id per sentence — the colour channel. |
distances |
FloatArray
|
The |
Source code in lexograph/analyze/__init__.py
lexograph.analyze.embeddings.embed_sentences(sentences, *, model_name=DEFAULT_MODEL, batch_size=64)
¶
Embed sentences into L2-normalised vectors.
The model is downloaded on first use and cached by sentence-transformers.
Because the embeddings are L2-normalised, a dot product equals cosine
similarity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sentences
|
Sequence[str]
|
The sentences to embed. |
required |
model_name
|
str
|
A sentence-transformers model id. |
DEFAULT_MODEL
|
batch_size
|
int
|
Encoding batch size. |
64
|
Returns:
| Type | Description |
|---|---|
FloatArray
|
An |
Example
Not run as a doctest (it would download the model)::
from lexograph import segment, load_demo_text
from lexograph.analyze.embeddings import embed_sentences
sentences = segment(load_demo_text())
embeddings = embed_sentences(sentences)
Source code in lexograph/analyze/embeddings.py
lexograph.analyze.graph.knn_graph(embeddings, *, k=5)
¶
Build a weighted cosine k-nearest-neighbour graph over the embeddings.
Node i is sentence i; an edge carries the cosine similarity
(1 - cosine distance) as its weight. The graph is undirected: the
mutual edge keeps the stronger of the two directed similarities.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embeddings
|
FloatArray
|
An |
required |
k
|
int
|
Neighbours per node (capped at |
5
|
Returns:
| Type | Description |
|---|---|
Graph
|
A networkx graph with nodes |
Examples:
Source code in lexograph/analyze/graph.py
lexograph.analyze.graph.embedding_distances(embeddings)
¶
Return the pairwise cosine distance matrix of the embeddings.
Ready to pass as distances to
:func:lexograph.presets.recurrence.recurrence_plot for a semantic
recurrence dotplot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embeddings
|
FloatArray
|
An |
required |
Returns:
| Type | Description |
|---|---|
FloatArray
|
An |
Examples:
Source code in lexograph/analyze/graph.py
lexograph.analyze.graph.pagerank_scores(graph, n)
¶
Return weighted PageRank as a per-sentence array (the size channel).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Graph
|
A weighted sentence graph (e.g. from :func: |
required |
n
|
int
|
The total sentence count, so the result aligns to every sentence even if the graph has dropped some nodes. |
required |
Returns:
| Type | Description |
|---|---|
FloatArray
|
A length- |
FloatArray
|
|
Examples:
>>> import networkx as nx
>>> g = nx.path_graph(3)
>>> for u, v in g.edges():
... g[u][v]["weight"] = 1.0
>>> pagerank_scores(g, 3).shape
(3,)
Source code in lexograph/analyze/graph.py
lexograph.analyze.graph.community_labels(graph, n, *, method='louvain', embeddings=None, n_clusters=10, seed=42)
¶
Return a per-sentence community label (the colour channel).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Graph
|
A weighted sentence graph (used by the Louvain method). |
required |
n
|
int
|
The total sentence count, so labels align to every sentence. |
required |
method
|
CommunityMethod
|
|
'louvain'
|
embeddings
|
FloatArray | None
|
Required for |
None
|
n_clusters
|
int
|
Number of clusters for |
10
|
seed
|
int
|
Random seed for reproducibility. |
42
|
Returns:
| Type | Description |
|---|---|
ndarray
|
A length- |
ndarray
|
the largest community; a node absent from the graph gets |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> import networkx as nx
>>> g = nx.path_graph(4)
>>> for u, v in g.edges():
... g[u][v]["weight"] = 1.0
>>> labels = community_labels(g, 4)
>>> labels.shape
(4,)
Source code in lexograph/analyze/graph.py
lexograph.analyze.backbone.extract_backbone(graph, *, min_alpha_ptile=0.5, min_degree=1)
¶
Return the disparity-filter backbone of a weighted graph.
The input is copied (never mutated): edges below min_alpha_ptile are
dropped, then nodes whose degree falls below min_degree are pruned
iteratively until stable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Graph
|
A weighted networkx graph. |
required |
min_alpha_ptile
|
float
|
Edges with an alpha percentile below this are removed. |
0.5
|
min_degree
|
int
|
Nodes left with a degree below this are pruned ( |
1
|
Returns:
| Type | Description |
|---|---|
Graph
|
A new graph containing only the backbone. |
Examples:
>>> import networkx as nx
>>> g = nx.path_graph(5)
>>> for u, v in g.edges():
... g[u][v]["weight"] = float(v + 1)
>>> bb = extract_backbone(g, min_alpha_ptile=0.3)
>>> bb.number_of_nodes() <= g.number_of_nodes()
True