tmplot 0.2.0__tar.gz → 0.3.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: tmplot
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Visualization of Topic Modeling Results
5
5
  Author-email: Maksim Terpilovskii <maximtrp@gmail.com>
6
6
  License: MIT License
@@ -55,6 +55,7 @@ Provides-Extra: models
55
55
  Requires-Dist: tomotopy>=0.8.0; extra == "models"
56
56
  Requires-Dist: gensim; extra == "models"
57
57
  Requires-Dist: bitermplus; extra == "models"
58
+ Dynamic: license-file
58
59
 
59
60
  # tmplot
60
61
 
@@ -66,35 +67,46 @@ Requires-Dist: bitermplus; extra == "models"
66
67
  [![PyPI](https://img.shields.io/pypi/v/tmplot)](https://pypi.org/project/tmplot)
67
68
  [![Issues](https://img.shields.io/github/issues/maximtrp/tmplot.svg)](https://github.com/maximtrp/tmplot/issues)
68
69
 
69
- **tmplot** is a Python package for analysis and visualization of topic modeling results. It provides the interactive report interface that borrows much from LDAvis/pyLDAvis and builds upon it offering a number of metrics for calculating topic distances and a number of algorithms for calculating scatter coordinates of topics. It can be used to select closest and stable topics across multiple models.
70
+ **tmplot** is a comprehensive Python package for **topic modeling analysis and visualization**. Built for data scientists and researchers, it provides powerful interactive reports and advanced analytics that extend beyond traditional LDAvis/pyLDAvis capabilities.
71
+
72
+ **Analyze** • **Visualize** • **Compare** multiple topic models with ease
70
73
 
71
74
  ![Plots](https://raw.githubusercontent.com/maximtrp/tmplot/main/images/topics_terms_plots.png)
72
75
 
73
- ## Features
76
+ ## Key Features
77
+
78
+ ### Interactive Visualization
79
+
80
+ - **Topic scatter plots** with customizable coordinates and sizing
81
+ - **Term probability charts** with relevance weighting
82
+ - **Document analysis** showing top documents per topic
83
+ - **Interactive reports** with real-time parameter adjustment
84
+
85
+ ### Advanced Analytics
74
86
 
75
- - Supported models:
87
+ - **Topic stability analysis** across multiple model runs
88
+ - **Model comparison** with sophisticated distance metrics
89
+ - **Saliency calculations** for term importance
90
+ - **Entropy metrics** for model optimization
76
91
 
77
- - [tomotopy](https://bab2min.github.io/tomotopy/): `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
78
- - [gensim](https://radimrehurek.com/gensim/): `LdaModel`, `LdaMulticore`
79
- - [bitermplus](https://github.com/maximtrp/bitermplus): `BTM`
92
+ ### Model Support
80
93
 
81
- - Supported distance metrics:
94
+ - **[tomotopy](https://bab2min.github.io/tomotopy/)**: `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
95
+ - **[gensim](https://radimrehurek.com/gensim/)**: `LdaModel`, `LdaMulticore`
96
+ - **[bitermplus](https://github.com/maximtrp/bitermplus)**: `BTM`
82
97
 
83
- - Kullback-Leibler (symmetric and non-symmetric) divergence
84
- - Jenson-Shannon divergence
85
- - Jeffrey's divergence
86
- - Hellinger distance
87
- - Bhattacharyya distance
88
- - Total variation distance
89
- - Jaccard inversed index
98
+ ### Distance Metrics
90
99
 
91
- - Supported [algorithms](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.manifold) for calculating topics scatter coordinates:
100
+ - Kullback-Leibler (symmetric & non-symmetric)
101
+ - Jensen-Shannon divergence
102
+ - Jeffrey's divergence
103
+ - Hellinger & Bhattacharyya distances
104
+ - Total variation distance
105
+ - Jaccard index
92
106
 
93
- - t-SNE
94
- - SpectralEmbedding
95
- - MDS
96
- - LocallyLinearEmbedding
97
- - Isomap
107
+ ### Dimensionality Reduction
108
+
109
+ t-SNE, SpectralEmbedding, MDS, LocallyLinearEmbedding, Isomap
98
110
 
99
111
  ## Donate
100
112
 
@@ -102,55 +114,77 @@ If you find this package useful, please consider donating any amount of money. T
102
114
 
103
115
  <a href="https://www.buymeacoffee.com/maximtrp" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
104
116
 
105
- ## Installation
117
+ ## Quick Start
106
118
 
107
- The package can be installed from PyPi:
119
+ ### Installation
108
120
 
109
121
  ```bash
122
+ # From PyPI (recommended)
110
123
  pip install tmplot
111
- ```
112
-
113
- Or directly from this repository:
114
124
 
115
- ```bash
125
+ # Development version
116
126
  pip install git+https://github.com/maximtrp/tmplot.git
117
127
  ```
118
128
 
119
- ## Dependencies
129
+ ### Basic Usage
130
+
131
+ ```python
132
+ import tmplot as tmp
133
+
134
+ # Load your topic model and documents
135
+ model = your_fitted_model # tomotopy, gensim, or bitermplus
136
+ docs = your_documents
120
137
 
121
- - `numpy`
122
- - `scipy`
123
- - `scikit-learn`
124
- - `pandas`
125
- - `altair`
126
- - `ipywidgets`
127
- - `tomotopy`, `gensim`, and `bitermplus` (optional)
138
+ # Create interactive report
139
+ tmp.report(model, docs=docs)
128
140
 
129
- ## Quick example
141
+ # Or create individual visualizations
142
+ coords = tmp.prepare_coords(model)
143
+ tmp.plot_scatter_topics(coords, size_col='size')
144
+ ```
145
+
146
+ ## Advanced Examples
147
+
148
+ ### Get Stable Topics
130
149
 
131
150
  ```python
132
- # Importing packages
133
151
  import tmplot as tmp
134
- import pickle as pkl
135
- import pandas as pd
136
152
 
137
- # Reading a model from a file
138
- with open('data/model.pkl', 'rb') as file:
139
- model = pkl.load(file)
153
+ # Find stable topics across multiple models
154
+ models = [model1, model2, model3, model4]
155
+ closest_topics, distances = tmp.get_closest_topics(models)
156
+ stable_topics, stable_distances = tmp.get_stable_topics(closest_topics, distances)
157
+ ```
158
+
159
+ ### Analyze Model
160
+
161
+ ```python
162
+ # Calculate entropy for model selection
163
+ entropy_score = tmp.entropy(phi_matrix)
140
164
 
141
- # Reading documents from a file
142
- docs = pd.read_csv('data/docs.txt.gz', header=None).values.ravel()
165
+ # Analyze topic stability
166
+ saliency = tmp.get_salient_terms(phi, theta)
167
+ ```
143
168
 
144
- # Plotting topics as a scatter plot
145
- topics_coords = tmp.prepare_coords(model)
146
- tmp.plot_scatter_topics(topics_coords, size_col='size', label_col='label')
169
+ ### Visualize
147
170
 
148
- # Plotting terms probabilities
149
- terms_probs = tmp.calc_terms_probs_ratio(phi, topic=0, lambda_=1)
150
- tmp.plot_terms(terms_probs)
171
+ ```python
172
+ # Create topic distance matrix with different metrics
173
+ topic_dists = tmp.get_topics_dist(phi, method='jensen-shannon')
151
174
 
152
- # Running report interface
153
- tmp.report(model, docs=docs, width=250)
175
+ # Generate coordinates with custom algorithm
176
+ coords = tmp.get_topics_scatter(topic_dists, theta, method='tsne')
177
+ tmp.plot_scatter_topics(coords, topic=3) # Highlight topic 3
154
178
  ```
155
179
 
156
- You can find more examples in the [tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html).
180
+ ## Documentation & Examples
181
+
182
+ - [Complete Tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html) - Step-by-step guide
183
+ - [API Reference](https://tmplot.readthedocs.io/) - Full documentation
184
+ - [Example Notebooks](https://github.com/maximtrp/tmplot/tree/main/examples) - Jupyter examples
185
+
186
+ ## Requirements
187
+
188
+ **Core dependencies:** `numpy`, `scipy`, `scikit-learn`, `pandas`, `altair`, `ipywidgets`
189
+
190
+ **Optional models:** `tomotopy`, `gensim`, `bitermplus`
tmplot-0.3.0/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # tmplot
2
+
3
+ [![Codacy coverage](https://img.shields.io/codacy/coverage/5939b1cf99bc4f9d91de11c0d3ff9e50)](https://app.codacy.com/gh/maximtrp/tmplot/coverage)
4
+ [![Codacy grade](https://img.shields.io/codacy/grade/5939b1cf99bc4f9d91de11c0d3ff9e50)](https://app.codacy.com/gh/maximtrp/tmplot)
5
+ [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/maximtrp/tmplot/python-package.yml?label=tests)](https://github.com/maximtrp/tmplot/actions/workflows/python-package.yml)
6
+ [![Documentation Status](https://readthedocs.org/projects/tmplot/badge/?version=latest)](https://tmplot.readthedocs.io/en/latest/?badge=latest)
7
+ [![Downloads](https://static.pepy.tech/badge/tmplot)](https://pepy.tech/project/tmplot)
8
+ [![PyPI](https://img.shields.io/pypi/v/tmplot)](https://pypi.org/project/tmplot)
9
+ [![Issues](https://img.shields.io/github/issues/maximtrp/tmplot.svg)](https://github.com/maximtrp/tmplot/issues)
10
+
11
+ **tmplot** is a comprehensive Python package for **topic modeling analysis and visualization**. Built for data scientists and researchers, it provides powerful interactive reports and advanced analytics that extend beyond traditional LDAvis/pyLDAvis capabilities.
12
+
13
+ **Analyze** • **Visualize** • **Compare** multiple topic models with ease
14
+
15
+ ![Plots](https://raw.githubusercontent.com/maximtrp/tmplot/main/images/topics_terms_plots.png)
16
+
17
+ ## Key Features
18
+
19
+ ### Interactive Visualization
20
+
21
+ - **Topic scatter plots** with customizable coordinates and sizing
22
+ - **Term probability charts** with relevance weighting
23
+ - **Document analysis** showing top documents per topic
24
+ - **Interactive reports** with real-time parameter adjustment
25
+
26
+ ### Advanced Analytics
27
+
28
+ - **Topic stability analysis** across multiple model runs
29
+ - **Model comparison** with sophisticated distance metrics
30
+ - **Saliency calculations** for term importance
31
+ - **Entropy metrics** for model optimization
32
+
33
+ ### Model Support
34
+
35
+ - **[tomotopy](https://bab2min.github.io/tomotopy/)**: `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
36
+ - **[gensim](https://radimrehurek.com/gensim/)**: `LdaModel`, `LdaMulticore`
37
+ - **[bitermplus](https://github.com/maximtrp/bitermplus)**: `BTM`
38
+
39
+ ### Distance Metrics
40
+
41
+ - Kullback-Leibler (symmetric & non-symmetric)
42
+ - Jensen-Shannon divergence
43
+ - Jeffrey's divergence
44
+ - Hellinger & Bhattacharyya distances
45
+ - Total variation distance
46
+ - Jaccard index
47
+
48
+ ### Dimensionality Reduction
49
+
50
+ t-SNE, SpectralEmbedding, MDS, LocallyLinearEmbedding, Isomap
51
+
52
+ ## Donate
53
+
54
+ If you find this package useful, please consider donating any amount of money. This will help me spend more time on supporting open-source software.
55
+
56
+ <a href="https://www.buymeacoffee.com/maximtrp" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
57
+
58
+ ## Quick Start
59
+
60
+ ### Installation
61
+
62
+ ```bash
63
+ # From PyPI (recommended)
64
+ pip install tmplot
65
+
66
+ # Development version
67
+ pip install git+https://github.com/maximtrp/tmplot.git
68
+ ```
69
+
70
+ ### Basic Usage
71
+
72
+ ```python
73
+ import tmplot as tmp
74
+
75
+ # Load your topic model and documents
76
+ model = your_fitted_model # tomotopy, gensim, or bitermplus
77
+ docs = your_documents
78
+
79
+ # Create interactive report
80
+ tmp.report(model, docs=docs)
81
+
82
+ # Or create individual visualizations
83
+ coords = tmp.prepare_coords(model)
84
+ tmp.plot_scatter_topics(coords, size_col='size')
85
+ ```
86
+
87
+ ## Advanced Examples
88
+
89
+ ### Get Stable Topics
90
+
91
+ ```python
92
+ import tmplot as tmp
93
+
94
+ # Find stable topics across multiple models
95
+ models = [model1, model2, model3, model4]
96
+ closest_topics, distances = tmp.get_closest_topics(models)
97
+ stable_topics, stable_distances = tmp.get_stable_topics(closest_topics, distances)
98
+ ```
99
+
100
+ ### Analyze Model
101
+
102
+ ```python
103
+ # Calculate entropy for model selection
104
+ entropy_score = tmp.entropy(phi_matrix)
105
+
106
+ # Analyze topic stability
107
+ saliency = tmp.get_salient_terms(phi, theta)
108
+ ```
109
+
110
+ ### Visualize
111
+
112
+ ```python
113
+ # Create topic distance matrix with different metrics
114
+ topic_dists = tmp.get_topics_dist(phi, method='jensen-shannon')
115
+
116
+ # Generate coordinates with custom algorithm
117
+ coords = tmp.get_topics_scatter(topic_dists, theta, method='tsne')
118
+ tmp.plot_scatter_topics(coords, topic=3) # Highlight topic 3
119
+ ```
120
+
121
+ ## Documentation & Examples
122
+
123
+ - [Complete Tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html) - Step-by-step guide
124
+ - [API Reference](https://tmplot.readthedocs.io/) - Full documentation
125
+ - [Example Notebooks](https://github.com/maximtrp/tmplot/tree/main/examples) - Jupyter examples
126
+
127
+ ## Requirements
128
+
129
+ **Core dependencies:** `numpy`, `scipy`, `scikit-learn`, `pandas`, `altair`, `ipywidgets`
130
+
131
+ **Optional models:** `tomotopy`, `gensim`, `bitermplus`
@@ -5,4 +5,4 @@ from ._stability import * # noqa: F401, F403
5
5
  from ._vis import * # noqa: F401, F403
6
6
  from ._metrics import * # noqa: F401, F403
7
7
 
8
- __version__ = '0.2.0'
8
+ __version__ = "0.3.0"
@@ -21,12 +21,13 @@ def _dist_klb(a1: np.ndarray, a2: np.ndarray):
21
21
 
22
22
 
23
23
  def _dist_sklb(a1: np.ndarray, a2: np.ndarray):
24
- dist = kl_div(a1, a2) + kl_div(a1, a2)
24
+ dist = kl_div(a1, a2) + kl_div(a2, a1)
25
25
  return dist[np.isfinite(dist)].sum()
26
26
 
27
27
 
28
28
  def _dist_jsd(a1: np.ndarray, a2: np.ndarray):
29
- dist = 0.5 * kl_div(a1, a2) + 0.5 * kl_div(a1, a2)
29
+ m = 0.5 * (a1 + a2)
30
+ dist = 0.5 * kl_div(a1, m) + 0.5 * kl_div(a2, m)
30
31
  return dist[np.isfinite(dist)].sum()
31
32
 
32
33
 
@@ -36,16 +37,22 @@ def _dist_jef(a1: np.ndarray, a2: np.ndarray):
36
37
  return vals.sum()
37
38
 
38
39
 
40
+ # Small value for numerical stability
41
+ EPSILON = 1e-64
42
+
43
+
39
44
  def _dist_hel(a1: np.ndarray, a2: np.ndarray):
40
- a1[(a1 <= 0) | ~np.isfinite(a1)] = 1e-64
41
- a2[(a2 <= 0) | ~np.isfinite(a2)] = 1e-64
42
- hel_val = distance.euclidean(np.sqrt(a1), np.sqrt(a2)) / np.sqrt(2)
45
+ a1_safe = a1.copy()
46
+ a2_safe = a2.copy()
47
+ a1_safe[(a1_safe <= 0) | ~np.isfinite(a1_safe)] = EPSILON
48
+ a2_safe[(a2_safe <= 0) | ~np.isfinite(a2_safe)] = EPSILON
49
+ hel_val = distance.euclidean(np.sqrt(a1_safe), np.sqrt(a2_safe)) / np.sqrt(2)
43
50
  return hel_val
44
51
 
45
52
 
46
53
  def _dist_bhat(a1: np.ndarray, a2: np.ndarray):
47
54
  pq = a1 * a2
48
- pq[(pq <= 0) | ~np.isfinite(pq)] = 1e-64
55
+ pq[(pq <= 0) | ~np.isfinite(pq)] = EPSILON
49
56
  dist = -np.log(np.sum(np.sqrt(pq)))
50
57
  return dist
51
58
 
@@ -92,6 +99,14 @@ def get_topics_dist(
92
99
  Topics distances matrix.
93
100
  """
94
101
  phi_copy = np.array(phi)
102
+
103
+ if phi_copy.ndim != 2:
104
+ raise ValueError("phi must be a 2D array (words x topics)")
105
+ if np.any(phi_copy < 0):
106
+ raise ValueError("phi must contain non-negative probability values")
107
+ if not np.allclose(phi_copy.sum(axis=0), 1.0, atol=1e-6):
108
+ raise ValueError("phi columns must sum to 1 (probability distributions)")
109
+
95
110
  topics_num = phi_copy.shape[1]
96
111
  topics_pairs = combinations(range(topics_num), 2)
97
112
 
@@ -165,6 +180,7 @@ def get_topics_scatter(
165
180
  elif method == "mds":
166
181
  method_kws.setdefault("dissimilarity", "precomputed")
167
182
  method_kws.setdefault("normalized_stress", "auto")
183
+ method_kws.setdefault("n_init", 1)
168
184
  transformer = MDS(**method_kws)
169
185
 
170
186
  elif method == "lle":
@@ -156,6 +156,8 @@ def get_theta(model: object, corpus: Optional[List] = None) -> Optional[DataFram
156
156
  elif _is_gensim(model):
157
157
  if corpus is None:
158
158
  raise ValueError("`corpus` must be supplied for a gensim model")
159
+ if len(corpus) == 0:
160
+ raise ValueError("corpus cannot be empty")
159
161
  tdd = list(map(model.get_document_topics, corpus))
160
162
  theta = DataFrame(zeros((len(tdd), model.num_topics)))
161
163
  for doc_id, doc_topic in enumerate(tdd):
@@ -165,6 +167,8 @@ def get_theta(model: object, corpus: Optional[List] = None) -> Optional[DataFram
165
167
 
166
168
  elif _is_btmplus(model):
167
169
  theta = DataFrame(model.matrix_topics_docs_)
170
+ else:
171
+ raise ValueError(f"Unsupported model type: {type(model)}")
168
172
 
169
173
  if isinstance(theta, DataFrame):
170
174
  theta.index.name = "topics"
@@ -264,9 +268,19 @@ def calc_topics_marg_probs(
264
268
  Union[pandas.DataFrame, numpy.ndarray]
265
269
  Marginal topics probabilities.
266
270
  """
267
- p_t = array(theta).sum(axis=1)
268
- p_t /= p_t.sum()
271
+ theta_arr = array(theta)
272
+ if theta_arr.size == 0:
273
+ raise ValueError("theta matrix cannot be empty")
274
+
275
+ p_t = theta_arr.sum(axis=1)
276
+ total_sum = p_t.sum()
277
+ if total_sum == 0:
278
+ raise ValueError("theta matrix contains all zeros - cannot normalize")
279
+
280
+ p_t /= total_sum
269
281
  if topic_id is not None:
282
+ if topic_id < 0 or topic_id >= len(p_t):
283
+ raise IndexError(f"topic_id {topic_id} out of bounds for {len(p_t)} topics")
270
284
  return p_t[topic_id]
271
285
  return p_t
272
286
 
@@ -282,6 +296,8 @@ def calc_terms_marg_probs(
282
296
  ----------
283
297
  phi : Union[numpy.ndarray, pandas.DataFrame]
284
298
  Words vs topics matrix.
299
+ p_t : Union[numpy.ndarray, pandas.Series]
300
+ Topic marginal probabilities.
285
301
  word_id: Optional[int]
286
302
  Word index.
287
303
 
@@ -290,8 +306,20 @@ def calc_terms_marg_probs(
290
306
  Union[numpy.ndarray, pandas.Series]
291
307
  Marginal terms probabilities.
292
308
  """
293
- p_w = (array(phi) * array(p_t)).sum(axis=1)
309
+ phi_arr = array(phi)
310
+ p_t_arr = array(p_t)
311
+
312
+ if phi_arr.size == 0:
313
+ raise ValueError("phi matrix cannot be empty")
314
+ if p_t_arr.size == 0:
315
+ raise ValueError("p_t array cannot be empty")
316
+ if phi_arr.shape[1] != p_t_arr.shape[0]:
317
+ raise ValueError(f"phi topics dimension {phi_arr.shape[1]} must match p_t length {p_t_arr.shape[0]}")
318
+
319
+ p_w = (phi_arr * p_t_arr).sum(axis=1)
294
320
  if word_id is not None:
321
+ if word_id < 0 or word_id >= len(p_w):
322
+ raise IndexError(f"word_id {word_id} out of bounds for {len(p_w)} words")
295
323
  return p_w[word_id]
296
324
  return p_w
297
325
 
@@ -315,10 +343,17 @@ def get_salient_terms(phi: ndarray, theta: ndarray) -> ndarray:
315
343
  numpy.ndarray
316
344
  Terms saliency values.
317
345
  """
346
+ if phi.size == 0 or theta.size == 0:
347
+ raise ValueError("phi and theta matrices cannot be empty")
348
+ if phi.shape[1] != theta.shape[0]:
349
+ raise ValueError(f"phi topics dimension {phi.shape[1]} must match theta topics dimension {theta.shape[0]}")
350
+
318
351
  p_t = calc_topics_marg_probs(theta)
319
352
  p_w = calc_terms_marg_probs(phi, p_t)
320
353
 
321
354
  def _p_tw(phi, w, t):
355
+ if p_w[w] == 0:
356
+ return 0 # Avoid division by zero
322
357
  return array(phi)[w, t] * p_t[t] / p_w[w]
323
358
 
324
359
  saliency = array(
@@ -327,6 +362,8 @@ def get_salient_terms(phi: ndarray, theta: ndarray) -> ndarray:
327
362
  * sum(
328
363
  (
329
364
  _p_tw(phi, w, t) * log(_p_tw(phi, w, t) / p_t[t])
365
+ if _p_tw(phi, w, t) > 0 and p_t[t] > 0
366
+ else 0 # Handle log(0) cases
330
367
  for t in range(phi.shape[1])
331
368
  )
332
369
  )
@@ -105,6 +105,9 @@ def report(
105
105
  ipywidgets.widgets.widget_box.VBox
106
106
  Report interface as a VBox instance.
107
107
  """
108
+ # Input validation
109
+ if not docs or len(docs) == 0:
110
+ raise ValueError("docs cannot be empty")
108
111
 
109
112
  _topics_kws = (
110
113
  {"chart_kws": {"height": height, "width": width}}
@@ -117,7 +120,7 @@ def report(
117
120
  if not words_kws
118
121
  else deepcopy(words_kws)
119
122
  )
120
- _top_docs_kws = {} if not docs_kws else deepcopy(top_docs_kws)
123
+ _top_docs_kws = {} if not top_docs_kws else deepcopy(top_docs_kws)
121
124
  _docs_kws = {} if not docs_kws else deepcopy(docs_kws)
122
125
 
123
126
  # Headers init
@@ -162,8 +165,10 @@ def report(
162
165
  }
163
166
  )
164
167
 
168
+ # Cache phi matrix to avoid repeated calls
169
+ phi = get_phi(model)
170
+
165
171
  if "terms_probs" not in _words_kws:
166
- phi = get_phi(model)
167
172
  terms_probs = calc_terms_probs_ratio(phi, topic=0)
168
173
  _words_kws.update({"terms_probs": terms_probs})
169
174
 
@@ -106,6 +106,9 @@ def get_closest_topics(
106
106
  if mid == ref:
107
107
  continue
108
108
 
109
+ # Get phi matrix for current model
110
+ current_phi = get_phi(model)
111
+
109
112
  # Distance matrix for all topic pairs
110
113
  all_vs_all_dists = np.zeros((topics_num, topics_num))
111
114
 
@@ -113,7 +116,7 @@ def get_closest_topics(
113
116
  for t_ref in range(topics_num):
114
117
  for t in range(topics_num):
115
118
  all_vs_all_dists[t_ref, t] = dist_func(
116
- model_ref_phi.iloc[:, t_ref], get_phi(model).iloc[:, t]
119
+ model_ref_phi.iloc[:, t_ref], current_phi.iloc[:, t]
117
120
  )
118
121
 
119
122
  # Creating two arrays for the closest topics ids and distance values
@@ -128,11 +128,15 @@ def plot_scatter_topics(
128
128
  else {"condition": {"test": f"datum['topic'] == {topic}", "value": "red"}}
129
129
  )
130
130
 
131
- data = (
132
- DataFrame(topics_coords, columns=[x_col, y_col])
133
- if isinstance(topics_coords, ndarray)
134
- else topics_coords.copy()
135
- )
131
+ # Input validation
132
+ if isinstance(topics_coords, ndarray):
133
+ if topics_coords.size == 0:
134
+ raise ValueError("topics_coords cannot be empty")
135
+ data = DataFrame(topics_coords, columns=[x_col, y_col])
136
+ else:
137
+ if topics_coords.empty:
138
+ raise ValueError("topics_coords DataFrame cannot be empty")
139
+ data = topics_coords.copy()
136
140
 
137
141
  if not topic_col:
138
142
  topic_col = "topic"
@@ -225,6 +229,13 @@ def plot_terms(
225
229
  altair.Chart
226
230
  Terms probabilities chart.
227
231
  """
232
+ # Input validation
233
+ if terms_probs.empty:
234
+ raise ValueError("terms_probs DataFrame cannot be empty")
235
+ required_cols = [x_col, y_col, color_col]
236
+ missing_cols = [col for col in required_cols if col not in terms_probs.columns]
237
+ if missing_cols:
238
+ raise ValueError(f"Missing required columns: {missing_cols}")
228
239
  if not x_kws:
229
240
  x_kws = {"stack": None}
230
241
  if not y_kws:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: tmplot
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Visualization of Topic Modeling Results
5
5
  Author-email: Maksim Terpilovskii <maximtrp@gmail.com>
6
6
  License: MIT License
@@ -55,6 +55,7 @@ Provides-Extra: models
55
55
  Requires-Dist: tomotopy>=0.8.0; extra == "models"
56
56
  Requires-Dist: gensim; extra == "models"
57
57
  Requires-Dist: bitermplus; extra == "models"
58
+ Dynamic: license-file
58
59
 
59
60
  # tmplot
60
61
 
@@ -66,35 +67,46 @@ Requires-Dist: bitermplus; extra == "models"
66
67
  [![PyPI](https://img.shields.io/pypi/v/tmplot)](https://pypi.org/project/tmplot)
67
68
  [![Issues](https://img.shields.io/github/issues/maximtrp/tmplot.svg)](https://github.com/maximtrp/tmplot/issues)
68
69
 
69
- **tmplot** is a Python package for analysis and visualization of topic modeling results. It provides the interactive report interface that borrows much from LDAvis/pyLDAvis and builds upon it offering a number of metrics for calculating topic distances and a number of algorithms for calculating scatter coordinates of topics. It can be used to select closest and stable topics across multiple models.
70
+ **tmplot** is a comprehensive Python package for **topic modeling analysis and visualization**. Built for data scientists and researchers, it provides powerful interactive reports and advanced analytics that extend beyond traditional LDAvis/pyLDAvis capabilities.
71
+
72
+ **Analyze** • **Visualize** • **Compare** multiple topic models with ease
70
73
 
71
74
  ![Plots](https://raw.githubusercontent.com/maximtrp/tmplot/main/images/topics_terms_plots.png)
72
75
 
73
- ## Features
76
+ ## Key Features
77
+
78
+ ### Interactive Visualization
79
+
80
+ - **Topic scatter plots** with customizable coordinates and sizing
81
+ - **Term probability charts** with relevance weighting
82
+ - **Document analysis** showing top documents per topic
83
+ - **Interactive reports** with real-time parameter adjustment
84
+
85
+ ### Advanced Analytics
74
86
 
75
- - Supported models:
87
+ - **Topic stability analysis** across multiple model runs
88
+ - **Model comparison** with sophisticated distance metrics
89
+ - **Saliency calculations** for term importance
90
+ - **Entropy metrics** for model optimization
76
91
 
77
- - [tomotopy](https://bab2min.github.io/tomotopy/): `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
78
- - [gensim](https://radimrehurek.com/gensim/): `LdaModel`, `LdaMulticore`
79
- - [bitermplus](https://github.com/maximtrp/bitermplus): `BTM`
92
+ ### Model Support
80
93
 
81
- - Supported distance metrics:
94
+ - **[tomotopy](https://bab2min.github.io/tomotopy/)**: `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
95
+ - **[gensim](https://radimrehurek.com/gensim/)**: `LdaModel`, `LdaMulticore`
96
+ - **[bitermplus](https://github.com/maximtrp/bitermplus)**: `BTM`
82
97
 
83
- - Kullback-Leibler (symmetric and non-symmetric) divergence
84
- - Jenson-Shannon divergence
85
- - Jeffrey's divergence
86
- - Hellinger distance
87
- - Bhattacharyya distance
88
- - Total variation distance
89
- - Jaccard inversed index
98
+ ### Distance Metrics
90
99
 
91
- - Supported [algorithms](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.manifold) for calculating topics scatter coordinates:
100
+ - Kullback-Leibler (symmetric & non-symmetric)
101
+ - Jensen-Shannon divergence
102
+ - Jeffrey's divergence
103
+ - Hellinger & Bhattacharyya distances
104
+ - Total variation distance
105
+ - Jaccard index
92
106
 
93
- - t-SNE
94
- - SpectralEmbedding
95
- - MDS
96
- - LocallyLinearEmbedding
97
- - Isomap
107
+ ### Dimensionality Reduction
108
+
109
+ t-SNE, SpectralEmbedding, MDS, LocallyLinearEmbedding, Isomap
98
110
 
99
111
  ## Donate
100
112
 
@@ -102,55 +114,77 @@ If you find this package useful, please consider donating any amount of money. T
102
114
 
103
115
  <a href="https://www.buymeacoffee.com/maximtrp" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
104
116
 
105
- ## Installation
117
+ ## Quick Start
106
118
 
107
- The package can be installed from PyPi:
119
+ ### Installation
108
120
 
109
121
  ```bash
122
+ # From PyPI (recommended)
110
123
  pip install tmplot
111
- ```
112
-
113
- Or directly from this repository:
114
124
 
115
- ```bash
125
+ # Development version
116
126
  pip install git+https://github.com/maximtrp/tmplot.git
117
127
  ```
118
128
 
119
- ## Dependencies
129
+ ### Basic Usage
130
+
131
+ ```python
132
+ import tmplot as tmp
133
+
134
+ # Load your topic model and documents
135
+ model = your_fitted_model # tomotopy, gensim, or bitermplus
136
+ docs = your_documents
120
137
 
121
- - `numpy`
122
- - `scipy`
123
- - `scikit-learn`
124
- - `pandas`
125
- - `altair`
126
- - `ipywidgets`
127
- - `tomotopy`, `gensim`, and `bitermplus` (optional)
138
+ # Create interactive report
139
+ tmp.report(model, docs=docs)
128
140
 
129
- ## Quick example
141
+ # Or create individual visualizations
142
+ coords = tmp.prepare_coords(model)
143
+ tmp.plot_scatter_topics(coords, size_col='size')
144
+ ```
145
+
146
+ ## Advanced Examples
147
+
148
+ ### Get Stable Topics
130
149
 
131
150
  ```python
132
- # Importing packages
133
151
  import tmplot as tmp
134
- import pickle as pkl
135
- import pandas as pd
136
152
 
137
- # Reading a model from a file
138
- with open('data/model.pkl', 'rb') as file:
139
- model = pkl.load(file)
153
+ # Find stable topics across multiple models
154
+ models = [model1, model2, model3, model4]
155
+ closest_topics, distances = tmp.get_closest_topics(models)
156
+ stable_topics, stable_distances = tmp.get_stable_topics(closest_topics, distances)
157
+ ```
158
+
159
+ ### Analyze Model
160
+
161
+ ```python
162
+ # Calculate entropy for model selection
163
+ entropy_score = tmp.entropy(phi_matrix)
140
164
 
141
- # Reading documents from a file
142
- docs = pd.read_csv('data/docs.txt.gz', header=None).values.ravel()
165
+ # Analyze topic stability
166
+ saliency = tmp.get_salient_terms(phi, theta)
167
+ ```
143
168
 
144
- # Plotting topics as a scatter plot
145
- topics_coords = tmp.prepare_coords(model)
146
- tmp.plot_scatter_topics(topics_coords, size_col='size', label_col='label')
169
+ ### Visualize
147
170
 
148
- # Plotting terms probabilities
149
- terms_probs = tmp.calc_terms_probs_ratio(phi, topic=0, lambda_=1)
150
- tmp.plot_terms(terms_probs)
171
+ ```python
172
+ # Create topic distance matrix with different metrics
173
+ topic_dists = tmp.get_topics_dist(phi, method='jensen-shannon')
151
174
 
152
- # Running report interface
153
- tmp.report(model, docs=docs, width=250)
175
+ # Generate coordinates with custom algorithm
176
+ coords = tmp.get_topics_scatter(topic_dists, theta, method='tsne')
177
+ tmp.plot_scatter_topics(coords, topic=3) # Highlight topic 3
154
178
  ```
155
179
 
156
- You can find more examples in the [tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html).
180
+ ## Documentation & Examples
181
+
182
+ - [Complete Tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html) - Step-by-step guide
183
+ - [API Reference](https://tmplot.readthedocs.io/) - Full documentation
184
+ - [Example Notebooks](https://github.com/maximtrp/tmplot/tree/main/examples) - Jupyter examples
185
+
186
+ ## Requirements
187
+
188
+ **Core dependencies:** `numpy`, `scipy`, `scikit-learn`, `pandas`, `altair`, `ipywidgets`
189
+
190
+ **Optional models:** `tomotopy`, `gensim`, `bitermplus`
tmplot-0.2.0/README.md DELETED
@@ -1,98 +0,0 @@
1
- # tmplot
2
-
3
- [![Codacy coverage](https://img.shields.io/codacy/coverage/5939b1cf99bc4f9d91de11c0d3ff9e50)](https://app.codacy.com/gh/maximtrp/tmplot/coverage)
4
- [![Codacy grade](https://img.shields.io/codacy/grade/5939b1cf99bc4f9d91de11c0d3ff9e50)](https://app.codacy.com/gh/maximtrp/tmplot)
5
- [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/maximtrp/tmplot/python-package.yml?label=tests)](https://github.com/maximtrp/tmplot/actions/workflows/python-package.yml)
6
- [![Documentation Status](https://readthedocs.org/projects/tmplot/badge/?version=latest)](https://tmplot.readthedocs.io/en/latest/?badge=latest)
7
- [![Downloads](https://static.pepy.tech/badge/tmplot)](https://pepy.tech/project/tmplot)
8
- [![PyPI](https://img.shields.io/pypi/v/tmplot)](https://pypi.org/project/tmplot)
9
- [![Issues](https://img.shields.io/github/issues/maximtrp/tmplot.svg)](https://github.com/maximtrp/tmplot/issues)
10
-
11
- **tmplot** is a Python package for analysis and visualization of topic modeling results. It provides the interactive report interface that borrows much from LDAvis/pyLDAvis and builds upon it offering a number of metrics for calculating topic distances and a number of algorithms for calculating scatter coordinates of topics. It can be used to select closest and stable topics across multiple models.
12
-
13
- ![Plots](https://raw.githubusercontent.com/maximtrp/tmplot/main/images/topics_terms_plots.png)
14
-
15
- ## Features
16
-
17
- - Supported models:
18
-
19
- - [tomotopy](https://bab2min.github.io/tomotopy/): `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
20
- - [gensim](https://radimrehurek.com/gensim/): `LdaModel`, `LdaMulticore`
21
- - [bitermplus](https://github.com/maximtrp/bitermplus): `BTM`
22
-
23
- - Supported distance metrics:
24
-
25
- - Kullback-Leibler (symmetric and non-symmetric) divergence
26
- - Jenson-Shannon divergence
27
- - Jeffrey's divergence
28
- - Hellinger distance
29
- - Bhattacharyya distance
30
- - Total variation distance
31
- - Jaccard inversed index
32
-
33
- - Supported [algorithms](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.manifold) for calculating topics scatter coordinates:
34
-
35
- - t-SNE
36
- - SpectralEmbedding
37
- - MDS
38
- - LocallyLinearEmbedding
39
- - Isomap
40
-
41
- ## Donate
42
-
43
- If you find this package useful, please consider donating any amount of money. This will help me spend more time on supporting open-source software.
44
-
45
- <a href="https://www.buymeacoffee.com/maximtrp" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
46
-
47
- ## Installation
48
-
49
- The package can be installed from PyPi:
50
-
51
- ```bash
52
- pip install tmplot
53
- ```
54
-
55
- Or directly from this repository:
56
-
57
- ```bash
58
- pip install git+https://github.com/maximtrp/tmplot.git
59
- ```
60
-
61
- ## Dependencies
62
-
63
- - `numpy`
64
- - `scipy`
65
- - `scikit-learn`
66
- - `pandas`
67
- - `altair`
68
- - `ipywidgets`
69
- - `tomotopy`, `gensim`, and `bitermplus` (optional)
70
-
71
- ## Quick example
72
-
73
- ```python
74
- # Importing packages
75
- import tmplot as tmp
76
- import pickle as pkl
77
- import pandas as pd
78
-
79
- # Reading a model from a file
80
- with open('data/model.pkl', 'rb') as file:
81
- model = pkl.load(file)
82
-
83
- # Reading documents from a file
84
- docs = pd.read_csv('data/docs.txt.gz', header=None).values.ravel()
85
-
86
- # Plotting topics as a scatter plot
87
- topics_coords = tmp.prepare_coords(model)
88
- tmp.plot_scatter_topics(topics_coords, size_col='size', label_col='label')
89
-
90
- # Plotting terms probabilities
91
- terms_probs = tmp.calc_terms_probs_ratio(phi, topic=0, lambda_=1)
92
- tmp.plot_terms(terms_probs)
93
-
94
- # Running report interface
95
- tmp.report(model, docs=docs, width=250)
96
- ```
97
-
98
- You can find more examples in the [tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html).
File without changes
File without changes
File without changes
File without changes
File without changes