From 837ba85051e273e503e285a3a8698d8638ef9e44 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 7 Feb 2026 15:14:53 -0500 Subject: [PATCH 1/4] Removed unused imports and improved docstrings --- src/temporalmapper/temporal_mapper.py | 57 +++++++++++---------------- src/temporalmapper/utilities.py | 50 ----------------------- 2 files changed, 22 insertions(+), 85 deletions(-) diff --git a/src/temporalmapper/temporal_mapper.py b/src/temporalmapper/temporal_mapper.py index 3cfc2a8..90a7b60 100755 --- a/src/temporalmapper/temporal_mapper.py +++ b/src/temporalmapper/temporal_mapper.py @@ -1,41 +1,49 @@ -import matplotlib.pyplot as plt import networkx as nx import numpy as np -from temporalmapper.utilities import * -from temporalmapper.weighted_clustering import * -from tqdm import tqdm, trange -from sklearn.metrics import pairwise_distances +from tqdm import trange from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA -from scipy.sparse import issparse from sklearn.neighbors import NearestNeighbors -from sklearn.base import ClusterMixin +from scipy.sparse import issparse from datamapplot.palette_handling import palette_from_datamap import matplotlib as mpl from copy import deepcopy import plotly.graph_objects as go +from temporalmapper.utilities import ( + std_sigmoid, + time_semantic_plot, + compute_time_semantic_positions, + prepare_plotly_graph_objects, +) +from temporalmapper.weighted_clustering import ( + square, + cosine_window, + weighted_clusters, +) + """TemporalMapper class minimal usage example: # load from your data file: data : (n_dim, N_data) array-like time : (N_data,) array-like - semantic_dist : (N_data,) array-like # choose an sklearn clusterer: clusterer = HDBSCAN() # init and build the graph: - TG = TemporalGraph( + mapper = TemporalGraph( time, data, clusterer, N_checkpoints = 10, ) - TG.build() - myGraph = TG.G + mapper.build() + myGraph = mapper.G + # generate a matplotlib figure + mapper.temporal_plot() """ @@ -54,6 +62,9 @@ class TemporalMapper: Run the density-based mapper algorithm to construct the temporal graph. get_vertex_data(str node): Returns the index of elements of ``data`` which are in vertex ``node``. + get_dir_subvertices(str node, float threshold = 0.0, bool backwards=False): + Returns the vertices that descend from ``node`` with outedge weight at least ``threshold``. + If ``backwards = True``, returns the ancestors instead of descendants. temporal_plot(): Returns a matplotlib axis containing a temporal plot interactive_temporal_plot(): @@ -185,30 +196,6 @@ def _compute_checkpoints(self): self._compute_critical_points() return checkpoints - def _compute_critical_points(self): - if self.distance is None: - self._compute_knn() - if verbose: - print("Computing morse critical points...") - - std_time = np.copy(self.time) - std_time = self.scaler.fit_transform(std_time.reshape(-1, 1)) - temporal_delta = [ - np.mean(std_time[indx] - std_time[indx[0]]) for indx in TG.dist_indices - ] - temporal_delta = np.squeeze(np.vstack(temporal_delta)) - event_strength = temporal_delta / self.distance[:, -1] - ## smooth it out a bit - smooth_strength = np.zeros(self.n_samples) - for k in trange(self.time, disable=self.disable): - smooth_strength += ( - tmwc.square(self.time[k], self.time, 1, 0.05) * event_strength[k] - ) - ## find peaks & troughs - peaks = find_peaks(smooth_vals, prominence=0.8, height=0.5)[0] - troughs = find_peaks(-smooth_vals, prominence=0.8, height=0.5)[0] - critical_points = np.hstack((peaks, troughs)) - def _compute_knn(self): """Run sklearn NearestNeighbours to compute knns.""" if self.verbose: diff --git a/src/temporalmapper/utilities.py b/src/temporalmapper/utilities.py index 151f094..f566d41 100755 --- a/src/temporalmapper/utilities.py +++ b/src/temporalmapper/utilities.py @@ -67,56 +67,6 @@ def epsilon_balls(data, epsilon): indices.append(idx) return distances, indices - -def graph_to_holoviews(G, dataset_func=None): - """Take TemporalGraph.G and output the required HoloViews objects for a modified Sankey diagram.""" - nxNodes = G.nodes() - nodes = nxNodes # lol - cnt = 0 - orphans = [] - idx = 0 - for node in nxNodes: - if G.degree(node) == 0: - cnt += 1 - orphans.append(node) - continue - G.nodes()[node]["index"] = idx - idx += 1 - - for node in orphans: - G.remove_node(node) - nxNodes = G.nodes() - if cnt != 0: - print(f"Warning: removed {cnt} orphan nodes from the graph.") - nodes_ = {"index": [], "size": [], "label": [], "colour": [], "column": []} - for i, node in enumerate(nxNodes): - nodes_["index"].append(i) - nodes_["size"].append(nodes[node]["count"]) - try: - nodes_["label"].append(nodes[node]["label"]) - except KeyError: - nodes_["label"].append(nodes[node]["index"]) - nodes_["colour"].append("#ffffff") - nodes_["column"].append(nodes[node]["slice_no"]) - - cmap = {nodes[node]["index"]: nodes[node]["colour"] for node in nodes} - try: - nodes = hv.Dataset(nodes_, "index", ["size", "label", "colour", "column"]) - except NameError: - nodes = dataset_func(nodes_, "index", ["size", "label", "colour", "column"]) - - edges = [] - - for u, v, d in G.edges(data=True): - uidx = nxNodes[u]["index"] - vidx = nxNodes[v]["index"] - u_size = nxNodes[u]["count"] - v_size = nxNodes[v]["count"] - edges.append((uidx, vidx, (u_size * d["src_weight"], v_size * d["dst_weight"]))) - - return nodes, edges, cmap - - def compute_cluster_yaxis(clusters, semantic_dist, func=cluster_avg_1D): y_data = [] for tslice in clusters: From 53ce73b48406988a5638053925533d6afd95c8db Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 7 Feb 2026 15:25:16 -0500 Subject: [PATCH 2/4] used deptry to fix pyproject.toml dependencies --- pyproject.toml | 5 +---- src/temporalmapper/utilities.py | 1 - src/temporalmapper/weighted_clustering.py | 8 +------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b5a9316..33c0671 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ readme = "README.md" license = {text = "BSD-3-Clause license"} keywords = ["Mapper", "TDA", "Morse Theory", "Temporal Topic Modeling"] dependencies = [ + "adjustText", "numpy", "matplotlib", "pandas", @@ -20,10 +21,6 @@ dependencies = [ "scikit-learn", "scipy", "networkx", - "numba", -] -[project.optional-dependencies] -visualizations = [ "datamapplot", "datashader", "vectorizers", diff --git a/src/temporalmapper/utilities.py b/src/temporalmapper/utilities.py index f566d41..ac56fe9 100755 --- a/src/temporalmapper/utilities.py +++ b/src/temporalmapper/utilities.py @@ -16,7 +16,6 @@ def std_sigmoid(x): transform = (x - mu) / (std) return 1 / (1 + np.exp(-1 * transform)) - def cluster_avg_1D(cluster_data, y_data): """Average out the y_data in each cluster, to use as y-axis positions for the graph visualization""" diff --git a/src/temporalmapper/weighted_clustering.py b/src/temporalmapper/weighted_clustering.py index 99c2267..a2c7ab5 100755 --- a/src/temporalmapper/weighted_clustering.py +++ b/src/temporalmapper/weighted_clustering.py @@ -1,11 +1,5 @@ -import sys import numpy as np -import pandas as pd -import math -import numba -from tqdm import tqdm, trange -from warnings import warn - +from tqdm import tqdm def gaussian(t0, t, density, binwidth, epsilon=0.1, params=None): """ Returns weights for samples at times t for a Gaussian kernel centered at t0 """ From 2b9aeb7a0b1c1e95e087bd4f0929fce62713ba98 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 7 Feb 2026 15:35:55 -0500 Subject: [PATCH 3/4] Improved pyproject.toml as suggested by ChatGPT --- pyproject.toml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 33c0671..ec243c3 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,13 +4,22 @@ build-backend = "setuptools.build_meta" [project] name = "temporal-mapper" +version = "1.1.0" authors = [ {name = "Kaleb D Ruscitti", email="kaleb.ruscitti@uwaterloo.ca"}, ] -version = "1.1.0" +description = "Implementation of density-based Mapper for temporal topic modelling." readme = "README.md" -license = {text = "BSD-3-Clause license"} -keywords = ["Mapper", "TDA", "Morse Theory", "Temporal Topic Modeling"] +license = {text = "BSD-3-Clause"} +keywords = ["mapper", "tda", "morse theory", "temporal topic modeling"] + +classifiers = [ + "License :: OSI Approved :: BSD License", + "Programming Language :: Python :: 3", + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", +] + dependencies = [ "adjustText", "numpy", @@ -25,3 +34,8 @@ dependencies = [ "datashader", "vectorizers", ] + +[project.urls] +Homepage = "https://github.com/TutteInstitute/temporal-mapper" +Repository = "https://github.com/TutteInstitute/temporal-mapper" +Documentation = "https://temporal-mapper.readthedocs.io" \ No newline at end of file From 4fb7db5bedc4cdc2d7405391cedf3401c4b9ad91 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 7 Feb 2026 15:38:28 -0500 Subject: [PATCH 4/4] updated __init__.py --- src/temporalmapper/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/temporalmapper/__init__.py b/src/temporalmapper/__init__.py index 54e932b..82884ad 100755 --- a/src/temporalmapper/__init__.py +++ b/src/temporalmapper/__init__.py @@ -1,5 +1,6 @@ import temporalmapper.temporal_mapper as tm_main +import temporalmapper.utilities as tm_utils TemporalMapper = tm_main.TemporalMapper -centroid_datamap = tm_main.centroid_datamap -time_semantic_plot = tm_main.time_semantic_plot +centroid_datamap = tm_utils.centroid_datamap +time_semantic_plot = tm_utils.time_semantic_plot